How to protect @ConfigurationProperties classes from changes?
To use annotation @ConfigurationProperties
, you need to create a class with getters and setters:
@ConfigurationProperties(prefix = "some")
public class PropertiesConfig {
private boolean debug;
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
}
But this leads to a situation where someone wants to change this value by calling:
@Autowire
private PropertiesConfig config;
//....
config.setDebug(true);
Is there a way to create @ConfigurationProperties
annotated classes without delimiters and external parser / read classes?
source to share
Something like this works great
@Configuration
class MyAppPropertiesConfiguration {
@Bean
@ConfigurationProperties(prefix = "some")
public PropertiesConfig propertiesConfig () {
return new PropertiesConfigImpl();
}
public interface PropertiesConfig {
public boolean isDebug();
}
private static class PropertiesConfigImpl implements PropertiesConfig {
private boolean debug;
@Override
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
}
}
and then
@Autowired PropertiesConfig properties;
source to share
Impossible out of the box. @ConfigurationProperties
beans must have standard receivers and setters. You can consider the approach outlined in this answer: Immutable @ConfigurationProperties
Or something like this:
@Component
public class ApplicationProperties {
private final String property1;
private final String property2;
public ApplicationProperties(
@Value("${some.property1"}) String property1,
@Value("${some.other.property2}) String property2) {
this.property1 = property1;
this.property2 = property1;
}
//
// ... getters only ...
//
}
source to share
One approach with minimal code boilerplate would probably use a getter-only interface
public interface AppProps {
String getNeededProperty();
}
and get rid of boilerplate getters and setters in the implementation with Lombok comments @Getter
and @Setter
:
@ConfigurationProperties(prefix = "props")
@Getter
@Setter
public class AppPropsImpl implements AppProps {
private String neededProperty;
}
Then other beans are available to bean bo only by interface, instead of labeling it as @Component
or using it @EnableConfigurationProperties(AppPropsImpl.class)
in the main application class, consider setting it in a config which will expose it to the interface:
@Configuration
@EnableConfigurationProperties
public class PropsConfiguration {
@Bean
public AppProps appProps(){
return new AppPropsImpl();
}
}
Now this bean can only be injected using the frontend and this makes the setters inaccessible to other beans:
public class ApplicationLogicBean {
@Autowired
AppProps props;
public void method(){
log.info("Got " + props.getNeededProperty());
}
}
Tested with Spring Boot 1.5.3 and Lombok 1.16.16.
source to share