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

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>

Related

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

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>

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.

Spring REST - binding GET parameters to nested objects

I know you can bind get request parameters to a pojo like:
#RequestMapping(value = "/reservation",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public List<Reservation> loadReservations(ReservationCriteria criteria)
return service.loadReservations(criteria);
}
Using a pojo like:
public class ReservationCriteria {
String hotelName;
DateRange reservationDateRange;
//getters-setters omitted
}
With a request: /reservation?hotelName=myHotel
myHotel will be bound to hotelName in ReservationCriteria object.
But how can I bind parameters to the nested object DateRange? Which defined like:
public class DateRange {
Date from;
Date to;
//getters-setters omitted
}
Is there a URL pattern which allows that kind of binding something like:
/reservation?hotelName=myHotel&reservationDateRange={fromDate=14.04.2016,toDate=15.04.2016}
Or do I have to declare seperate request parameters and bind them manually?
#RequestMapping(value = "/reservation",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public List<Reservation> loadReservations(
ReservationCriteria criteria,
#RequestParam Date from,
#RequestParam Date to)
DateRange range = new DateRange();
range.setFrom(from);
range.setTo(to);
criteria.setDateRange(range);
return service.loadReservations(criteria);
}
I would prefer not to modify ReservationCriteria class because it is used in many other projects, which would cause alot of refactoring to be made.
Since at least Spring 4 you can pass in nested objects separated with "." in the url.
In the OP case it would be for query parameters:
?reservationDateRange.from=2019-04-01&reservationDateRange.to=2019-04-03
This assumes that Date can be parsed from the given string. This may not work to an arbitrary level of nesting but I've tested it works with one additional nested object.
When you pass a POJO as container of data, Spring use the name of the properties for build the query string and with the data that you pass build the pojo through an appropriated converter. This works for planar pojo or in other words without nesting, for this purpose you have provide the your converter. for this reason you cold have a think like below:
public class ReservationCriteria {
String hotelName;
Date from;
Date to;
//getters-setters omitted
}
#RequestMapping(value = "/reservation",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public List<Reservation> loadReservations(ReservationCriteria criteria)
return service.loadReservations(criteria);
}
/reservation?hotelName=value&from=val&to=val
in this way you can benefit of standard converter of SpringMVC.
the your attempt to use a sort of json for codificate the inner object didn't work because Spring by default in query string don't understand this presentation you have provide a converter for this purpose.
Update for answer to Ben's comment:
If you want implement a custom Converter you had implements the org.springframework.core.convert.converter.Converter<S, T> and then register the your new Converter on the Spring Conversion Service.
On xml configuration you can use FormattingConversionServiceFactoryBean and register it on mvc namespace like below:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<mvc:annotation-driven conversion-service="conversionService"/>
<context:component-scan base-package="com.springapp.mvc"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<util:list>
<bean class="com.springapp.mvc.DateRangeToStringConverter"/>
<bean class="com.springapp.mvc.StringToDateRangeConverter"/>
</util:list>
</property>
</bean>
</beans>
on java config you can extends WebMvcConfigurerAdapter and add you bena like below:
#Configuration
#EnableWebMvc
public class YourWebConfigurationClass extends WebMvcConfigurerAdapter{
#Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addConverter(yourConverter());
}
...
}
the your converter can be like below:
public class DateRangeToStringConverter implements Converter<DateRange,String> {
#Override
public String convert(DateRange dateRange) {
return Json.createObjectBuilder().add("fromDate",DateFormatData.DATE_FORMAT.format(dateRange.getFrom()))
.add("toDate", DateFormatData.DATE_FORMAT.format(dateRange.getTo()))
.build()
.toString();
}
}
public class StringToDateRangeConverter implements Converter<String,DateRange> {
#Override
public DateRange convert(String dateRange) {
DateRange range = new DateRange();
JsonObject jsonObject = Json.createReader(new StringReader(dateRange)).readObject();
try {
range.setFrom(DateFormatData.DATE_FORMAT.parse(jsonObject.getString("fromDate")));
} catch (ParseException e) {
e.printStackTrace();
}
try {
range.setTo(DateFormatData.DATE_FORMAT.parse(jsonObject.getString("toDate")));
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(range);
return range;
}
}
in this way you can listgening on the url: http://localhost:8080/reservation?hotelName=myHotel&reservationDateRange={"fromDate":"14.04.2016","toDate":"15.04.2016"}
pleas pay attenction on reservation DateRange field because I encoded it like a json.
I hope that it can help you

Bean property 'xxx' is not writable or has an invalid setter method

I have spring web application. I have defined the controller bean which takes the bean of service as property. Also service bean takes the Dao. Dao is tested and working fine. Now the problem with service. Actually i'd make sure about the setters there !
so what is the problem ?
Controller Bean :
<bean id="listTypeController" class="me.web.servlet.controller.ListTypeController">
<property name="typeService" ref="typeService" />
</bean>
Service Bean :
<bean id="typeService"class="me.general.service.impl.TypeServiceImpl">
<property name="genericDao" ref="genericDao" />
<property name="typeDao" ref="typeDao" />
</bean>
Service class:
public class TypeServiceImpl implements TypeService {
private TypeDao typeDao;
private GenericDao genericDao;
public TypeDao getTypeDao() {
return typeDao;
}
public GenericDao getGenericDao() {
return genericDao;
}
public void setTypeDao(TypeDao typeDao) {
this.typeDao = typeDao;
}
public void setGenericDao(GenericDao genericDao) {
this.genericDao = genericDao;
}
}
List Controller:
public class ListTypeController {
public static final String SEARCH_TYPE_FORM_ATTRIBUTE_NAME = "SearchTypeForm";
private TypeService typeService;
#ModelAttributeSEARCH_TYPE_FORM_ATTRIBUTE_NAME)
public SearchTypeForm createForm() {
SearchTypeForm form = new SearchTypeForm();
form.setPageSize(SystemConfiguration.getCurrentConfiguration().getDefaultPageSize());
form.setActive(Boolean.TRUE);
return form;
}
#RequestMapping("/administration/types")
public String listTypes(#ModelAttribute(SEARCH_TYPE_FORM_ATTRIBUTE_NAME) SearchTypeForm form,
Model model) {
Page<Type> all = typeService.findTypes(form);
model.addAttribute("all", all);
return "/master/general/List";
}
public void setTypeServic(TypeService typeService) {
this.typeService = typeService;
}
}
The Error :
Invalid property 'typeService' of bean class
[me.web.servlet.controller.ListTypeController]:
Bean property 'typeService' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?
ListTypeController doesn't have a property of the appropriate type to receive the typeService bean, or else the setter for that property is malformed. Note that if you have some proxying going on and your ListTypeController specifies the type as TypeServiceImpl, then it may be because you should be referring to the bean by its interface type, TypeService. A proxy of your typeService would be a TypeService, but not a TypeServiceImpl.
Update: Based on your new code: setTypeServic should be setTypeService, or else your property name is actually typeServic.
In my case i named my propery as: isMyProperty and is in prefix caused an issue. I had to change the name to myProperty.
In my case it was because I had correct setter and getter but each with different type.
My setter took String and parsed it to target enum type and my getter returned directly the enum.
For some reason Spring (v3) got confused.

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;

Resources