I'm trying to bind application properties to a Map<MyEnum, List<CustomObject>> in Spring.
I'm aware of following bindings for maps:
foo.keyValueMap.EnumKey=value
foo.keyListValueMap.EnumKey=value1,value2
which respectively creates a Map<EnumKey, String> keyValueMap and Map<EnumKey, List<String>> keyListValueMap.
What I try to accomplish is as the titles says, a map Map<MyEnum, List<CustomObject>>, whereCustomObject having multiple properties including a Set.
class CustomObject {
private Set<String> set;
private String property;
// ...
}
Related
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());
}
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
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;
I have following usecase:
I'm having map with properties:
Map <String, String[]> args = new HashMap(){{
put("requester.firstName", "Alice");
put("requester.lastName", "Smith");
put("requester.address", "Glasgow Av");
put("publication.type", "print");
put("publication.subtype", "book");
}};
I need to convert it to this pojo
public class WebRequest{
private Requester requester;
private Publication publication;
}
class Requester{
private String firstName;
private String lastName;
private String address;
}
class Publication{
private String type;
private String subType;
}
Can I use Jackson, to run the conversion? If not, what is the best suitable library for this?
Thanks,
Nadiia
You might be able to use the BeanUtils of apache common. That framework is capable to map from a Map to a bean almost instantly.
Map<String,String> yourMap = new HashMap<String,String>();
yourMap.put("name", "Joan");
yourMap.put("age", "30");
YourBean p = new YourBean();
try {
BeanUtils.populate(p, yourMap);
} catch (Throwable e) {
//do something...
}
What I'm not sure about is whether it automatically recognizes nested objects and corresponding properties but maybe you are able to do this di-visioning manually (by offering 2 maps, etc).
More information can be found here BeanUtils
I found here on StackOverflow excellent solution for my problem. Similar problem,
BeanUtils converting java.util.Map to nested bean
One of the answers was perfect:
You should use Spring's BeanWrapper class. It supports nested properties, and optionally create inner beans for you:
BeanOne one = new BeanOne();
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(one);
wrapper.setAutoGrowNestedPaths(true);
Map<String, Object> map = new HashMap<>();
map.put("fieldOne", "fieldOneValue");
map.put("fieldTwo.fieldOne", "fieldOneValue");
wrapper.setPropertyValues(map);
assertEquals("fieldOneValue", one.getFieldOne());
BeanTwo two = one.getFieldTwo();
assertNotNull(two);
assertEquals("fieldOneValue", two.getFieldOne();
I hope it will help somebody with similar problem.
Is there a way to make the data on the persistence.xml dynamic?
I was thinking of adding a database name property on my properties file, then the tables are created, if not existing.
Is this possible?
I'm using EclipseLink(JPA2.0) and MySQL.
If you use JPA in standalone environment, you can pass additional properties to Persistence.createEntityManagerFactory().
In application server environments you can use datasource obtained from JNDI.
If you are using spring, you can use the spring property-placeholder-configurer mechanism to do so. Just extend your EclipseLink vendor adapter:
public class ExtendedJpaVendorAdapter extends XJpaVendorAdapter {
private Map<String, Object> vendorProperties;
#Override
public Map<String, Object> getJpaPropertyMap() {
Map<String, Object> properties = super.getJpaPropertyMap();
properties.putAll(vendorProperties);
return properties;
}
public Map<String, Object> getVendorProperties() {
return vendorProperties;
}
public void setVendorProperties(Map<String, Object> vendorProperties) {
this.vendorProperties = vendorProperties;
}
}
And then you can configure these in the spring xml file.