#PropertySource working with spel (systemEnvironment and systemProperties) - spring

I have in src/main/resources the following files
bpp-dev.properties
bpp-prod.properties
bpp-test.properties
Through my STS I can define the key envB, it in two places
how a VM argument such as -DenvB=dev
how an Environment such as Variable envB and Value prod
If in a Configuration class I have the following.
#Configuration
#PropertySource("classpath:/com/manuel/jordan/properties/bpp-${envB}.properties")
public class PropertiesConfiguration {
It works fine but always has preference the System Properties over Environment Variables, it is the default behaviour. I have no problem here.
But if I want work explicitly with Environment Variables, the following fails
#Configuration
#PropertySource("classpath:/com/manuel/jordan/properties/bpp-#{systemEnvironment['envB']}.properties")
public class PropertiesConfiguration {
Always I receive:
Caused by: java.io.FileNotFoundException:
class path resource
[com/manuel/jordan/properties/bpp-#{systemEnvironment['envB']}.properties]
cannot be opened because it does not exist
How I can fix this?
If I use the functional #PropertySource and just playing in the same #Configuration class I work with the following:
#Value("#{systemProperties['envB']}")
private String propertiesEnvB;
#Value("#{systemEnvironment['envB']}")
private String environmentEnvB;
to be printed later, both works fine.

Related

spring boot read property value from file content (not property file)

Is there a way to inject the value of a property from file content?
In my case i want to read a public certificate:
#ConstructorBinding
#ConfigurationProperties(prefix = "certificate")
#Value
public class Certificate {
String publicKey;
}
The certificate is in a file with content like
-----BEGIN CERTIFICATE-----
MIIC3DCCAcSgAwIBAgIGAYYWvEf6MA0GCSqGSIb3DQEBCwUAMC8xLTArBgNVBAMM
JDhjOGVmNjQxLTEwMGEtNDUxMi1iOTFhLWM3Mzc5NDcwMTdjMzAeFw0yMzAyMDMx
...
4/eJiZvtUhlPTZAeBCbmwHhLFufMRrYtOje/JLDcXFUhF4Ypb6BITbbWijJ7oMqP
1Amyt3eKiVhFdIVk1U4gp19wda4oeKP+5gaPTvAlYrN+EWdC1lUDRBipcM5zioFk
CwELjzRA2Dzg059g93NN7Q==
-----END CERTIFICATE-----
Currently i have 2 ways to load this as property:
load it in env variable with shell CERTIFICATE_PUBLIC_KEY="$(cat ./certs/device-cert.pem)" - need to run before
change the file to a property file beginning with certificate.publicKey=
and adding "\n" at every line end and adding it as additional property source
Is there a way to load the file content directly into a property on start?
At the moment i don't want to loose the Spring Boot Property feature - because it is really flexible.
If not possible i can of course just load the file and use its content.
It is possible with Spring. You can add the following option to your application properties file:
spring:
config:
import: configtree:/specify_the_path_where_your_file_is_located/
Then you should put your public key file to that location and give a name to this file according to your desired configuration properties:
certificate.publicKey
And you're done here! During application startup the content of that file will be injected to that property and will be both accesible from your configuration properties or from Environment bean

Could not resolve placeholder 'XXX' in string value "${XXX}"

In my spring boot example, I'd like to read environment variables from my local machine(Win 7).
#Data
#Component
public class EnvironmentVariableSystemProperties {
#Value("${java.home}")
private String javaHome;
#Value("${DATASTORE.DATASET}")
private String datastoreDataset;
#Value("${SPRINGA}")
private String springConfigName;
}
It works well when reading java.home and DATASTORE.DATASET which have been added in my OS environment variables before.
I just added a new variable SPRINGA. When running spring boot example, I got the error:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'SPRINGA' in string value "${SPRINGA}".
Should I restart up my machine to make the variable work?
I just restarted Eclipse, but it didn't work.
Restarting Eclipse with the Restart in the Menu doesn't work.
Exiting Eclipse and Running it again works.
How weird it is!

Injecting Environment Variable into Groovy / Spring

I have a groovy class that uses spring injection to get a hostname (previously defined in application.properties). It works fine, the code looks like this:
import org.springframework.beans.factory.annotation.Value
... ...
#Value('${mycontext.var1}')
private String serverHost
Now, instead of using application.properties, I'd like to inject from an environment variable named SERVER_HOSTNAME. I tried the following, but it does not work.
#Value('${System.getenv("SERVER_HOSTNAME")}')
private String serverHost
It seems that the following piece of code should work:
#Value("#{environment.SERVER_HOSTNAME}")
private String serverHost

How to add an active spring profile from an environment variable?

Until now, I'm setting the following environment variable in my ~/.bash_profile :
export SPRING_PROFILES_ACTIVE=local
This set my active spring profile. But now, I want to add the local profile to other profiles defined in application.properties and not replace them.
In the Spring Boot documentation, there is a section about adding active profile, but I see nothing about adding active profile from an environment variable.
I've tried to set the SPRING_PROFILES_INCLUDE environment variable, but this has no effect.
How to do this?
P.S.: I'm using Spring Boot 1.4.2.
With default addition profile
You can introduce your own environment variable in the application.properties file, next to the defined profiles using an expression. For instance, if your current file looks like this:
spring.profiles.active=profile1,profile2
with a custom environment variable it will change into:
spring.profiles.active=profile1,profile2,${ADDITIONAL_APP_PROFILES:local}
where ADDITIONAL_APP_PROFILES is the name of the environment variable which you set instead of SPRING_PROFILES_ACTIVE.
The value local is used when the variable is not set on a current environment. In that case, the profile called local will be activated. If you don't set the default value and the environment variable is not present, the whole expression will be used as the name of an active profile.
Without default addition profile
If you like to avoid activating the default profile, you can remove the placeholder value and the comma before the variable expression:
spring.profiles.active=profile1,profile2${ADDITIONAL_APP_PROFILES}
but in that case the variable set on a current environment have to start with a comma:
export ADDITIONAL_APP_PROFILES=,local
The next sentence in the documentation you linked to:
Sometimes it is useful to have profile-specific properties that add to the active profiles rather than replace them. The spring.profiles.include property can be used to unconditionally add active profiles.
So you can launch your application with a command-line parameter:
-Dspring.profiles.include=${SPRING_PROFILES_INCLUDE}
This is an example of adding a programmatically additional active profile from system env or jvm arg.
#Configuration
public class ApplicationInitializer implements WebApplicationInitializer, ApplicationContextInitializer<ConfigurableWebApplicationContext> {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("contextInitializerClasses", this.getClass().getCanonicalName());
}
#Override
public void initialize(ConfigurableWebApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
environment.addActiveProfile(System.getProperty("myProperty"));
environment.addActiveProfile(System.getEnv("myProperty"));
}
}
Here is not the Spring way, but also could be useful in some cases.
public static void main(String[] args) {
System.setProperty("spring.profiles.active", "local");
SpringApplication.run(MainApplication.class, args);
}
To support bash environment, available values are SPRING_PROFILES_ACTIVE and SPRING_PROFILES_DEFAULT
not, SPRING_PROFILES_INCLUDE
you probably have to resort commandline way -Dspring.profiles.include or pro grammatically workout with ConfigurableEnvironment
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/AbstractEnvironment.html#ACTIVE_PROFILES_PROPERTY_NAME

How to externalize configuration in Spring Boot using profiles?

I have an application where I would like to change a datasource password that is stored in a application.yml file. The password in the YML file is stored such as this:
----
spring:
profiles: production
datasource:
password: prodpassword
Note: I also have profiles for development and stage.
The password prop is set on a class using ConfigurationProperties such as follows:
#Component
#ConfigurationProperties(prefix="datasource")
public class DataSourceConnector {
private password;
public void setPassword(String password) {
this.password = password;
}
Now, I try to override the prodpassword with prodpa$$word via a command line arg but it doesn't work:
java -Dspring.profiles.active=production -jar /usr/share/myapp/myapp-1.0.jar --datasource.password='prodpa$$word'
I also tried creating an identical (except the new password) application.yml file outside of the jar. That doesn't work either.
java -Dspring.profiles.active=production -jar /usr/share/myapp/myapp-1.0.jar --spring.config.location=/usr/share/myapp/
Note: I left out the file name in the location param due to this note from http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-profile-specific-properties:
If you have specified any files in spring.config.location, profile-specific variants of those files will not be considered. Use directories inspring.config.location if you also want to also use profile-specific properties.
How can I override datasource.password within the application.yml of the jar?
Edit:
The application is being started / stopped using supervisorctl.
After changing the config file that contains the java command, supervisorctl must reread the change:
supervisorctl reread
Next, activate the changes with:
supervisorctl update

Resources