I have common project whith spring configuration class
#Configuration
#ImportResource(locations = {"classpath*:spring/spring-test-context.xml"})
public class CommonConfiguration{
}
In this spring-test-context.xml there are some beans which requires injection of values from properties file.
I use this common library in several projects but these properties are not used in all projects.
So I put them with null value in application.properties file in this common library but they are not visible from there in given projects so I need to add null values in application.properties file in each project which have dependency to common library.
I'd like to have this properties with deafult values in common library and to be overwritten with specific values in project where they are needed ?
How to do it ?
You should be able to achieve your goal providing the PropertySource from the common library application.properties. Maybe rename it to spring-test-context.properties just to make sure there is no confusion with the standard properties file:
#Configuration
#PropertySource("classpath:spring-test-context.properties")
#ImportResource(locations = {"classpath*:spring/spring-test-context.xml"})
public class CommonConfiguration{
}
Related
I have two spring boot apps. The first is an API library that's pulled into the second (a web application) as a dependent jar.
The first, is an API library that houses functions to create "cases" in an IBM solution. It's a standalone type jar that has a service class that exposes methods like getCaseXMLForDocId(String docId) or createCaseForAgreementNumber(String agreementNumber)
The first library called CaseInvocationAPI has an application.properties file which has several properties. For example:
caseinvocation.query.fetchNonProcessedCaseXml=SELECT Id, CaptureSource, AgreementNumber, CaptureSourceID FROM CaseInvocation WHERE ProcessIndicator IN (0, 2)
The service class has a method which makes a query, grabbing that query string from a member variable that's populated with a property from the application.properties file:
#Value("${caseinvocation.query.fetchNonProcessedCaseXml}")
private String selectNonProcessedQueryString;
The second SpringBoot app is a webapplication that has REST controllers. These controllers expose endpoints that call the CaseInvocationAPI library, specifically the CaseInvocationService class.
The problem I am having is that when the SpringBoot WEBAPPLICATION starts up, the context configuration blows up with the following error:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'caseinvocation.query.fetchNonProcessedCaseXml' in string value "${caseinvocation.query.fetchNonProcessedCaseXml}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:219)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:193)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:813)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1039)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
... 45 common frames omitted
It appears that when the WebApp starts up, when it's trying to build the classes from the dependent jar, those properties are not being found.
I didn't think I had to copy each and every property out of the dependent jar application.properties file into an application.properties file in the Webapp project.
Why isn't the WebApp project (CaseInvocationWebApp) picking up the application.properties file from the dependent jar file (CaseInvocationAPI)?
I checked the compiled jar file (CaseInvocationAPI) and the application.properties file is there in the jar.
Looks like the problem was related to the fact that both the child jar and the webapp have application.properties files. I wasn't aware that the parent WebApp application.properties sort of overwrites the others (ignoring all others really).
Special thanks to Paschoal for his response.
You can see details on the answer here:
Adding multiple application.properties files
There are 3 ways (that I can think of) you can approach this:
The dependency, API library, should not have an application.properties since it's a library and not an executable Spring boot application in itself. You only define the properties in your web application's application.properties, even for the API library.
But, here the assumption is that you have access to the API library jar.
You can redefine all the properties in web application's application.properties essentially overriding them.
Explicitly configure the Spring boot application to use both the application.properties files, each for different set of properties.
Caveat: The file names must be different, as config location is classpath for both.
#SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplicationBuilder(WebApplication.class)
.properties("spring.config.location=classpath:api-application.properties,classpath:application.properties")
app.run(args);
}
}
I have a project, let's call it BaseProject, which contains a properties file defining different configurations. One of those properties could be security.password.minlength=4.
Now I have a ProjectA which builds up on BaseProject and there for depends on it.
ProjectA
|
|--BaseProject
Now in ProjectA I would like to have a default security.password.minlength of 8.
If I simply add a application.properties file to my ProjectA, containing security.password.minlength=8 and the specific property is set to 8. Al tough all the other properties form my BaseProject are ignored now, giving me the exception: java.lang.IllegalArgumentException: Could not resolve placeholder
I still would like to use all properties defined in BaseProject but solely set the security.password.minlength to a different value. How can I achieve this?
Update
Currently I let Spring do the handling of the application.properties file. Inside my application, I simply get the values from the Spring environment.
If you are using the default property handling of Spring Boot, you can make use of profiles. E.g. you could use a profile named projecta for your derived project and specify your properties in a file named application-projecta.properties. This will automatically be picked up when you specify the profile to be active (see here: http://www.baeldung.com/spring-profiles)
I found the following solution for me:
BaseProject has a application.properties which contains all the default values.
ProjectA has a projectA.properties which is I integrate with
#PropertySource("projectA.properties")
public class ProjectA {
public static void main(String[] args) {
SpringApplication.run(ProjectA .class, args);
}
}
This allows me to override any property from the BaseProject project in the projectA.properties file. The properties which I don't define in projectA.properties are still taken from the application.properties of the BaseProject`.
I am unable to read application.properties value in my project in classes that are injected as a bean from another project. My project is using another project which has classes which needs to read configuration from application.properties.
Mine is a maven project and a spring boot application having application.properties in src/main/resources folder and those properties values are defined in it.
What is it that I am missing that it is unable to read file values? Or is there is any other mechanism for setting these properties for classes loaded via component-scan
Below line of code works fine, it is able to read value from the application.properties:
#PostConstruct
void init() throws ClassNotFoundException, IOException {
System.out.println(context.getEnvironment().getProperty("env.host",
"default value"));
}
Now there is another project which I am using in mine. When loading the classes those beans are getting initialized as dependency of another class, there also it tries to read same value in constants file as
static final String HOST_PROPERTY = "${env.host}";
There this value is not getting initialized to value from applictaion.properties
If you want to get application.properties values,you have to two option.
1) you can autowire Environment class and use its getProperty() method as
#Autowired
Environment env;
env.getProperty("${env.host}");
2)#Value annotation
#Value("${env.host}")
String HOST_PROPERTY;
If I create a commons library having an application.properties defining common configurations. Like:
spring.main.banner-mode=off
How can I inherit these properties into another project where I include those commons library?
Maven:
<project ...>
<groupId>de.mydomain</groupId>
<artifactId>my-core</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<!-- this one holds the common application.properties -->
<groupId>my.domain</groupId>
<artifactId>my-commons</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
How can I inherit the configuration from my-commons to my-core?
Solution is to include the shared properties using a different name, here application-shared.properties
In shared library:
#SpringBootApplication
#PropertySource(ResourceUtils.CLASSPATH_URL_PREFIX + "application-shared.properties") //can be overridden by application.properties
public class SharedAutoConfiguration {
}
In main app:
#SpringBootApplication
#Import(SharedAutoConfiguration.class)
public class MainAppConfiguration extends SpringBootServletInitializer {
}
This way the commons/shared config gets loaded, but is though able to be overridden in application.properties of main app.
It does not work with the spring.main.banner-mode property (don't know why), but with all other properties it worked well.
I had a same motivation - to extract common configuration for typical service into a separate starter/library. I've decided to move with EnvironmentPostProcessor
My commons-web library has its own application-web.properties with, lets say, single property:
spring.main.banner-mode: off
And EnvironmentPostProcessor to pick it up
public class DefaultPropertiesEnvironmentPostProcessor implements EnvironmentPostProcessor {
#SneakyThrows
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
environment.getPropertySources()
.addLast(new ResourcePropertySource("application-web.properties"));
}
}
To make it works you need to specify a post processor (on a library side) in resources/META-INF/spring.factories this way:
org.springframework.boot.env.EnvironmentPostProcessor=\
com.surprise.starter.web.properties.DefaultPropertiesEnvironmentPostProcessor
With such solution it's possible to pick up this config on service side and override it in regular application.properties
I'm not using #PropertySource cause there is nuance with properties ordering & detection:
...
#PropertySource annotations on your #Configuration classes. Please
note that such property sources are not added to the Environment until
the application context is being refreshed. This is too late to
configure certain properties such as logging.* and spring.main.* which
are read before refresh begins.
You can try this with Spring.
You can define your src/main/resources/application.properties in a common module as you mentionned. It will be present in classpath for other project that depends on it.
Then with Annotation #PropertySource, in other projects that depends on common module :
#Configuration
#PropertySource("classpath*:META-INF/spring/properties/*.properties")
public class Config {
...
}
Or with XML configuration :
<context:property-placeholder location="classpath*:META-INF/spring/properties/*.properties"/>
It should import all the configuration files in the give classpath directory.
Also, you should be aware that you can't have two same files in classpath. You will have a conflict.
For instance, this situation will generate a conflict :
Project A (depends on Project B) :
src/main/resources/application.properties
Project B :
src/main/resources/application.properties
You will have to rename application.properties file or to put it in a different directory.
I'm having a problem properly setting up spring boot for my multi-module maven project.
There is a module "api" that uses another module "core". Api has an application.properties file that contains spring.mail.host=xxx. According to the spring boot documentation this provides you with a default implementation of the JavaMailSender interface, ready to be autowired.
However the class that is responsible for sending out the e-mails resides in the "core" package. When I try to build that module the build fails because no implementation of JavaMailSender can be found.
My guess then was that the mailing config should reside in "core" in a separate application.properties. I created that and moved the spring.mail.host property from the "api" to the "core" property file.
This time the core module builds successfully, but "api" fails to build because of the same exception, so I think I just moved the problem.
I don't understand the required structure for handling this type of situations well enough so I was wondering what the correct way is for having a "core" module containing all the correct configuration for sending mails and having other modules use the mailing code and config that resides in it.
I found the answer in another stack overflow question: How to add multiple application.properties files in spring-boot?
It turns out there can only be 1 application.properties file in the final jar that spring boot creates. To have multiple files you have to rename one of the files to something custom. I named the properties of the core module "core-application.properties".
Then in the API module I added this to the spring boot application class:
#SpringBootApplication
#PropertySource(value = {"core-application.properties", "application.properties"})
Doing this I can correctly use the base properties file and overwrite them in the more specific modules. Also you can still create profile-specific properties file (core-application-production.properties) with this setup, no need to add those to the propertysource manually). Note that #PropertySource does not work for yaml configuration files at this moment.
there is one effective application.properties per project. you just keep 2 properties file for a success build.
when api module use core module, the application.properties in core module is overwrite by api.
Your API's pom.xml must has dependency of CORE module.
the solution is to define properties files as a value of #PropertiesSource in Starter class.
but it is beter to put "classpath:" behind the properties files.
for example in Intellij idea after adding the "classpatch:" word berhind the files name, values become to link. like this:
#SpringBootApplication
#PropertySource(value = {"classpath:core-application.properties", "classpath:application.properties"})
I hope to helped you.