Spring cannot read from property file - spring

have a class which is annotated with #Service, trying to read a property using values, the value always comes as zero
#Service
public class custom implements Conditional
{
#Value("${test.property}")
private boolean properttyValue;
}
#test.properties
test.property= true
If i provide any non existent value in #Value, it throws an error , which means property is loaded,
Any idea whats wrong ?

This is because test.propeties not in the class path. If you are using Spring boot use -Dspring.config.location to specify external configurations. You can do this using the following ways
-Dspring.config.location=your/config/dir/
-Dspring.config.location=classpath:pro1.properties,classpath:prop2.properties
If you are not using Spring boot, this can be done using
#Configuration
#PropertySource("classpath:test.properties")
public class PropertiesWithJavaConfig {
//...
}
#Configuration
#PropertySource({
"classpath:test.properties"
})
public class PropertiesWithJavaConfig {
//...
}
For external file "file:/" can be used instead of classpath e.g. file:./,file:./config/

Related

(De-)Serializing Spring Boot ConfigurationProperties with Jackson

My spring Boot application uses a class annotated with #Configuration and #ConfigurationProperties:
#Configuration
#ConfigurationProperties(prefix = "my")
#Getter
#Setter
public class MyConfigurationProperties {
#Value("${timeout}")
private int defaultTimeout;
}
Now I'd like to read and update these configuration properties using a (private) REST interface, so I created the following controller.
#RestController
#RequestMapping(path = "config")
public class ConfigController {
final MyConfigurationProperties myConfig;
public ConfigController(MyConfigurationProperties myConfig) {
this.myConfig = myConfig;
}
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MyConfigurationProperties> get() {
return ResponseEntity.ok(myConfig);
}
}
Unfortunately this doesn't seem to work as I get the following exception when calling the endpoint:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.context.expression.StandardBeanExpressionResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
The JSON response even contains "strange" properties when disabling FAIL_ON_EMPTY_BEANS:
How would I be able to (de-)serialize this configuration class using Jackson?
When removing the annotations #Configuration and #ConfigurationProperties for testing purposes, the serialization works just fine. So it seems to have to do something with the class being a bean?
You are mixing things: configuration properties and autowiring a value. If you want to have a POJO as a configuration property class, drop the #Value annotation. You can also drop #Configuration annotation if you add #EnableConfigurationProperties to your main class (this way all #ConfigurationProperties classes will be automatically detected). If a problem persists, please update the question and show us how the properties prefixed with 'my' look like.

SpringBoot does not resolve #Value properties without PropertySource annotation

I have a bunch of #Value annotated fields in a SpringBoot configuration file, with the matching values in the standard application.properties . If I don't annotate the configuration file with #PropertySource("classpath:application.properties") it will just copy the "${prop1}" string into the actual variable.
I tried adding #EnableAutoConfiguration to the #Configuration class (instead of the PropertySource annotation), but all it does is to break when a requested property is not found.
SpringBoot is supposed to resolve the properties automatically from the standard application.properties file, why this behaviour? Using version 2.2.2.RELEASE
Update:
The answers are correct, the reason it was not working was that I was calling these properties in a test. Annotating the test with #SpringBootTest fixes the issue. In fact when the application is running it is #SpringBootApplication that does the magic
As you can read in this article (chapter 5), SpringBoot manage automatically the application.properties file.
I don't know if this is your problem because I've not seen the code, but in Spring Boot the Application class should be annotated with #SpringBootApplication.
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Take a look at this starting example.
You can then inject the value for example in a controller class in this way:
#RestController
public class HelloController {
#Value("${test}")
private String test;
#RequestMapping("/test")
String hello() {
return test;
}
}

application.properties not read with #EnableAutoConfiguration and custom spring boot starter

I try to create a simple custom spring boot starter that read property in application.properties :
#EnableConfigurationProperties({ CustomStarterProperties.class })
#Configuration
public class CustomStarterAutoConfiguration {
#Autowired
private CustomStarterProperties properties;
#Bean
public String customStarterMessage() {
return properties.getMessage();
}
}
with its ConfigurationProperties :
#ConfigurationProperties(prefix = "custom.starter")
public class CustomStarterProperties {
private String message;
/* getter and setter */
...
}
There is also the corresponding application.properties and META-INF/spring.factories to enable the autoconfiguration.
I have another project that declares this starter as a dependency and in which I write a test to see if the customStarterMessage Bean is created :
#RunWith(SpringRunner.class)
#EnableAutoConfiguration
public class TotoTest {
#Autowired
String customStarterMessage;
#Test
public void loadContext() {
assertThat(customStarterMessage).isNotNull();
}
}
This test fails (even with the appropriate application.properties file in the project) because the application.properties seems to not be read.
It works well with a #SpringBootTest annotation instead of the #EnableAutoConfiguration but I would like to understand why EnableAutoConfiguration is not using my application.properties file whereas from my understanding all the Spring AutoConfiguration are based on properties.
Thanks
#EnableAutoConfiguration on test classes don't prepare required test context for you.
Whereas #SpringBootTest does default test context setup for you based on default specification like scanning from root package, loading from default resources. To load from custom packages which are not part of root package hierarchy, loading from custom resource directories you have define that even in test context configuration. All your configurations will be automatically done in your actual starter project based on #EnableAutoConfiguration you defined.

#EnableAutoConfiguration annotation with class prameter is not initializing properties object

i have following #CongfigurationProperties class
//#Component
#ConfigurationProperties
#PropertySource("classpath:typesofcharge.properties")
public class ChargeProperties {
private HashMap<String,String> charge=new HashMap<>();
public HashMap<String,String> getCharge()
{
return this.charge;
}
}
And this is my Configuration file
#SpringBootApplication
#ComponentScan({"com.vehiclemanagement.config,com.vehiclemanagement.client,"
+ "com.vehiclemanagement.controller,"
+ "com.vehiclemanagement.exception,"
+ "com.vehiclemanagement.model,"
+ "com.vehiclemanagement.service"})
#EnableConfigurationProperties(ChargeProperties.class)
public class VehicleManagementConfig {
public static void main(String[] args) {
SpringApplication.run(VehicleManagementConfig.class, args);
}
}
If i use #Component annotation in ChargeProperties and remove ChargeProperties.class annotation in Configuration class the charge HashMap is initialized properly
If i remove #Component and pass ChargeProperties.class as argument like this
#EnableConfigurationProperties(ChargeProperties.class) like how document says the charge HashMap is empty when i run
I am using spring boot 2.0.2 release .But i am following latest docs. Can anyone explain why this are not working as document suggest
content of property file is as follows
UPDATE the content of property files are as shown
#DO NOT MODIFY THIS FILE
charge.peak=Double_rate;
charge.lateNight=duration_based_charge;
charge.earlyMorning=special_offers;
When specifying ChargeProperies.class on the #EnableConfigurationProperties annotation it will be registered as a bean through the EnableConfigurationPropertiesImportSelector class inside #EnableConfigurationProperties.
So in the example, if you have only annotated the ChargeProperties class with #ConfigurationProperties it will create a chargeProperties bean with an empty charge HashMap because it defaulted back to application.properties as the source.
A custom source can be specified by using #PropertySource.
#PropertySource annotation providing a convenient and declarative mechanism for adding
a PropertySource to Spring's Environment. To be used in conjunction
with #Configuration classes.
As per documentation above, to use #PropertySource to load the custom source, one has to use the #Configuration annotation.
#Configuration
#PropertySource("classpath:typesofcharge.properties")
Under the hood a #Configuration class is a #Component.
#Target(value=TYPE)
#Retention(value=RUNTIME)
#Documented
#Component
public #interface Configuration
So to your question. By specifying a custom #PropertySource without #Configuration, spring did not load the properties in the #PropertySource annotation and defaulted back to the application.properties.
If we use #PropertySource we have to use component otherwise the properties will not be read
since we added the #ComponentScan We don't have to mention #EnableConfiguationProperties annotation at all The propety class object can be autowired as Bean

Spring conditional component scan configuration

I have a configuration class which registers beans based on a very simple condition (checking a property value in application.properties). The configuration class and the condition are the following:
#Configuration
#Conditional(DatabaseConfigurationCondition.class)
#ComponentScan(basePackageClasses = DBConfigComponents.class)
public class DatabaseConfigurationLoader {
#Bean
public DatabaseConfigurationRepository databaseConfigurationRepository() {
return new DatabaseConfigurationRepository();
}
}
and
public class DatabaseConfigurationCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("configuration.type").contains("db");
}
}
In addition of the beans registered in this configuration class I have component scan which scans for other components. When the condition is not met, I expect the beans which are defined in the configuration class not to be registered (which happens to be a case), but also I expect other classes which are annotated with #Component (or #Repository, #Service, etc.. ) and are in same folder as DBConfigComponents.class marker interface not to be registered, which does not happen. Beans which are scanned are always registered, no matter if the condition is fulfilled or not.
When I put the #Conditional(DatabaseConfigurationCondition.class) on each #Component annotated class, than it's working correctly, but I don't want to put it on each class separately.
Any suggestion?
Fortunately, I managed to fix this. The problem in my case was that I had another #ComponentScan annotation placed in other configuration class in other Maven module - not conditional on any property. The components which are in same package as DBConfigComponents marker interface were actually scanned by the other configuration class.
The way #ComponentScan works is on package level. Although, in different Maven modules, both configuration classes were in same package. #ComponentScan works perfectly fine with #Conditional. No need #Conditional to be placed on each component separately.
The best way to achieve this is not to annotate these beans using #Component / #Service and #Repository annotations. Instead you should return these as part of the configuration you have setup which would be DatabaseConfigurationLoader. See sample below.
#Configuration
#Conditional(DatabaseConfigurationCondition.class)
public class DatabaseConfigurationLoader {
#Bean
public DatabaseConfigurationRepository databaseConfigurationRepository() {
return new DatabaseConfigurationRepository();
}
#Bean
public SomeService someService() {
return new SomeService();
}
#Bean
public SomeComponent someComponent() {
return new SomeComponent();
}
}
Note: Typically #Configuration with #Conditional are used in libraries that you want to include in your spring boot application. Such libraries should not share the same package as your spring boot application. Thus they should not be picked up by #ComponentScan annotation. Beans from libraries should not be annotated with #Component / #Service / #Repository annotations. Spring suggests using AutoConfiguration for that. See https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html & https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html
No need to implement Condition interface, you need to use '#ConditionalOnProperty' annotation:
#Configuration
#ComponentScan(basePackageClasses = DBConfigComponents.class)
#ConditionalOnProperty(name = "configuration.type", havingValue = "db")
public class DatabaseConfigurationLoader {
#Bean
public DatabaseConfigurationRepository databaseConfigurationRepository() {
return new DatabaseConfigurationRepository();
}
}
you can use 'prefix' instead of 'havingValue' depending on your needs.

Resources