I am not sure if this is a complex problem but as a starting person this seems a bit complex to me. I have an object based on which i need to show some values on the UI and let user select some of them, i need to send data back to another controller when user click on the submit button.Here is the structure of my data object
public class PrsData{
private Map<String, List<PrsCDData>> prsCDData;
}
public class PrsCDData{
private Map<String, Collection<ConfiguredDesignData>> configuredDesignData;
}
public ConfiguredDesignData{
// simple fields
}
I have set the object in model before showing the view like
model.addAttribute("prsData", productData.getPrData());
In the form i have following settings
<form:form method="post" commandName="prsData" action="${addProductToCartAction}" >
<form:hidden path="prsCDData['${prsCDDataMap.key}']
[${status.index}].configuredDesignData['${configuredDesignDataMap.key}']
[${configuredDesignDataStatus.index}].code"/>
<form:hidden path="prsCDData['${prsCDDataMap.key}']
[${status.index}].configuredDesignData['${configuredDesignDataMap.key}']
[${configuredDesignDataStatus.index}].description"/>
</form:form>
This is what i have at AddProductToCartController
public String addToCart(@RequestParam("productCodePost") final String code,
@ModelAttribute("prsData") final PrsData prsData, final Model model,
@RequestParam(value = "qty", required = false, defaultValue = "1") final long qty)
On submitting the form i am getting following exception
org.springframework.beans.NullValueInNestedPathException: Invalid property 'prsCDData[Forced][0]'
of bean class [com.product.data.PrsData]:
Cannot access indexed value of property referenced in indexed property path 'prsCDData[Forced][0]': returned null
It seems like its trying to access the values on this controller while i am trying to send value to that controller and trying to create same object with selected values
Can any one tell me where i am doing wrong and what i need to take care of
Edit
I did some more research and came to know that Spring do not support auto-populating list/map for custom objects and based on the answer i tried to change implementation like
public class PrsData{
private Map<String, List<PrsCDData>> prsCDData;
// lazy init
public PrsData()
{
this.prsCDData = MapUtils.lazyMap(new HashMap<String, List<PrsCDData>>(),
FactoryUtils.instantiateFactory(PrsCDData.class));
}
}
public class PrsCDData{
private Map<String, Collection<ConfiguredDesignData>> configuredDesignData;
public PrsCDData()
{
this.configuredDesignData = MapUtils.lazyMap(new HashMap<String,
List<ConfiguredDesignData>>(),
FactoryUtils.instantiateFactory(ConfiguredDesignData.class));
}
}
but i am getting following exception
org.springframework.beans.InvalidPropertyException:
Invalid property 'prsCDData[Forced][0]' of bean class [com.data.PrsData]:
Property referenced in indexed property path 'prsCDData[Forced][0]'
is neither an array nor a List nor a Set nor a Map;
returned value was [com.data.PrsCDData@6043a24d]
i am not sure which thing i am doing wrong, it seems that either my JSTL expression is not right
Explanation : if in you controller you have @ModelAttribute("user") User user
, and you load a corresponding page that contains <form:form commandName="user">
, an empty User is instantiated.
All its attributes are null, or empty in case of a List or a Map. Moreover, its empty lists/maps have been instantiated with an autogrowing implementation. What does it mean ? Let's say we have an empty autogrowing List<Coconut> coconuts
. If I do coconuts.get(someIndex).setDiameter(50)
, it will work instead of throwing an Exception, because the list auto grows and instantiate a coconut for the given index.
Thanks to this autogrowing, submitting a form with the below input will work like a charm :
<form:input path="coconuts[${someIndex}].diameter" />
Now back to your problem : Spring MVC autogrowing works quite well with a chain of objects, each containing a map/list (see this post). But given your exception, it looks like Spring doesn't autogrow the possible objects contained by the autogrowed list/map. In Map<String, List<PrsCDData>> prsCDData
, the List<PrsCDData>
is a mere empty list with no autogrowing, thus leading to your Exception.
So the solution must use some kind of Apache Common's LazyList or Spring's AutoPopulatingList.
You must implement your own autogrowing map that instantiates a LazyList/AutoPopulatingList for a given index. Do it from scratch or using some kind of Apache Common's LazyMap / MapUtils.lazyMap implementation (so far I have not found a Spring equivalent for LazyMap).
Example of solution, using Apache Commons Collections :
public class PrsData {
private Map<String, List<PrsCDData>> prsCDData;
public PrsData() {
this.prsCDData = MapUtils.lazyMap(new HashMap<String,List<Object>>(), new Factory() {
public Object create() {
return LazyList.decorate(new ArrayList<PrsCDData>(),
FactoryUtils.instantiateFactory(PrsCDData.class));
}
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With