Spring Boot doesn't override default property by profile property in Map - java

I have a property with an array value that I want to override when a certain profile is active. But instead of replacing the property Spring Boot performs a strange merge of two arrays. It worked fine on Spring Boot version 1.5 but stopped after upgrading to version 2.5.
I have an application.yml that looks like this:
spring.config.use-legacy-processing: true
configuration:
type:
my-type:
... # some configuration properties
my-list: ['first','second','third']
---
spring:
profiles: dev
configuration:
type:
my-type:
... # some configuration properties
my-list: ['fourth']
I am retrieving this configuration as Map and for property my-list when running with dev profile I am getting an array ['fourth','second','third']. It is the default array with the first element replaced by the value from the profile configuration. If I would replace profile array with ['fourth','fifth'] then the result would be ['fourth','fifth','third'].
I tried to disable legacy processing and use spring.active.on-profile it still works the same way.
If I am consuming properties to class instead of Map then everything works fine but the list of properties is not fixed.
Maybe someone knows what could be done about this?

Related

Activate SQL-Logging via Spring Boot and Hibernate via Environment variables (casing problem)

I want to log all SQL-Statements in SpringBoot 2.7.0. In https://www.baeldung.com/sql-logging-spring-boot#2-via-loggers it is done via the following properties:
spring.jpa.properties.hibernate.format_sql: true
logging.level.org.hibernate.SQL: DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder: DEBUG
This works fine as long as I use the .yml-File. But I have to set it via Environment Variables in OpenShift.
Unfornenatly the Docs https://github.com/spring-projects/spring-boot/wiki/Relaxed-Binding-2.0#environment-variables don't say much about the writing of
format_sql (underscore in property)
hibernate.SQL (all uppercase)
sql.BasicBinder (CamelCase in property)
I've tried the following ones, but none of them work:
LOGGING_LEVEL_ORG_HIBERNATE_SQL=DEBUG
LOGGING_LEVEL_ORG_HIBERNATE_TYPE_DESCRIPTOR_SQL_BASICBINDER=TRACE
SPRING_JPA_PROPERTIES_HIBERNATE_FORMAT_SQL=true
Any ideas?
Use name : logging.level.org.hibernate.SQL

Spring Boot doesn't resolve property placeholder in yaml for apring.profiles.active property

I am used to feature that I can refer to another property from within .yml file using ${...}.
So I have Spring Boot v2.3.0.RELEASE and following .yml:
env: dev
spring:
profiles:
active: ${env}
But unfortunately, when running my application i see
The following profiles are active: ${env}
Despite the fact that this placeholder works perfectly in other properties, for example kafka topics i define as
topic: ${env}.topic_name
and i can see in logs that it's resolved properly
Kafka producer topic=dev.topi_name
Seems like spring.profiles.active is some sort of an exception from this rule, but i can't find why. And how can i get the same result (with profile depending on other property variable) as is, without env variables, external keys, setting in code, etc. ?
This problem has been fixed in Spring Boot 2.4.0 as a part of the updated config file processing (more about it in 2.4.0 release notes).
If interested, you can play with the new property spring.config.use-legacy-processing to see the difference in how spring.profiles.active is processed.

Disable Redis AutoConfig in spring boot when testing

I am trying to disable Redis when I am testing with spring boot. I have disabled my configuration but the auto config created a default connection and fails because it can't connect to a non-existent service. For testing I am content to just use a basic in-memory cache or a no-op cache. That doesn't work either. Here is what I have tried:
per this issue I added said configuration to my test app properties
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
But. That gets me a bit further. But ultimately I get a NoSuchBeanDefinitionException redisTemplate - this is because redisReferenceResolver is trying to look that up.
Looking at my debugger right now, the bean it's trying to hydrate is:
org.springframework.data.redis.core.convert.ReferenceResolverImpl which is coming from spring-data-redis:1.8.0.RELEASE which is coming from this dependency: compile('org.springframework.boot:spring-boot-starter-data-redis') . I admit, the bean name is a bit misleading. The type it actually resolves to is not
The only other reference to redis is in our hibernate support.
Can someone explain how to turn this off for testing?
Try excluding this two auto-configuration classes in your test properties file:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
or
exclude
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
and set: spring.data.redis.repositories.enabled=false
With YAML syntax (& Spring Boot):
spring.autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
- org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
If you have SystemEnvironmentPropertySource in you app context you can use environment variable SPRING_AUTOCONFIGURE_EXCLUDE separating items with comma:
SPRING_AUTOCONFIGURE_EXCLUDE=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
Also try #EnableAutoConfiguration(exclude = {...}) on a #TestConfiguration annotated class.
If you dont want to change any files/code, you can also do this with an environment variable:
SPRING_AUTOCONFIGURE_EXCLUDE=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration

Override an application property to undefined/unset

I am not sure if this is a valid question, but I was wondering if this was possible.
A Spring boot project has an application.properties and several profile specific properties. The profile specific properties overrides the defined application.properties with whatever has been defined in the application-profile.properties, and also adds those properties belonging exclusively in the profile specific properties. Illustration below:
application.properties
key1=value1
key2=value2
application-profile.properties
key1=valueProfile1
key3=valueProfile3
When the application starts with this profile, the final properties that it sees are as follows:
key1=valueProfile1
key2=value2
key3=valueProfile3
In short, you have a union of both the common and profile properties, with the profile property values appending and overriding the common.
But what if, in a god-knows-what scenario, i need a property to be defined in the common application.properties but i need it to be "undefined" when the application starts in one particular profile. Illustration below:
application.properties
keySpecial=specialValue
key1=value1
key2=value2
application-special.properties
key1=valueSpecial1
//unset or undefine keySpecial
keyAlternateSpecial=specialAlternateValue
key3=valueSpecial3
Now, when the application starts with this "special" profile, I want it to see the final properties as follows:
keyAlternateSpecial=specialAlternateValue
key1=valueSpecial1
key2=value2
key3=valueSpecial3
Note that keySpecial is not defined, doesnt even exist, when the application runs in this special profile.
Is this possible?
Note: I know that I can refrain from defining "keySpecial" in the common application.properties, and define them in all other profile specific properties. And specify "keyAlternateSpecial" only in "special" profile properties.
More Info:
The scenario that made me wonder about this is the spring boot datasource jndi property. From the docs
spring.datasource.jndi-name= # JNDI location of the datasource. Class, url, username & password are ignored when set.
The mere existence of this property makes the application ignore the other datasource properties (class,url,username,password) even if they are set.
I am not allowed to remove the jndi property from the "application.properties". But instead I wanted to unset/undefine it and add the other datasource properties (class,url,username,password) in a "special" profile properties.
You can fake removing spring.datasource.jndi-name from application.property by setting spring.datasource.jndi-name=false. This way #ConditionalOnProperty(prefix = "spring.datasource", name = "jndi-name") won't enable autoconfiguration class. For details look at ConditionalOnProperty javadoc.
I solved in my use case with by defining the JNDI property in default profile which is activated when no other profiles are defined, in this way during development I can use a different datasources without JNDI.
Here's an excerpt of my application.yml file, don't know if this works for you.
spring:
jpa:
database: POSTGRESQL
hibernate:
ddl-auto: none
# Default profile, active by default on JBoss since no spring profiles are activated
---
spring:
profiles: default
datasource:
jndi-name: java:jboss/datasources/anagraficaDS
# Development configuration
---
spring:
profiles: development
datasource:
platform: postgres
url: jdbc:postgresql://localhost:5432/my-db
username: root
password: secret
driverClassName: org.postgresql.Driver
Late to the party, but:
Since SpringBoot 2.4 a good option would be profile groups.
Put keySpecial=specialValue (and other related config) in its own profile - let's call it special.
Then add it to the profiles it needs to be in. So if you have profiles a, b, and c, and you only need special to be in a and b, then:
spring.profiles.group.profilea[0]=special
spring.profiles.group.profileb[0]=special

Does spring boot support using both properties and yml files at the same time?

I have a spring boot application and I want to use both a yml file for my application properties and also a plain application-${profile}.properties file set to configure my application.
So my question is can this be done and if so, how do you configure spring boot to look for both the yml file and the properties and merge them into one set per environment?
As to why I want/need to use both, it is because I like the flexibility and ease of use of yml files but an internal component (for encryption) requires using the properties file set.
I did see this point being made YAML files can’t be loaded via the #PropertySource annotation
but nothing stating whether both can be used together.
Please provide detailed configuration (XML or Java config) on how to get this working.
TIA,
Scott
I can answer my own question, as it just works as you would expect. The application.yml file and the appropriate application-${profile}.properties both get loaded and merged into the environment. Spring boot just makes this work naturally.
Yes You can use both at same time in same project.
When you use both YML and properties at same time, say for example
application.yml and application.properties at same time in same
project, first application.yml will be loaded, later
application.properties will be loaded.
Important point to be noted is that if application.yml and
application.properties have same keys for example in
application.yml has spring.app.name = testYML and
application.properties has spring.app.name = testProperties at same
time in same project, then application.yml value will be overwritten
by application.properties value since it is loading at last.
And the value in spring.app.name = testProperties.
Yes, you can run both without doing any configuration.
In Spring Boot, it picks .properties or .yaml files in the following sequences :
application-{profile}.{properties|yml}
application.{properties|yml}

Categories

Resources