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

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;

Related

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

Spring bind application properties Map<MyEnum, List<CustomObject>>

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;
// ...
}

Spring Annotations - Injecting Map of Objects

Using XML annotation , I am injecting a map using the below config -
<bean id = "customerfactory" class = "com.brightstar.CustomerFactory">
<property name = "getCustomerMap">
<map key-type = "java.lang.String" value-type = "com.brightstar.CustomerImpl">
<entry key = "DEFAULT" value-ref = "getDefaultImpl"></entry>
<entry key = "PERSON" value-ref = "getPersonImpl"></entry>
<entry key = "COMPANY" value-ref = "getCompanyImpl"></entry>
</map>
</property>
</bean>
I have created 3 beans - DefaultImpl , PersonImpl and CompanyImpl. How can I inject these as a map using Spring Annotation?
EDIT: For now , I have performed the below but not sure if it is the recommended approach
private Map<String, CustomerImpl> getCustomerMap ;
#Autowired
private GetDefaultImpl getDefaultImpl;
#Autowired
private GetPersonImpl getPersonImpl;
#Autowired
private GetCompanyImpl getCompanyImpl;
private static final String DEFAULT = "DEFAULT";
private static final String COM = "PERSON";
private static final String SOM = "COMPANY";
#PostConstruct
public void init(){
getCustomerMap = new LinkedHashMap<String,CustomerImpl>();
getCustomerMap.put(DEFAULT, getDefaultImpl);
getCustomerMap.put(PERSON, getPersonImpl);
getCustomerMap.put(COMPANY, getCompanyImpl);
}
1.Inject a Map which contains Objects, (Using Java Config)
You can do like this...
#Configuration
public class MyConfiguration {
#Autowired private WhiteColourHandler whiteColourHandler;
#Bean public Map<ColourEnum, ColourHandler> colourHandlers() {
Map<ColourEnum, ColourHandler> map = new EnumMap<>();
map.put(WHITE, whiteColourHandler);
//put more objects into this map here
return map;
}
}
====================
2.Inject a Map which contains Strings (Using properties file)
You can inject String values into a Map from the properties file using the #Value annotation and SpEL like this.
For example, below property in the properties file.
propertyname={key1:'value1',key2:'value2',....}
In your code,
#Value("#{${propertyname}}")
private Map<String,String> propertyname;
Note: 1.The hashtag as part of the annotation.
2.Values must be quotes, else you will get SpelEvaluationException
Just adding my 2 cents. As far as I understood, you are implementing factory pattern , switching between the implementations at runtime. So, it is code, not a configuration, ideal place for that to be in is code itself, not the properties file. I would go with the first approach that Sundararaj Govindasamy suggested. I don't see any problem in #postConstruct method as well. But I would go with the former as its cleaner.

How to convert map with flat properties (prop1.prop2.prop3) into POJO

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.

JPA persistence.xml

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.

Categories

Resources