I'm new to Java class design and need help with the following:
Example scenario: I want to pass the company name and email to the BaseEmailMessage class, and fetch these values from the application.properties file.
I also have static variables SIGN_UP_URL and PASSWORD_RESET_URL in the SignUpEmail and PasswordResetEmail classes, respectively, and I need to fetch these from the same properties file.
abstract public class BaseEmailMessage {
// Need to fetch these from application properties
// as they are common for all email types
private String COMPANY_NAME;
private String COMPANY_EMAIL;
// constructor, methods, getters, and setters...
}
@Component
public class SignUpEmail extends BaseEmailMessage {
// Need to fetch this from application properties specific to this class only
private static final String SIGN_UP_URL;
}
@Component
public class PasswordResetEmail extends BaseEmailMessage {
// Need to fetch this from application properties specific to this class only
private static final String PASSWORD_RESET_URL;
}
How can I achieve this in a clean and maintainable way? Any best practices to improve the maintainability of this code?
Thanks!
I tried autowiring the Environment instance to the classes, but not sure should I move with that approach or not?
You can use @ConfigurationProperties
and constructor injection instead of manually fetching values from the environment. I think it is a maintainable way to achieve what you're asking.
Avoid using static fields because they're not easily injected by Spring.
application.properties
:email.company-name=Example Company
email.company-email=info@example.com
email.signup.url=https://example.com/signup
email.passwordreset.url=https://example.com/reset-password
@Component
@ConfigurationProperties(prefix = "email")
public class EmailProperties {
private String companyName;
private String companyEmail;
private final Signup signup = new Signup();
private final Passwordreset passwordreset = new Passwordreset();
// getters and setters
public static class Signup {
private String url;
// getters and setters
}
public static class Passwordreset {
private String url;
// getters and setters
}
// getters and setters for top-level properties
public String getCompanyName() { return companyName; }
public void setCompanyName(String companyName) { this.companyName = companyName; }
public String getCompanyEmail() { return companyEmail; }
public void setCompanyEmail(String companyEmail) { this.companyEmail = companyEmail; }
public Signup getSignup() { return signup; }
public Passwordreset getPasswordreset() { return passwordreset; }
}
BaseEmailMessage
:public abstract class BaseEmailMessage {
protected final String companyName;
protected final String companyEmail;
protected BaseEmailMessage(String companyName, String companyEmail) {
this.companyName = companyName;
this.companyEmail = companyEmail;
}
// methods, getters, etc.
}
@Component
public class SignUpEmail extends BaseEmailMessage {
private final String signupUrl;
public SignUpEmail(EmailProperties emailProperties) {
super(emailProperties.getCompanyName(), emailProperties.getCompanyEmail());
this.signupUrl = emailProperties.getSignup().getUrl();
}
// methods using signupUrl
public String getSignupUrl() {
return signupUrl;
}
}
I think this way is maintainable because it is clear separation, easy management and constructor injection.