I am trying to derive a value for a property in my application.yml config file using Spring SpEL expression, but it looks like the the expression is not getting evaluated.
Here's my application.yml snippet:
spring:
profiles: local
cloud.client.hostname: abc.pqr.xyz.lmn.westus.env.company.com
boot:
admin:
client:
instance:
metadata.tags.environment: local
metadata.tags.dc: "#{'${spring.cloud.client.hostname}'.split('.')[4]}"
url: http://localhost:8079
During runtime, the property spring.boot.admin.client.instance.metadata.tags.dc is being evaluated to abc.pqr.xyz.lmn.westus.env.company.com.split('.')[4] and expectation is that it be evaluated to westus.
What am I missing?
SpEL is not supported in application.yml.
Use #Value("#{'${spring.cloud.client.hostname}'.split('\\.')[4]}" ) String property in code instead.
Related
I have a Spring boot application with different environments. I have a main application.yml with a set of properties and an application-test.yml for my test environment.
Inside my application.yml, I have the following config
spring:
liquibase:
enabled: false
user: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
change-log: classpath:db/changelog-master.yaml
And inside my application-test.yml, I have the following
spring
liquibase:
user: sa
password: password
I was expecting my test environment to use liquibase.user and liquibase.password from the application-test.yml and pick the two other sub-properties (liquibase.enabled and liquibase.change-log) from application.yml. My reasoning was that in my test environment, the Application context would pick up all the properties in application.yml and then overwrite only the subkeys defined in application-test.yml, while keeping the original values of application.yml if not explicitly overwritten.
But that does not seem to be the case; it looks as if the key liquibase in my application-test.yml overwrites all the key and subkeys of the liquibase defined in application.yml.
Therefore since in my application-test.yml, liquibase.enabled and liquibase.change-log are not defined; the test environment does not know about these values. I was expecting them to be picked up from the main application.yml instead. I tried to define them manually in my application-test.yml and my tests work fine. If I remove them, my tests fail because they use the default properties for liquibase instead of liquibase.enabled: false and liquibase.change-log: classpath:db/changelog-master.yaml
What I would like to do is the following:
In my main application.yml, have
main_key:
sub_key_1: value_1
sub_key_2: value_2
sub_key_3: value_3
And in my application-test.yml, have only
main_key:
sub_key_1: test_value_1
have my test environment pickup sub_key_2: value_2 and sub_key_3: value_3 directly from application.yml, without them being overwritten by nothing in my test environment (since they are not defined in my application-test.yml)
Is it possible to have think kind of logic : if main_key.sub_key_2 is defined in application-test.yml is defined, then use it, otherwise use the main_key.sub_key_2 defined in application.yml ?
I feel that if I don't define all the sub_keys of my main_key in my application-test.yml, it is not possible to do it.
Many thanks for your help
Actually, I think I know why it does not work.
I had an empty application.yml inside my test/resources/application.yml. So I believe spring boot picks up the test/resources/application.yml instead of the src/main/resources/application.yml when test/resources/application.yml exists.
Which explains why the properties in my src/main/resources/application.yml were not picked up at all.
The solution was simply to delete the test/resources/application.yml
this is my spring datasource config
spring:
datasource:
driver-class-name: org.mariadb.jdbc.Driver
url: ex.com
username: exId
password: exPw
and we know we can use os environment variable for spring datasource config like this
# export SPRING_DARASOURCE_URL=ex.com
But we can not export SPRING_DARASOURCE_DRIVER-CLASS-NAME because of '-' like this
# export SPRING_DARASOURCE_DRIVER-CLASS-NAME=org.mariadb.jdbc.Driver
So if i wanna get spring.datasource.driver-class-name via os environment variable,
what i have to do?
In most cases, any punctuation like those hyphens can be converted to underscores for the system environment variable, e.g. SPRING_DATASOURCE_DRIVER_CLASS_NAME. In some earlier versions of Spring this wasn't exactly standardized yet and some properties might drop the hyphens entirely, e.g. SPRING_DATASOURCE_DRIVERCLASSNAME.
Another approach: set the system env var, JAVA_TOOL_OPTIONS, with any desired Java/JVM options like:
JAVA_TOOL_OPTIONS=-server -Xmx1g -Dspring.datasource.driver-class-name=com.mysql.jdbc.Driver
I am using to configure spring boot with an external YAML configuration and CMD.
-> application.yml file
spring:
profiles: integration-test
datasource:
driverClassName: ${SPRING_DATASOURCE_DRIVER_CLASS_NAME}
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
-> cmd
mvn clean install
-> Result
Caused by: java.lang.IllegalStateException: Cannot load driver class: ${SPRING_DATASOURCE_DRIVER_CLASS_NAME}
Can anyone explain this to me?
When you use the syntax ${}, you are actually telling Spring Boot to use the value of the property whose name is between brackets. In your case, Spring Boot tries to resolve the property SPRING_DATASOURCE_DRIVER_CLASS_NAME. When it fails, it uses the string as is, which leads to the error you mentioned, since no driver exists under the name ${SPRING_DATASOURCE_DRIVER_CLASS_NAME}.
To solve the issue, you can either :
replace the ${} by the real values, e.g. driverClassName: org.postgresql.Driver and do the same for the other properties (url, username and password)
provide properties SPRING_DATASOURCE_DRIVER_CLASS_NAME,SPRING_DATASOURCE_URL and the two others. These can passed in the command line with -D options (e.g. -DSPRING_DATASOURCE_DRIVER_CLASS_NAME=org.postgresql.Driver) or through environment variables. You can look at spring Boot documentation for more details.
Pass those variables in your launch configuration of your program or at commandline when you run your app with java YourMainClass, e.g.
java -DSPRING_DATASOURCE_DRIVER_CLASS_NAME=<full_qualified_name_of_your_jdbc_driver_class> -DSPRING_DATASOURCE_URL=<jdbc_url> YourMainClass
also pass the other two variables the same way, username & password!
your can even set those enviroment variables on OS level, so you don't have to set them each time you start your application...
if your using Spring Boot also have a look at this one: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
I have a password ending in a colon, say abc:, that I want to store encrypted in GIT and decrypt with Spring Cloud Config.
Here's the expected YAML file :
spring:
datasource:
password: "abc:"
Here's the encrypted YAML file :
spring:
datasource:
password: "{cipher}blablabla"
And here's what I receive from Spring Cloud Config after decryption :
spring:
datasource:
password: abc:
Which is interpreted as a key instead of a value by the YAML parser.
Is there a way to tell Spring Cloud Config that I want to surround the decrypted value in quotes or something similar ?
EDIT
My mistake, Spring Could Config server actually adds quotes when needed after decrypting the string. So the result is as expected :
spring:
datasource:
password: 'abc:'
The issue is that when I reference this value using a placeholder the quotes disappear in the process :
a_key:
another_key: ${spring.datasource.password}
becomes when processed by Spring Could Config server :
a_key:
another_key: abc:
So the question really is : how to preserve quotes when referencing a value using placeholders in a YAML file with Spring Cloud Config?
The only way I found so far is to leave the placeholder resolution to runtime by escaping the $ character :
a_key:
another_key: \${spring.datasource.password}
The resulting YAML served by Spring Cloud Config server is then :
a_key:
another_key: ${spring.datasource.password}
Link to Spring Cloud Config documentation here
I have set following in spring boot yaml file. But not working.
I checked the question Set DEFAULT_VIEW_INCLUSION in YAML file. But there they have given answer for new custom objectmapper object, but not using the spring convertor object.
spring:
jackson:
mapper:
DEFAULT_VIEW_INCLUSION: true
Please try the following config:
spring:
jackson:
default-property-inclusion: DEFAULT_VIEW_INCLUSION