How to define a property of type List<E> in a Spring Bean? - spring

I work with Hybris and in the beans.xml file we can define POJOs to be used in projects.
I want to know how can I define a POJO in Spring with a property of type List where E should be another type I define in my beans.xml.
For example, I want to define a POJO like this:
public class MyPojo{
private String someProperty;
public String getSomeProperty(){
return someProperty;
}
public void setSomeProperty(String someProperty){
this.someProperty = someProperty;
}
}
And another POJO that will contain a list of MyPojo:
public class MyPojoListHolder{
private List<MyPojo> myPojoList;
public List<MyPojo> getMyPojoList(){
return myPojoList;
}
public void setMyPojoList(String myPojoList){
this.myPojoList= myPojoList;
}
}
MyPojo would be defined in my beans.xml as follows:
<bean class="my.package.MyPojo">
<property name="someProperty" type="java.lang.String"></property>
</bean>
I can define MyPojoListHolder like this:
<bean class="my.package.MyPojoListHolder">
<property name="myPojoList" type="java.util.List"></property>
</bean>
But that creates a class with myPojoList defined as a List object, but I'd like it to be defined as List.
How can I achieve this?

You can do, for example, something like:
<property name="genders" type="java.util.List<com.your.package.data.GenderData>"/>
In your example, you would end up with
<bean class="my.package.MyPojoListHolder">
<property name="myPojoList" type="java.util.List<my.package.MyPojo>"></property>
</bean>

Related

instantiate a property with return type form a method

Say I have the following class
public class AbcFactory{
#Autowired
private Builder1 builder1;
#Autowired
private Builder2 builder2;
public Builder<Employee > getBuilder(Employee employee) {
if (employee.isMale(employee)) {
return builder1;
} else {
return builder2;
}
}
How to get the returnType from AbcFactory.getBuilder() as a property to a another bean id .
something i tried looks like this
<property name="builder">
?????
</property>
try,
<bean id="emp" class="com.pack.Employee"/>
<bean id="factory" class="com.pack.AbcFactory">
</bean>
<bean id="result" class="com.pack.Builder"
factory-bean="factory" factory-method="getBuilder">
<constructor-arg ref="emp"/>
</bean>
Aren't you mixing up static configuration (launchtime) with dynamic behavior (runtime). Spring cannot be setup according to a call that did not happen yet.
Or maybe "employee" is a bean itself ? See JavaConfig in that case.

Get the object which failed validation Spring Batch validation

I am having this task to process input .csv, .txt files and store the data into a database. I am using Spring Batch for this purpose. Before dumping the data into database, I have to perform some validation checks on the data. I am using Spring Batch's ValidatingItemProcessor and Hibernate's JSR-303 reference implementation hibernate validator for the same. The code looks something like:
public class Person{
#Pattern(regexp = "someregex")
String name;
#NotNull
String address;
#NotNull
String age;
//getters and setters
}
And then I wrote a validator which looks something like this --
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;
import org.springframework.batch.item.validator.ValidationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.batch.item.validator.Validator;
class MyBeanValidator implements Validator<Person>, InitializingBean{
private javax.validation.Validator validator;
#Override
public void afterPropertiesSet() throws Exception {
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
validator = validatorFactory.usingContext().getValidator();
}
#Override
public void validate(Person person) throws ValidationException {
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(person);
if(constraintViolations.size() > 0) {
generateValidationException(constraintViolations);
}
}
private void generateValidationException(Set<ConstraintViolation<Object>> constraintViolations) {
StringBuilder message = new StringBuilder();
for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
message.append(constraintViolation.getMessage() + "\n");
}
throw new ValidationException(message.toString());
}
And then I have a processor which subclasses Spring Batch's ValidatingItemProcessor.
public class ValidatingPersonItemProcessor extends ValidatingItemProcessor<Person>{
#Override
public Person process(Person person) {
//some code
}
The records that pass validation checks would be passed on to another processor for further processing but the failed ones will be cleaned and then passed on to next processor.
Now I want to catch hold of records which failed validation. My objective is to report all input records that failed validation and clean those records further before I could pass on those records to next processor for further processing. How can I achieve this?
Will the Spring Batch process terminate if validation fails for some input? If yes, how to avoid that? My Processor configuration looks something like :
<batch:chunk reader="personItemReader" writer="personDBWriter" processor="personProcessor"
commit-interval="100" skip-limit="100">
<batch:skippable-exception-classes>
<batch:include class="org.springframework.batch.item.validator.ValidationException"/>
</batch:skippable-exception-classes>
<batch:listeners>
<batch:listener>
<bean
class="org.someorg.poc.batch.listener.PersonSkipListener" />
</batch:listener>
</batch:listeners>
</batch:chunk>
<bean id="personProcessor"
class="org.springframework.batch.item.support.CompositeItemProcessor">
<property name="delegates">
<list>
<ref bean="validatingPersonItemProcessor" />
<ref bean="personVerifierProcessor" />
</list>
</property>
</bean>
<bean id="validatingPersonItemProcessor" class="org.someorg.poc.batch.processor.ValidatingPersonItemProcessor" scope="step">
<property name="validator" ref="myBeanValidator" />
</bean>
<bean id="myBeanValidator" class="org.someorg.poc.batch.validator.MyBeanValidator">
</bean>
<bean id="personVerifierProcessor" class="org.someorg.poc.batch.processor.PersonVerifierProcessor" scope="step"/>
</beans>
I guess your validatingPersonItemProcessor bean has his validator parameter set with your myBeanValidator. So the Exception will be thrown by the processor.
Create your own SkipListener. Here you put the logic on what happens when an item is not validated (writtes to a file, a DB, etc.), in the onSkipInProcess();.
You need to add the ValidationException you throw in <batch:skippable-exception-classes> so they will be caught (and doesn't terminate your batch), and add your SkipListener in the <batch:listeners>, so it will be call when an exception is thrown.
EDIT: Answer to comment.
If your processor is a ValidatingItemProcessor and you set the validator, it should automatically call validate. However if you make your own ValidatingItemProcessor by extending it, you should explicitely call super.process(yourItem); (process() of ValidatingItemProcessor ) to validate your item.

Map property value not getting set correctly in Spring

For my test bean Map property is not being set properly and null value is getting set which i find on debug.
Actually the bean has 3 properties and one of the property is a Map and rest are simple key value pairs.
The problem is that spring is setting 3 properties(from,html) correctly but is not setting the Map property ("to").
Below is the code and the solutions that i have tried. The "to" property of the EmailInfo class is getting set to null.
I have kept the constants in a property file and have used PropertyPlaceholderConfigurer.
I am sure there is no problem with the property file as the "from" property is getting set with the correct value.
<bean id="Info"
class="com.src.framework.EmailInfo"
scope="prototype">
<property name="to">
<!-- <map>
<entry key="DEV" value="${email.dev}" />
</map> -->
<util:map map-class="java.util.HashMap">
<entry key="DEV" value="${email.dev}"/>
</util:map>
</property>
<property name="from" value="${email.sender}" />
<property name="html" value="true" />
</bean>
The EmailInfo class
public class EmailInfo {
private boolean html;
private Map<String, String[]> to;
private String from;
public boolean isHtml() {
return this.html;
}
public void setHtml(boolean argHtml) {
this.html = argHtml;
}
public Map<String, String[]> getTo() {
return this.to;
}
public void setTo(Map<String, String[]> argTo) {
this.to = argTo;
}
public String getFrom() {
return this.from;
}
public void setFrom(String argFrom) {
this.from = argFrom;
}
}
Please provide your suggestions are to what i am doing wrong here and how to rectify it.
Try change signature of your map to Map<String,String> because it looks like you have not proper types in that map that you want to put it in xml.
But when you would like to have working your case with Map<String,String[]> you have change your xml
<util:list id="myList">
<value>foo</value>
<value>bar</value>
</util:list>
<util:map>
<entry key="DEV" value="myList"/>
</util:map>

Programmatic access to properties created by property-placeholder

I'm reading properties file using context:property-placeholder. How can I access them programatically (#Value doesn't work - I don't know property titles at the moment of developing)?
The main problem is I can't change applicationContext.xml file because it's setted up by "parent" framework
ps. It's strange but Environment.getProperty returns null
No you can't. PropertyPlaceholderConfigurer is a BeanFactoryPostProcessor, it is only "alive" during bean creation. When it encounters a ${property} notation, it tries to resolve that against its internal properties, but it does not make these properties available to the container.
That said: similar questions have appeared again and again, the proposed solution is usually to subclass PropertyPlaceHolderConfigurer and make the Properties available to the context manually. Or use a PropertiesFactoryBean
We use the following approach to access properties for our applications
<util:properties id="appProperties" location="classpath:app-config.properties" />
<context:property-placeholder properties-ref="appProperties"/>
Then you have the luxury of just autowiring properties into beans using a qualifier.
#Component
public class PropertyAccessBean {
private Properties properties;
#Autowired
#Qualifier("appProperties")
public void setProperties(Properties properties) {
this.properties = properties;
}
public void doSomething() {
String property = properties.getProperty("code.version");
}
}
If you have more complex properties you can still use ignore-resource-not-found and ignore-unresolvable. We use this approach to externalise some of our application settings.
<util:properties id="appProperties" ignore-resource-not-found="true"
location="classpath:build.properties,classpath:application.properties,
file:/data/override.properties"/>
<context:property-placeholder ignore-unresolvable="true" properties-ref="appProperties"/>
#Value
annotation works on new releases of Spring (tested on v3.2.2)
Here is how it is done:
Map your properties file in spring configuration file
<!--Import Info:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd-->
<context:property-placeholder location="classpath:/app-config.properties" />
Create app-config.properties inside (root) your source folder
my.property=test
my.property2=test2
Create a controller class
#Controller
public class XRDSBuilder
{
#Value("${my.property}")
private String myProperty;
public String getMyProperty() { return myProperty; }
}
Spring will automatically map the content of my.property to your variable inside the controller
Mapping to a list
Property value:
my.list.property=test,test2,test3
Controller class configuration:
#Value("#{'${my.list.property}'.split(',')}")
private List<String> myListProperty;
Advanced mapping
#Component("PropertySplitter")
public class PropertySplitter {
/**
* Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2
*/
public Map<String, String> map(String property) {
return this.map(property, ",");
}
/**
* Example: one.example.property = KEY1:VALUE1.1,VALUE1.2;KEY2:VALUE2.1,VALUE2.2
*/
public Map<String, List<String>> mapOfList(String property) {
Map<String, String> map = this.map(property, ";");
Map<String, List<String>> mapOfList = new HashMap<>();
for (Entry<String, String> entry : map.entrySet()) {
mapOfList.put(entry.getKey(), this.list(entry.getValue()));
}
return mapOfList;
}
/**
* Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4
*/
public List<String> list(String property) {
return this.list(property, ",");
}
/**
* Example: one.example.property = VALUE1.1,VALUE1.2;VALUE2.1,VALUE2.2
*/
public List<List<String>> groupedList(String property) {
List<String> unGroupedList = this.list(property, ";");
List<List<String>> groupedList = new ArrayList<>();
for (String group : unGroupedList) {
groupedList.add(this.list(group));
}
return groupedList;
}
private List<String> list(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property);
}
private Map<String, String> map(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(property);
}
}
Property value:
my.complex.property=test1:value1,test2:value2
Controller class:
#Value("#{PropertySplitter.map('${my.complex.property}')}")
Map<String, String> myComplexProperty;
Spring follows Inversion Of Control approach, this means that we can simply inject particular property into POJO. But there are some cases, when you would like to access property given by name directly from your code - some might see it as anti-pattern - this is palpably true, but lets concentrate on how to do it.
The PropertiesAccessor below provides access to properties loaded by Property Placeholder and encapsulates container specific stuff. It also caches found properties because call on AbstractBeanFactory#resolveEmbeddedValue(String) is not cheap.
#Named
public class PropertiesAccessor {
private final AbstractBeanFactory beanFactory;
private final Map<String,String> cache = new ConcurrentHashMap<>();
#Inject
protected PropertiesAccessor(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public String getProperty(String key) {
if(cache.containsKey(key)){
return cache.get(key);
}
String foundProp = null;
try {
foundProp = beanFactory.resolveEmbeddedValue("${" + key.trim() + "}");
cache.put(key,foundProp);
} catch (IllegalArgumentException ex) {
// ok - property was not found
}
return foundProp;
}
}
Found answer at below site:
http://forum.spring.io/forum/spring-projects/container/106180-programmatic-access-to-properties-defined-for-the-propertyplaceholderconfigurer
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="propertyConfigurer">
<property name="properties" ref="props" />
</bean>
<bean id="props" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="file:C:/CONFIG/settings.properties"/>
</bean>
<util:properties id="prop" location="location of prop file" />
This return java.util.Properties object
In JAVA Code
Properties prop = (Properties) context.getBean("prop");
Now you can access ,
prop.getProperty("key");
This works if you need to scan multiple locations for your properties ...
<bean id="yourProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<array value-type="org.springframework.core.io.Resource">
<value>classpath:yourProperties.properties</value>
<value>file:../conf/yourProperties.properties</value>
<value>file:conf/yourProperties.properties</value>
<value>file:yourProperties.properties</value>
</array>
</property>
<property name="ignoreResourceNotFound" value="true" />
</bean>
<context:property-placeholder properties-ref="yourProperties" ignore-unresolvable="true"/>
And then in your actual classes ...
#Autowired
Properties yourProperties;
Tested using Spring 5.1.4
Create beans for your properties before putting them in property-placeholder to make the properties easy to access in-code.
Ex:
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="resources" value="classpath:META-INF/spring/config.properties" />
</bean>
<context:property-placeholder properties-ref="configProperties" ignore-unresolvable="true"/>
Code:
#Autowired
private PropertiesFactoryBean configProperties;
You can also use #Resource(name="configProperties")
Let's asume that you the properties file defined in that "parent" framework
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:main.properties" />
</bean>
You can use the #Value annotation in this way:
#Value( value = "#{applicationProperties['my.app.property']}" )
private String myProperty;

Spring: Bean property not writable or has an invalid setter method

I'm experimenting with Spring, I'm following the book: Spring: A developer's notebook. I'm getting this error:
"Bean property 'storeName' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?"
.. and I'm quite lost.
I have an ArrayListRentABike class which implements RentABike:
import java.util.*;
public class ArrayListRentABike implements RentABike {
private String storeName;
final List bikes = new ArrayList( );
public ArrayListRentABike( ) { initBikes( ); }
public ArrayListRentABike(String storeName) {
this.storeName = storeName;
initBikes( );
}
public void initBikes( ) {
bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, "Fair"));
bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222", 12, "Excellent"));
bikes.add(new Bike("Trek", "6000", 19, "33333", 12.4, "Fair"));
}
public String toString( ) { return "RentABike: " + storeName; }
public List getBikes( ) { return bikes; }
public Bike getBike(String serialNo) {
Iterator iter = bikes.iterator( );
while(iter.hasNext( )) {
Bike bike = (Bike)iter.next( );
if(serialNo.equals(bike.getSerialNo( ))) return bike;
}
return null;
}
}
And my RentABike-context.xml is this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="rentaBike" class="ArrayListRentABike">
<property name="storeName"><value>"Bruce's Bikes"</value></property>
</bean>
<bean id="commandLineView" class="CommandLineView">
<property name="rentaBike"><ref bean="rentaBike"/></property>
</bean>
</beans>
Any ideas please?
Thanks a lot!
Krt_Malta
You're using setter injection but don't have a setter defined for attribute storeName. Either add a setter/getter for storeName or use constructor injection.
Since you already have a constructor defined that takes storeName as input i'd say change your RentABike-context.xml to the following:
<bean id="rentaBike" class="ArrayListRentABike">
<constructor-arg index="0"><value>Bruce's Bikes</value></constructor-arg>
</bean>
Since the parameter passed to the constructor will initialize the storeName, you can use the constructor-arg element to set the storeName.
<bean id="rentaBike" class="ArrayListRentABike">
<constructor-arg value="Bruce's Bikes"/>
</bean>
The constructor-arg elements allow to pass parameters to the constructor (surprise, surprise) of your spring bean.
This error occurs because of storeName not defined for value solution is in:
<bean id="rentaBike" class="ArrayListRentABike">
<property name="storeName"><value>"Bruce's Bikes"</value></property>
</bean>

Resources