Spring Custom Properties File Under Subfolder Read in The Application Start - spring

Hi I have a custom properties file.And I have a aspect and it has condition.If my.properties under resource directly PropertySourcesPropertyResolver read myproperties and find it in applicationstart process.How can I force my properties file under subfolder read by propertysourcespropertyresolver
[restartedMain] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'myenable' in PropertySource 'configurationProperties' with value of type String
But When I add subfolder in resource like Resource/myfolder/my.properties that time PropertySourcesPropertyResolver cannot resolve it at the beginning
#Configuration
#PropertySource("classpath:/myfolder/my.properties")
public class MyConfigProperties
private String myenable;
....
#Service
#ConditionalOnExpression("'${myenable}'=='true'")
public class MyAspect

#PropertySource will work only if you put this annotation on a configuration class(annotated with #Configuration or any other annotation extending #Configuration like #SpringBootApplication, #SpringBootConfiguration etc.).
In your case annotate your class MyConfigPropertie with #Configuration along with #PropertySource
#PropertySource("classpath:/myfolder/my.properties")
#Configuration
public class MyConfigPropertie {
}
OR
put this #PropertySource("classpath:/myfolder/my.properties") on spring main class annotated with #SpringBootApplication

Related

Spring ConditionalOnProperty cannot read property in custom.properties file

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.

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 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).

Overriding Spring #PropertySource by #Import

I have a property test=default in class DefaultConfig, and I'm making them available using #PropertySource annotation.
#Configuration
#PropertySource("classpath:default.properties")
public class DefaultConfig {}
I then want to be able to override to test=override, which is in a different properties file in class OverrideConfig, so I again use #PropertySource.
#Configuration
#Import(DefaultConfig.class)
#PropertySource("classpath:override.properties")
public class OverrideConfig {}
I configure a test to prove that it works.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={OverrideConfig.class})
public class TestPropertyOverride {
#Autowired
private Environment env;
#Test
public void propertyIsOverridden() {
assertEquals("override", env.getProperty("test"));
}
}
Except of course it does not.
org.junit.ComparisonFailure: expected:<[override]> but was:<[default]>
Maxing out debug, I can see what's happening:
StandardEnvironment:107 - Adding [class path resource [default.properties]] PropertySource with lowest search precedence
StandardEnvironment:107 - Adding [class path resource [override.properties]] PropertySource with lowest search precedence
It seems backwards. Am I making a simple mistake or misthinking this, or would you expect the properties defined by an #PropertySource in an #Import-ed configuration class to be overridden by properties defined in am #PropertySource in the #Import-ing class?
Here is a solution by Helder Sousa, written as a comment of the JIRA issue created by the OP:
[T]he behaviour available in spring xml (one xml importing another xml) is achievable using nested configurations:
#Configuration
#PropertySource("classpath:default.properties")
public class DefaultConfig {}
#Configuration
#PropertySource("classpath:override.properties")
public class OverrideConfig {
#Configuration
#Import(DefaultConfig.class)
static class InnerConfiguration {}
}
With this setup, the properties will be gather in the proper order.
Today with Spring 4 you can use this:
#TestPropertySource(value="classpath:/config/test.properties")
And this can be used to use and eventually override properties for the junit test:
#RunWith(SpringJUnit4ClassRunner.class)
#TestPropertySource(value="classpath:/config/test.properties")
I'm currently struggling with a similar case in Spring 3.1 but I'm using a different approach to override properties, because #PropertySource does not support optional property files:
#Configuration
#PropertySource("classpath:default.properties")
public class BaseConfig {
#Inject
private ApplicationContext context;
#PostConstruct
public void init() throws IOException {
Resource runtimeProps = context.getResource("classpath:override.properties");
if (runtimeProps.exists()) {
MutablePropertySources sources = ((ConfigurableApplicationContext) context).getEnvironment().getPropertySources();
sources.addFirst(new ResourcePropertySource(runtimeProps));
}
}
...
It seems that #Import does not cause any specific order of #Configuration instantiation whatsoever besides the order dictated by normal bean dependencies. A way to force such an order is to inject the base #Configuration instance itself as a dependency. Could you try:
#Configuration
#Import(DefaultConfig.class)
#PropertySource("classpath:override.properties")
public class OverrideConfig {
#Inject
private DefaultConfig defaultConfig;
...
}
Does this help?
And maybe the new ContextHierarchy annotation could be of help here also but I didn't try this one out so far.
You could enforce the loading order of your properties like this:
#Configuration
#PropertySource(value={"classpath:default.properties","classpath:override.properties"})
public class OverrideConfig {
...
}
I had a similar problem and succeeded in just declaring also the default property in my custom configuration:
#Configuration
#Import(DefaultConfig.class)
#PropertySource({"classpath:default.properties", "classpath:override.properties"})
public class OverrideConfig {}

Resources