Spring ConditionalOnProperty cannot read property in custom.properties file - spring

Hi I have some custom properties files like application.properties.And I put some property in this files.Myproblem is #ConditionalOnProperty cannot read myproperties in customproperties file.
If I put same property in application.properties ConditionalOnProperty works but when I put myproperty in customproperties file that time it is not working.Except ConditionalOnProperty I dont have any problem to read values from custom properties file.Is there any way to read external properties from ConditionalOnProperty in spring boot.
#Congiuration
#PropertySource("classpath:myproperties.properties")
#ConfigurationProperties(prefix="mycustomprop")
public class MyProperties{
private String myproperty;
#Configuration
#ConditionalOnProperty(name = "mycustomprop.myproperty", havingValue = "false") //not work when myproperty in customproperty file
public class MyConfiguration implements WebMvcConfigurer
#SpringBootApplication
#PropertySources({
#PropertySource("classpath:myproperties.properties")
})
public class MyApplication

Your #PropertySource annotation needs to go on a #Configuration class (or #SpringBootApplication if you want), not your custom MyProperties object.

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.

Spring Java Config: configure already existing bean

I want to configure in my #Configuration class bean which is already created by other library's autoconfiguration. I just need to change some fields in that class after it's being initialized.
But I can't find a proper way how to provide code block in #Configuration class and not using #Bean annotation. Is there an ideomatic way to do so in spring?
One way to do this:
#Configuration
class TestConfig {
#Autowired
private SomeBean someBean;
#PostConstruct
private void initSomeBean() {
// someBean.setProperty("qwe");
}
}
#PostConstruct annotation defines init-method, which is getting called after SomeBean is autowired. In this method you can adjust your bean
Do you want to import one Config in AnotherConfig on? It can be done via annotation placed on AnotherConfig:
import org.springframework.context.annotation.Import;
...
#Import(value = {Config.class})
public class AnotherConfig ... {}

#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-boot application-test.properties

I am trying to unit test the spring-boot application using junit. I have placed the application-test.properties under src/test/resources. I have a ApplicationConfiguration Class which reads the application.properties.
My test class looks like this
#RunWith(SpringRunner.class)
#SpringBootTest(classes=ApplicationConfiguration.class)
#TestPropertySource(locations = "classpath:application-test.properties")
#ActiveProfiles("test")
public class TestBuilders {
#Autowired
private ApplicationConfiguration properties;
When I try to read the properties, it is always null.
My ApplicationConfiguration Class looks something like this
#Configuration
#ConfigurationProperties
#PropertySources({
#PropertySource("classpath:application.properties"),
#PropertySource(value="file:config.properties", ignoreResourceNotFound =
true)})
public class ApplicationConfiguration{
private xxxxx;
private yyyyy;
I tried all possible ways that I found on google.. No luck. Please help!
Thanks in Advance.
The issue is you don't have #EnableConfigurationProperties on your test class.
When you load the application it start from main class(one which has #SpringBootApplication) where you might have #EnableConfigurationProperties and hence it works when you start the application.
Whereas when you are running the Test with only ApplicationConfiguration class as you have specified here
#SpringBootTest(classes=ApplicationConfiguration.class)
Spring doesn't know that it has to Enable Configuration Properties and hence the fields are not injecting and hence null. But spring is reading your application-test.properties file. This can be confirmed by just injecting the value directly in your test class
#Value("${xxxxx}")
private String xxxxx;
Here the value is injected. But to inject into a class with ConfigurationProperties you need to enable it using #EnableConfigurationProperties
Put #EnableConfigurationProperties on your test class and everythhing works fine.

spring boot application context was not properly loaded if the yaml file wasn't application.yml

With following configuration, my test can read the properties from the yaml file correctly.
#SpringBootApplication
#PropertySource("classpath:application.yml")
#ComponentScan({ "com.my.service" })
public class MyApplication {
}
Then I renamed the yaml file to my-application.yml, and changed the PropertySource to
#PropertySource("classpath:my-application.yml")
Tests are failed due to the null property value. The configuration class is as following:
#Configuration
#ConfigurationProperties(prefix="my")
#Data
public class MyConfig {
private String attr1;
}
The test class is:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyApplication.class)
public class MyConfigTest {
#Autowired
private MyConfig myConfig;
#Test
public void getMyConfigTest() {
Assert.assertNotNull(myConfig.getAttr1());
}
Why spring boot can find the renamed yaml file, but it couldn't load the value correctly?
YAML files can’t be loaded via the #PropertySource annotation
It appears to work with #PropertySource("classpath:application.yml") because that's the default location and spring boot looks there regardless.
You may be able to use #ConfigurationProperties(location="claspath:my-application.yml") instead but it doesn't really achieve the same purpose (and I've never tried it myself).

Resources