Spring boot Custom Properties - java

in my project there are 2 resource properties
1. application.properties
server.port=8002
spring.data.mongodb.host=
spring.data.mongodb.port=
spring.data.mongodb.database=
spring.data.mongodb.username=
spring.data.mongodb.password=
2. application-development.properties
server.port=8002
spring.data.mongodb.host=
spring.data.mongodb.port=
spring.data.mongodb.database=
spring.data.mongodb.username=
spring.data.mongodb.password=
spring.data.solr.host
this class uses the value properties of development
#Configuration
#EnableSolrRepositories(basePackages = {
"id.alfadigital.alfagift.service.product.v1.db.solr.repository",
"id.alfadigital.alfagift.service.product.v2.db.solr.repository"
})
public class SolrConfiguration {
#Value("${spring.data.solr.host}")
private String solrUrl;
#Bean
public SolrClient solrClient() {
return new HttpSolrClient.Builder(solrUrl).build();
}
#Bean
public SolrTemplate solrTemplate(SolrClient client) {
return new SolrTemplate(client);
}
}
I use application-development.properties as my project resoure
so I run the project with the following command :
mvn spring-boot:run -D spring.profiles.active=development
but an error is attached when I run the project
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'solrConfiguration':
Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException:
Could not resolve placeholder 'spring.data.solr.host' in value "${spring.data.solr.host}"
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.data.solr.host' in value "${spring.data.solr.host}"
I'm confused, where are my mistakes, and how should I do?

Can you please run your application with following command. Because of wrong use of command it's not able to pick up the development profile.
mvn spring-boot:run -Dspring.profiles.active=development
Example:
how to use Spring Boot profiles

Provided you have the correct file name application-development.properties and correct Java Opts -Dspring.profiles.active=development, you must also place the profile specific properties file alongside with application.properties
Profile-specific properties are loaded from the same locations as standard application.properties
https://docs.spring.io/spring-boot/docs/2.1.12.RELEASE/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties

Make sure your properties file matches up with the name of your Spring profile as described here.
That is, if you are running from a "development" profile, Spring should pick up the application-development.properties file (or application-development.yml).
Then in your application.properties file you can specify your profile by using spring.profiles.active=development. Or you can specify the profile from the command line using -Dprofile as you mention.
As mentioned in in the link, "If several profiles are specified, a last-wins strategy applies. For example, profiles specified by the spring.profiles.active property are added after those configured through the SpringApplication API and therefore take precedence."
But also note that in your shared code you have no value for your spring.data.solr.host property.

Related

Spring Boot Property file precedence

In my Spring Boot program I'm getting a failure due to a bad property value on load. In particular, it uses the DB2 hibernate dialect but it's not defined in the property file I thought I was using.
Assuming no annotations, where does Spring look for the properties file? Yes I know it normally resides in src/main/resources/application.properties
What if I have a property in my test cases; does it ignore the one in main and use the one in test? Or does it start with the main version and let the test one override the main where it applies?
Does the application profile affect the property file used? Some people use the same application.properties file name in both main and test.
If I do have a TestSource annotation with a class path location, does it still augment it with something somewhere else?
Finally, how can I get Spring to tell me everywhere it looked for properties and not just one of them?
#Woodsman
It's possible to use many settings in each profile/environment in spring application on src/main/resources/ folder
application-dev.properties
application-local.properties
application-onlytests.properties
application-prd.properties
application.properties
the name after hyphen will be the name profile got by spring
Ex: application-{myenviroment}.properties
When you start spring application will be used application.properties by default.
You can tell spring to use an specific properties passing the environment in one of ways below:
Putting spring.profiles.active=prd inside application.properties file
Passing by parameters when start spring app --spring.profiles.active=local
Running your jar on command line java -jar myjar.jar --spring.profiles.active=dev
Setting an environment var in your machine/docker/container SET SPRING_ACTIVES_PROFILE=local
There are other ways using annotations on beans, passing jvm arguments and others
If you need run your tests in a specific configuration ( vars, database, settings ), It's possible to pass which .properties will be used
#ExtendWith(SpringExtension.class)
#AutoConfigureMockMvc
#SpringBootTest
#TestPropertySource(locations = "classpath:application-onlytests.properties")
public class RunTest_from_onlytests_properties {
#Autowired
private MockMvc mockMvc;
#Test // org.junit.jupiter.api.Test
public void test() throws Exception{
// ...
}
}

Spring Boot refuses to pick up application test properties [duplicate]

I have a spring boot application that I can package in a war that I want to deploy to different environments. To automate this deployment it'd be easier to have the configuration file externalized.
Currently everything works fine with a application.properties file in src/main/resources. Then I use ´mvn install´ to build a war deployable to tomcat.
But I would like to use a .yml file that does not need to be present on mvn install but that would be read from during deployment of the war and is in the same or a directory relative to my war.
24. externalized configuration shows where spring boot will look for files and 72.3 Change the location of external properties of an application gives more detail on how to configure this but I just do not understand how to translate this to my code.
My application class looks like this:
package be.ugent.lca;
Updated below
Do I need to add a #PropertySource to this file? How would I refer to a certain relative path?
I feel like it's probably documented in there as most spring boot documentation but I just don't understand how they mean me to do this.
EDIT
Not sure if this should be a separate issue but I think it's still related.
Upon setting the os variable the error of yaml file not found went away. Yet I still get the same error again as when I had no application .properties or .yml file.
Application now looks like this:
#Configuration
**#PropertySource("file:${application_home}/application.yml")**
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
The application_home OS variable
$ echo $application_home
C:\Masterproef\clones\la15-lca-web\rest-service\target
My application.yml file(part it complains about):
sherpa:
package:
base: be.ugent.lca
Error upon java -jar *.war
All variations upon:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'sherpa.package.base' in string value "${sherpa.package.base}"
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:204)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:178)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:808)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1027)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
... 142 more
Using external properties files
The answer lies in the Spring Boot Docs, I'll try to break it down for you.
First of all, no you should not use #PropertySource when working with Yaml configuration, as mentioned here under the Yaml shortcomings :
YAML files can’t be loaded via the #PropertySource annotation. So in the case that you need to load values that way, you need to use a properties file.
So, how to load propery files? That is explained here Application Property Files
One is loaded for you: application.yml , place it in one of the directories as mentioned in the link above. This is great for your general configuration.
Now for your environment specific configuration (and stuff like passwords) you want to use external property files, how to do that is also explained in that section :
If you don’t like application.properties as the configuration file name you can switch to another by specifying a spring.config.name environment property. You can also refer to an explicit location using the spring.config.location environment property (comma-separated list of directory locations, or file paths).
So you use the spring.config.location environment property.
Imagine you have an external config file: application-external.yml in the conf/ dir under your home directory, just add it like this:
-Dspring.config.location=file:${home}/conf/application-external.yml as a startup parameter of your JVM.
If you have multiple files, just seperate them with a comma. Note that you can easily use external properties like this to overwrite properties, not just add them.
I would advice to test this by getting your application to work with just your internal application.yml file , and then overwrite a (test) property in your external properties file and log the value of it somewhere.
Bind Yaml properties to objects
When working with Yaml properties I usually load them with #ConfigurationProperties, which is great when working with for example lists or a more complex property structure. (Which is why you should use Yaml properties, for straightforward properties you are maybe better of using regular property files). Read this for more information: Type-Safe Configuration properties
Extra: loading these properties in IntelliJ, Maven and JUnit tests
Sometimes you want to load these properties in your maven builds or when performing tests. Or just for local development with your IDE
If you use IntelliJ for development you can easily add this by adding it to your Tomcat Run Configuration : "Run" -> "Edit Configurations" , select your run configuration under "Tomcat Server" , check the Server tab and add it under "VM Options".
To use external configuration files in your Maven build : configure the maven surefire plugin like this in your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dspring.config.location=file:${home}/conf/application-external.yml</argLine>
</configuration>
</plugin>
When running JUnit tests in IntelliJ:
Run → Edit Configurations
Defaults → JUnit
add VM Options -> -ea -Dspring.config.location=file:${home}/conf/application-external.yml
Yes, you need to use #PropertySource as shown below.
The important point here is that you need to provide the application_home property (or choose any other name) as OS environment variable or System property or you can pass as a command line argument while launching Spring boot. This property tells where the configuration file (.properties or .yaml) is exactly located (example: /usr/local/my_project/ etc..)
#Configuration
#PropertySource("file:${application_home}config.properties")//or specify yaml file
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
There is a very simple way to achieve this.
Inside your original application.properties file you can just specify the following line:
spring.config.import=file:Directory_To_The_File/Property_Name.properties
It will automatically sync all the properties from the external property file.
Now lets say that you have a situation where you need to get properties from multiple property files. In that case, you can mention the same line in the external property file which in turn will take the remaining properties from the second property file and so on.
Consider the following example.
application.properties:
spring.config.import=file:Resources/Custom1.properties
Custom1.properties:
server.port=8090
.
.
.
spring.config.import=file:Resources/Custom2.properties
One of the easiest way to use externalized property file using system environment variable is, in application.properties file you can use following syntax:
spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB"
spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME}
spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PORT}
Now, declare above used environment variables,
export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost"
export OPENSHIFT_MYSQL_DB_PORT="3306"
export OPENSHIFT_MYSQL_DB_USERNAME="root"
export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"
This way you can use different value for same variable in different environments.
Use below code in your boot class:
#PropertySource({"classpath:omnicell-health.properties"})
use below code in your controller:
#Autowired
private Environment env;

Accesing spring boot's application.properties on weblogic 10.3.6

I am trying to acces a value defined in application.properties in a following way:
#Value("${server.url}")
private String serverUrl;
It works on embedded tomcat, but when I upload it to Weblogic I get the following error:
Error creating bean with name 'authorizationServiceImpl': Injection of
autowired dependencies failed; nested exception is
java.lang.IllegalArgumentException: Could not resolve placeholder
'server.url' in value "${server.url}"; nested exception is
java.lang.IllegalArgumentException: Could not resolve placeholder
'server.url' in value "${server.url}"
How can I make use of the application.properties file when hosting app on Weblogic server?
I found that if you want to use external properties on weblogic 10.3.6 you need to put the file in desired location and use the follwing annotation for setting property source in configuration/startup class:
#PropertySource(value = { "file:/...domains/MYdomain/application.properties" })
You should never place the application-XXX.properties files specific to an environment in the deployed component itself.
You should always externalize them outside it.
So, to solve your missing properties file problem, you have just to add the properties file(s) in a folder that you will add in the weblogic runtime classpath.
You can set the setDomainEnv.cmd/sh file of your domain and
add the folder path in the CLASSPATH variable.
For example, in Weblogic (11, 12 and maybe other older versions but not sure), in setDomainEnv.cmd, you should find this lines :
set JAVA_OPTIONS=%JAVA_OPTIONS%
#REM SET THE CLASSPATH
Replace #REM SET THE CLASSPATH by
SET CLASSPATH = %CLASSPATH%;yourPropertiesFilesAbsolutePath

Spring Boot executable jar and external configuration file

I have a Spring Boot application that uses 3rd-party jar. This jar requires an xml config file, that must be provided by clients on runtime (individually) and cannot be pre-packaged. 3rd party lib loads that file using below sequence (I stripped ifs and null-checks):
FileConfigurator.class.getResource("/" + filename);
Thread.currentThread().getContextClassLoader().getResource("/" + filename);
Thread.currentThread().getContextClassLoader().getResource(filename);
I cannot change the way that lib loads the file (e.g. using Spring's Resource loading), so it must be on classpath. Therefore I seem to lose the possibility of executing it like java -jar my-spring-boot-app.jar, because -jar option prevents any additional classpath entries from being added. So I started running it like
java -classpath my-spring-boot-app.jar:./config/: org.springframework.boot.loader.JarLauncher
My directory structure is following:
|-- config
| |-- application.properties
| `-- 3rd-party-config.xml
|-- my-spring-boot-app.jar
But then Spring's autowiring started to fail: Additional application.properties file in config directory overrides some of settings and using above command causes app startup to fail:
Error creating bean with name 'ORBConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String com.company.app.communication.corba.orb.ORBConfig.serverName; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'application.corba.serverName' in string value "${application.corba.serverName}"
Field String serverName is annotated with #Value("${application.corba.serverName}"), the property is defined in application.properties file bundled within JAR and value injection works fine when additional application.properties is not present in config dir.
My actual question is: what is the advisable way of deploying and/or running Spring Boot application, to take advantage of executable Jar feature, provide additional classpath resources on runtime and still be able to override some (but not all) properties by classpath application.properties file?
Application is packaged using spring boot maven plugin and uses spring-boot-starter-parent parent POM.
One simple answer if you won't change the startup command:
move ./config/application.properties to ./config/config/application.properties
If there exist more than one classpath resources with same name, Spring Boot will load only one of them, in you case, Spring Boot load and prioritize property resources as following:
file:config/application.properties
classpath:application.properties which maybe resolved to either my-spring-boot-app.jar!/applcation.properties or ./config/application.properties
If your classLoader chosen ./config/application.properties as second property source. Bang!
Spring Boot's default configuration property resource path priority (highest to lowest precedence) is:
file:config/
file:
classpath:config/
classpath
The ordinary executable jar execution make those two configuration property fall into:
file:config/application.properties
classpath:application.properties (from jar)
And moving ./config/application.propertie to './config/config/application.properties' becomes:
classpath:config/application.properties
classpath:application.properties (from jar)
Both in the same order and have no ambiguous.

#PropertySource in a Jar for an external file on the classpath

I'm trying to use the Spring framework's #PropertySource annotation in a Jar to load a properties file from outside the jar, but it's not finding the file.
I need the properties file to be external to the Jar so it can be edited. I don't know the exact location where the file will be, I figured I could just have it anywhere on the classpath.
I'm using the following annotation on my Config class.
#PropertySource('classpath:stc.properties')
And placed stc.properties in the same directory as the created Jar file. I tried specifying the classpath explicitly in the java command, but it still cannot find the file:
java -cp . -jar stc.jar
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: Failed to load bean class: com.example.stc.Config; nested exception is java.io.FileNotFoundException: class path resource [stc.properties] cannot be opened because it does not exist
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:162)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:299)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:243)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:254)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:94)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:609)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
[...]
Etc.
I've also tried using ./ as the classpath, and tried specifying the classpath (with both variants) in the Class-Path attribute of the jar's manifest, but it always gives the same results.
Assuming you have two files, one for local one for production
#PropertySources({
#PropertySource("classpath:application.properties"),
#PropertySource(value = "${ws.properties}", ignoreResourceNotFound = true)
})
And in tomcat or your jar file , pass on this parameter
-Dws.properties=file:/path-to.properties
I added this in setenv.sh
APPLICATION_OPTS="-Dlog4j.configurationFile=file:$PATH/log4j2.xml -Dlog4j.debug=true -Dapplication.properties=file:$PATH/application.properties
This is possible with Spring 4 only
Use a variable (System or Environment) to have the value of the file and you could refer your file like this:
#PropertySource("file:${MY_PATH}/application.properties")
My environment was:
OS: Windows | Container: Tomcat | Java: 7 | Spring: 4.2.4 | Springboot 1.3.1 | Maven
Step 1 a (war):
Add the file externalised properties file to JVM system properties.
As am running this off tomcat; I done this by creating setenv.bat in <TOMCAT_HOME>/bin/setenv.bat
set CATALINA_OPTS=%CATALINA_OPTS% -Dexternal.app.properties=file:<PATH_TO_EXTERNAL_FILE>\application-prod.properties
Step 1 b (jar):
Alternative if you are running from a jar use:
-Dexternal.app.properties=file:<PATH_TO_EXTERNAL_FILE>\application-prod.properties
Note the use of file: at the start on the line.
Step 2: In my application startup class I used annotation #PropertySource to load the specific environment application properties.
#SpringBootApplication
#PropertySources({
#PropertySource(value = "${external.app.properties.file}", ignoreResourceNotFound = true),
#PropertySource(value = "classpath:application.properties")
})
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
Step 3:
Using externalised properties in project
external/file/path/application-prod.properties
spring.datasource.url.ext=< PRODUCTION_DATASOURCE >
/src/main/resources/application.properties
spring.datasource.url=${spring.datasource.url.ext}
Hope this helps other having the same problem.
try giving the full path of the file:
#PropertySource('file:c:/.../stc.properties')
you could use --spring.config.location=file:/somepath parameter when running jar, where you specify path to config file (could be relative).
More info in docs
Let's say you have a jar with a default main and some default stc.properties inside the classpath.
An option would be that if there is a configuration file with that name next to the jar (actually in the execution directory) the properties that are set inside that config are merged with the ones of default config.
If the user decides not to use the external config, no error occurs.
For the above scenario you need:
#PropertySources({
#PropertySource("classpath:stc.properties"),
#PropertySource(value = "file:./stc.properties", ignoreResourceNotFound = true)
})
e.g. let's say the default stc.properties (inside the jar) content is:
propA=valueA
propB=valueB
Now if I add a file with the same name next to the jar containing:
propB=updatedValueB
propC=valueC
The effective loaded properties when executing java -jar stc.jar are:
propA=valueA
propB=updatedValueB
propC=valueC

Categories