Getting subset of application.properties by prefix - java

I have (partly) this application.properties in my Spring Boot app:
spring.main.banner-mode = off
app.set.a = 100
app.set.b = abc
app.set.c
# ...
I want to get injected a Properties object with all keys/values with prefix "app.". Something directly like this:
#Value(value="${app.*}")
private Properties appProperties; // this obviously won´t work

I have not tried with Properties. But this is how you do with a Map.
application.yml:
test:
my-map:
key1: value1
key2: value2
Java:
#Service
#ConfigurationProperties(prefix="test")
public class MyService {
private Map<String, String> myMap = new HashMap<>(); // add getter
}

Related

map of map as Bean injection in springboot configuration?

i usually use springboot to inject Beans and use patterns like
in a application.properties file
platform.accounts.acbot71.name=acbot71
platform.accounts.acbot71.secret=secret1
platform.accounts.acbot72.name=acbot72
platform.accounts.acbot72.secret=secret2
in a springboot configuration file
#ConfigurationProperties(prefix = "platform.accounts")
#Bean
public Map<String, PlatformAccount> platformAccounts() {
return new TreeMap<>();
}
with PlatformAccount as a pojo with classic getters and setters
String name;
String email;
All is ok. But now, i'd like to do an advanced configuration with 'inner' map
for each value of the existing map.
I'd like to build an application properties like..
platform.accounts.acbot71.name=acbot71
platform.accounts.acbot71.secret=secret1
platform.accounts.acbot71.subaccount1.name=sub1
platform.accounts.acbot71.subaccount1.secret=secret1
platform.accounts.acbot71.subaccount2.name=sub2
platform.accounts.acbot71.subaccount2.secret=secret2
platform.accounts.acbot72.name=acbot72
platform.accounts.acbot72.secret=secret2
platform.accounts.acbot72.subaccount1.name=sub1
platform.accounts.acbot72.subaccount1.secret=secret1
Purpose is to inject a second map into each object of type PlatformAccount
(i.e. the value of the first map)
How can i do that ?
any code as example ?
I'd do it in application.yml instead, and tweak the properties to have a subAccounts map.
platform:
accounts:
acbot71:
name: acbot71
secret: secret1
subAccounts:
subaccount1:
name: sub1
secret: secret1
subaccount2:
name: sub2
secret: secret2
acbot72:
name: acbot72
secret: secret2
subAccounts:
subaccount1:
name: sub1
secret: secret1
I guess it would look like this in application.properties...
platform.accounts.acbot71.name=acbot71
platform.accounts.acbot71.secret=secret1
platform.accounts.acbot71.subAccounts.subaccount1.name=sub1
platform.accounts.acbot71.subAccounts.subaccount1.secret=secret1
platform.accounts.acbot71.subAccounts.subaccount2.name=sub2
platform.accounts.acbot71.subAccounts.subaccount2.secret=secret2
platform.accounts.acbot72.name=acbot72
platform.accounts.acbot72.secret=secret2
platform.accounts.acbot72.subAccounts.subaccount1.name=sub1
platform.accounts.acbot72.subAccounts.subaccount1.secret=secret1
And your PlatformAccount class could look like this.
public class PlatformAccount {
private String name;
private String secret;
private Map<String, PlatformAccount> subAccounts;
}
I've never tried anything like this, Spring might freak out about the nested identical class. If it does, you would have to make a SubAccount config class.

How to get child properties from spring config

I have the following configuration:
external:
shop-service:
url: localhost:8080
timeout: 5000
pet-service:
url: localhost:8081
timeout: 10000
user-service:
url: localhost:8082
timeout: 15000
I want to create some config library that will read these properties in every my service. In every service I can have different clients with different values of properties, but all of them have the same structure.
Any ways how I can get a map that will contain client name as a key and object that has url and timeout values, if I know only external property at the beginning and don't know exact client names?
You can create a configuration class which maps your properties into a map.
#Getter
#Configuration
#ConfigurationProperties
public class Properties {
private Map<String, String[]> external = new HashMap<>();
}
In my opinion, you should avoid using String array as value type. Instead of, you should create a POJO to map the url and timeout properties.
#Getter
#Configuration
#ConfigurationProperties
public class Properties {
private Map<String, Data> external = new HashMap<>();
#Getter
#Setter
#ToString
public static class Data {
private long timeout;
private String url;
}
}
Note: the Properties class must have a getter for the map, and the Data properties must have a getter and setter for each attribute.
this is my solution
private static final String BASE_PROPERTY = "clients.";
private static final String DELIMITER = ".";
private final org.springframework.core.env.Environment environment;
public Set<String> getClientNames() {
return Arrays
.stream(((EnumerablePropertySource<?>) ((ConfigurableEnvironment) environment)
.getPropertySources()
.stream()
.filter(OriginTrackedMapPropertySource.class::isInstance)
.findFirst()
.orElseThrow(RuntimeException::new)).getPropertyNames())
.filter(currentValue -> StringUtils.startsWith(currentValue, BASE_PROPERTY))
.map(key -> StringUtils.substringBetween(key, DELIMITER, DELIMITER))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}

Merge property file into application.properties

I have two properties files. Let's say a.properties and b.properties. these file values has been stored in maps created, let say aMap and bMap.
#PropertySource(value={ "classpath:a.properties", "classpath:b.properties"})
Class propFile{
Private Map<String, String> aMap;
Private Map<String, String> bMap;
}
I have to merge these property file into application.properties such that it works same way. Please provide me solution for this.
You will be able to retrieve your properties by annotating your properties class with #Configuration and #ConfigurationProperties:
#Configuration
#ConfigurationProperties(prefix="maps")
public class ConfigProperties {
private Map<String, String> a;
private Map<String, String> b;
// getters and setters
}
The corresponding application.yml would look as follows:
maps:
a:
key:
test1
b:
key:
test2
Or alternatively with an application.properties file:
maps.a.key=test1
maps.b.key=test2

Reading from yaml is showing null values

To read from yaml file i am doing the following
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties("partners")
public class YAMLConfig {
private Map<String,String> partners = new HashMap<>();
public void setPartners(Map<String, String> partners) {
this.partners = partners;
}
public Map<String, String> getPartners() {
return partners;
}
}
yaml file
person2:
name: bbb
addresses:
to: jiang
bit: su
partners:
p1: wallet
p2: wallet
p3: wallet
And in other Java file i am Autowiring to get YamlConfig above
#Service
public class ObjectModificationService {
#Autowired
YAMLConfig yamlConfig;
public JSONObject modify(JSONObject jsonObject ) {
String type = yamlConfig.getPartners().get(partnerName.toLowerCase());
}
}
I am not getting any type above , also checked yamlConfig.getPartners() in debug it is coming as null. I was following this tutorial: https://www.baeldung.com/spring-yaml, but then again IDE is showing error when i put ConfigurationProperties without ConfigurationProperties("partners").
In your yml configuration class, you have the properties annotation set to "partners", this means that the YAMLConfig class will attempt to read the partners section only. The "person2" section will not be read.
To retrieve the dependency injected values, simply call: yamlConfig.getPartners()
Also, be sure that the application.yml is in the resources directory and/or in the same directory as the .jar
you have specified Partners map accepts String values. so, try Map value formatted with quotes ('') in yaml config file
person2:
name: bbb
addresses:
to: jiang
bit: su
partners:
p1: 'wallet'
p2: 'wallet'
p3: 'wallet'

Inject all keys and Values from property file as Map in Spring

Can someone provide some idea to inject all dynamic keys and values from property file and pass it as Map to DBConstants class using Setter Injection with Collection.
Keys are not known in advance and can vary.
// Example Property File that stores all db related details
// db.properties
db.username.admin=root
db.password.admin=password12
db.username.user=admin
db.password.user=password13
DBConstants contains map dbConstants for which all keys and values need to be injected.
Please provide bean definition to inject all keys and values to Map dbConstants.
public class DBConstants {
private Map<String,String> dbConstants;
public Map<String, String> getDbConstants() {
return dbConstants;
}
public void setDbConstants(Map<String, String> dbConstants) {
this.dbConstants = dbConstants;
}
}
You can create PropertiesFactoryBean with your properties file and then inject it with #Resource annotation where you want to use it as a map.
#Bean(name = "myProperties")
public static PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("prop_file_name.properties"));
return bean;
}
Usage:
#Resource(name = "myProperties")
private Map<String, String> myProperties;
you can use #Value.
Properties file:
dbConstants={key1:'value1',key2:'value2'}
Java code:
#Value("#{${dbConstants}}")
private Map<String,String> dbConstants;
you have to give spaces its like
hash.key = {indoor: 'reading', outdoor: 'fishing'}
Read map like below as i mentioned.
#Value("#{${hash.key}}")
private Map<String, String> hobbies;

Categories

Resources