Rewrite a property name in Spring Boot - java

I have a library that has a configuration class with #ConfigurationProperties(prefix ="b") and #ConditionalOnProperty(prefix = "b", name= "c"), in the project where I included this configuration class, the property "b" is nested under a property called "a" instead of being at the root level of the properties.yml, with this the property "b" name is "a.b" and the configuration class will get ignored, the property name needs to be kept "a.b" in the property file, is there a way to tell spring boot to ignore the "a" prefix for the property "b" or to rewrite the property name from "a.b" to "b" after application.yml gets loaded ?

You can (probably, depending on the exact context of the config class you're working with) use YAML anchor and alias to meet this need. YAML anchors are similar to anchors (<a> tags) in HTML; you mark some part of the yaml with an anchor, then refer to it with a reference somewhere else. The reference is an alias to the anchored value.
In your example, assuming the conditional config class is something like this:
#Configuration
#ConditionalOnProperty(prefix = "b", name = "foo")
#ConfigurationProperties(prefix ="b")
#Getter #Setter
public class SO_75435896 {
private String foo;
}
You can have a YAML config like this to populate it:
a.b: &b-alias
foo: bar
b: *b-alias
The anchor name (b-alias in my example) can be whatever you want, there's nothing special about that name I chose.
If you want to read more about YAML anchors, this is a decent explanation. It's part of Bitbucket documentation, but provides a pretty good general-purpose explanation with examples. There are, of course, plenty of other web pages about YAML anchors.

So your configuration class and properties files cannot be adapted. You can rename it at runtime in your application.yml :
BProperties
#ConfigurationProperties(prefix ="b")
public class BProperties {
private String c;
private String d;
}
And this properties file :
my-props-file.properties
a.b.c=value1
a.b.d=value2
You can rename the properties at runtime in your application.yml (define in classpath under src/main/ressources/) :
application.yml
b:
c: ${a.b.c}
d: ${a.b.d}

Related

External properties #configurationProperties style prefix for proprties with not predefined structure

I have some properties, where some initial part is same and remaining is different for all properties.
can have 1 dot (.) 2,3 or more.
I can't use #ConfigurationProperties to loca these with prefix ="com.some.props" because remaining properties are different
com:
some:
props:
prop1:
someProp: value
prop2:
anotherProp:
innerprop: value2
So I created a custom props class and used #Value but I have to write full property path for wach variable.
Is there a way I can apply a prefix for all #Value in a class
#Component (prefix="com.some.props") //Not a valid code, but want something of this sort.
class props {
#Values ("${prop1.someprop}")
String someprop;
#Values ("${prop2.anotherProp.innerProp}")
String somethingElse;
}

Inject values with Spring and YAML with nested properties

I want to inject some values from a YAML to the Spring context.
The structure of the YAML is similar so I did not want to duplicate code, but the Spring startup is failing because it is not being able to inject the value to the placeholder.
Please note my application.properties:
server.port=8084
activeProfile=dev
autoAgents.supplier.id=0
autoAgents.supplier.name=test
autoAgents.supplier.serviceType=REST
autoAgents.supplier.authType=1
autoAgents.supplier.adapter=test
autoAgents.supplier.username=test
autoAgents.supplier.secret=test
autoAgents.supplier.apiPassword=12345
autoAgents.client.id=1
autoAgents.client.name=test
autoAgents.client.serviceType=REST
autoAgents.client.authType=1
autoAgents.client.adapter=
autoAgents.client.username=test
autoAgents.client.secret=test
autoAgents.client.apiPassword=12345
Then I am injecting this values on the YAML, application.yml
activeProfile: ${activeProfile}
autoAgents:
supplier:
isSupplier: true
meta:
id: ${autoAgents.supplier.id}
name: ${autoAgents.supplier.name}
serviceType: ${autoAgents.supplier.serviceType}
authType: ${autoAgents.supplier.authType}
adapter: ${autoAgents.supplier.adapter}
credentials:
username: ${autoAgents.supplier.username}
secret: ${autoAgents.supplier.secret}
apiPassword: ${autoAgents.supplier.apiPassword}
client:
isSupplier: false
meta:
id: ${autoAgents.client.id}
name: ${autoAgents.client.name}
serviceType: ${autoAgents.client.serviceType}
authType: ${autoAgents.client.authType}
adapter: ${autoAgents.client.adapter}
credentials:
username: ${autoAgents.client.username}
secret: ${autoAgents.client.secret}
apiPassword: ${autoAgents.client.apiPassword}
And then I am importing this to a configuration property context:
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties
#Data
public class TwoConnectConfigurationProperties {
private String activeProfile;
#Value("${autoAgents.supplier}")
private AutoAgentDup supplier;
#Value("${autoAgents.client}")
private AutoAgentDup client;
}
But #Value("${autoAgents.supplier}") is not working.
Please advise.
As mentioned earlier it does not make sense to inject values to yaml, you can just create the "application.yaml" with the values directly. And just delete the ".properies" file.
You might want to take a look how to easily inject the properties with common suffix into a bean. Its nicely described here:
https://www.baeldung.com/configuration-properties-in-spring-boot
You will have a bean:
#Configuration
#ConfigurationProperties(prefix = "autoAgents.supplier")
public class AutoAgentSupplierProperties {
private long id;
private String name;
// ... rest of the properies properties
}
You might want the same for the "auto.agent" client.
If you want to avoid code duplication, you can have a bean with the common properties. Extend that class with 2 new classes. One for supplier and one for agent - and annotate those with
#ConfigurationProperties
annotation.
Why you need "nested properties"? If you only want to access them in application, just take values from .properties file and fill them as values to .yml file. E.g.: profile: dev, or
autoAgents:
client:
id: 1
Properties from .yml file can be accessed from code same way as from .properties file.
Your problem is in way how you access properties. When you use "#Configuration properties", you have to specific which one to use (e.g. #ConfigurationProperties("autoAgents.client").

Reg Spring #Entity annotation

I have a class which has the annotation
#Entity(value = "mongo_collection_name", noClassnameStored = true)
public class Class_Name{ .... }
As you see in the above code snippet, the mongo collection name is hard coded. Can I get this value from a properties file or Consul? What should I do in order to read it from properties file or Consul?
You can create a conf file and load them as dynamic properties using annotations Configuration and PropertySource
Follow the steps:
Create a conf file with the property. For example: /path/to/file.conf
collectionName=mongo_collection_name
Create a Configuration class
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.PropertySource
#Configuration
#PropertySource("file:/path/to/file.conf")
class AppProperties {
}
Now you can get the value with annotation Value in either Service class or Application like below
#Value("${collectionName}")
String collectionName
Let me know if you have questions.

How print all spring properties including dependecies?

Here is a question wich offer a solution to print all properties. But in fact it prints all properties from .properties files in application sources, system and environment properties. But it ignore all properties from
additional-spring-configuration-metadata.json
spring-configuration-metadata.json
spring-autoconfigure-metadata.properties
and others from json or properties in project dependecies
any properties which is considered as present in org.springframework.boot.autoconfigure.condition.ConditionalOnProperty annotation, with matchIfMissing key word, like that #ConditionalOnProperty(prefix = "spring.data.solr.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
Even I can not find any variable inside Environment env which points to any of these properties.
So is there a way to print all properties both from current application sources and from imported dependencies/jars, especially which are generated via by annotatios?

How to get the list of properties retrieved in #Value inside my Spring Application

In my application, I have dozen of properties mapped to my bean attributes like that:
#Value("#{props['prop1']}")
private String prop1;
#Value("#{props['prop2']}")
private String prop2;
#Value("#{props['prop3']}")
private String prop3;
In my property file, I always need to define the values:
prop1=value1
prop2=value2
prop3=specific-value
It's heavy because most of the properties are often the same. I would prefer to define default values in my code and then override what I need in my property file. The code can looks like this:
#Value("#{props['prop1'] ?: value1}")
private String prop1;
#Value("#{props['prop2'] ?: value2}")
private String prop2;
#Value("#{props['prop3'] ?: value3}")
private String prop3;
And in my property file, I just change prop3:
prop3=specific-value
This is handy because we have a smaller property file that is easier to maintain. Spring boot can also help more by picking the right property file according to the enabled profile.
Now I have one concern: as a developer, how I can know all the configuration points inside my application? If we are forced to add all the properties to the property file, then we can have the list of supported properties easily. However with an approach where only a few properties are defined, we lose this benefit and it becomes tricky to know what property can be changed.
I'm curious to know how this issue has been already addressed before and how. I would expect to have a utility tool like a maven plugin that can scan my beans, detects inside them the attributes annotated with #Value and prints a table of all properties and their default value defined in the application.

Categories

Resources