I'm sending this parameter to my struts action
cdata[1]=bar
In my action I'm interested in the index and the value.
I defined a getter/setter pair for CDATA as the OGNL documentation suggests:
public void setCdata(int index, String value){
LOG.info("setData; key="+ key +"; value="+ value);
// store index and value;
}
public String getCdata(int index){
return null; // don't really need a setter
}
This is the Exception I get:
2013-04-29 15:38:49,792 [http-apr-8080-exec-3] WARN com.opensymphony.xwork2.util.logging.commons.CommonsLogger.warn(CommonsLogger.java:60) - Error setting expression 'cdata[1]' with value '[Ljava.
lang.String;#4223d2a4'
ognl.OgnlException: target is null for setProperty(null, "1", [Ljava.lang.String;#4223d2a4)
at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:2309)
at ognl.ASTProperty.setValueBody(ASTProperty.java:127)
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220)
at ognl.SimpleNode.setValue(SimpleNode.java:301)
at ognl.ASTChain.setValueBody(ASTChain.java:227)
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220)
at ognl.SimpleNode.setValue(SimpleNode.java:301)
at ognl.Ognl.setValue(Ognl.java:737)
...
If I define a public member variable String[] cdata = new String[1000] I don't see any exception in my log but my setter is not called either. If the member variable is private I get another exception again.
Use the following setup
List<String> cdata = new ArrayList<String>();
public List<String> getCdata() {
return cdata;
}
public void setCdata(final List<String> cdata) {
if (cdata == null) {
this.cdata = new ArrayList<String>();
} else {
this.cdata = cdata;
}
}
submit the values from JSP like cdata[1]=value etc
only requirement is to have the getters/setters. I've tested this Tomcat7 running on java 1.6. You can submit values like cdata[0], cdata[1] likewise
or else you could use a map
private Map<String, String> data = new HashMap<String, String>();
public Map<String, String> getData() {
return data;
}
public void setData(Map<String, String> data) {
this.data = data;
}
JSP can have
<s:form action="indexProperty">
<h3>Test The Map</h3>
<input type="text" name="data['0']"/>
<input type="text" name="data['1']"/>
<s:iterator value="data.entrySet()" var="aData">
<s:property value="#aData.key" />-<s:property value="#aData.value" />
</s:iterator>
<input type="submit" name="submit" value="submit"/>
</s:form>
Gets populated without a issue
My solution (rather an ugly hack):
I made my action class implement ServletRequestAware and in the action iterate over the parameter map from HttpServletRequest, fetch cdata from it and parse it for index and value
I had to change the sent parameter and encode eg cdata[999]=foobar like cdata_999_=foobar because if it looks like an array field struts requires there's a setter/getter for it in the action class.
According to the docs, OGNL provides support for indexing properties of JavaBeans: OGNL Reference Guide:
JavaBeans supports the concept of Indexed properties. Specifically this means that an object has a set of methods that follow the following pattern:
public PropertyType[] getPropertyName();
public void setPropertyName(PropertyType[] anArray);
public PropertyType getPropertyName(int index);
public void setPropertyName(int index, PropertyType value);
You didn't implement all of these methods. Also if you didn't initialize an array, the values could not be set.
You can read more about indexed properties here.
Indexed Properties
An indexed property is an array instead of a single value. In this case, the bean class provides a method for getting and setting the entire array. Here is an example for an int[] property called testGrades:
public int[] getTestGrades() {
return mTestGrades;
}
public void setTestGrades(int[] tg) {
mTestGrades = tg;
}
For indexed properties, the bean class also provides methods for getting and setting a specific element of the array.
public int getTestGrades(int index) {
return mTestGrades[index];
}
public void setTestGrades(int index, int grade) {
mTestGrades[index] = grade;
}
Related
I am trying to get a List of custom object of type linked list into html using Sightly. But I a unable to read them in sightly. Sample Code is pasted below:
Java Bean:
public class MiniNavBean {
private String fPath;
private String activeAttr;
public MiniNavBean(String fPath, String activeAttr){
this.fPath = fPath;
this.activeAttr = activeAttr;
}
public String getFpath() {
return fPath;
}
public void setFpath(String fpath) {
this.fPath = fpath;
}
public String getActiveattr() {
return activeAttr;
}
public void setActiveattr(String activeattr) {
this.activeAttr = activeattr;
}
}
Java class which extends WCMUsePojo:
public class MiniNav extends WCMUsePojo {
private List<MiniNavBean> navList;
MiniNavBean miniNav;
public List<MiniNavBean> getNavList() {
return navList;
}
public void setNavList(List<MiniNavBean> navList) {
this.navList = navList;
}
#Override
public void activate() {
navList = new LinkedList<MiniNavBean>();
fPath = "fpaths";
activeAttr = "activeattrs;"
miniNav = new MiniNavBean(fpath, activeattr);
navList.add(miniNav);
}
}
Html file (Sightly):
<div data-sly-include="/apps/project/components/global.jsp"></div>
<div data-sly-use.mininav="com.components.MiniNav" data-sly-unwrap>
<div data-sly-list.navlist="${mininav.navList}">
<li>
<p>${navlist.fPath}</p>
<p>${navlist.activeAttr}</p>
</li>
</div>
When I am trying to execute the above code, I am able to see the linked list getting instantiated with the data in the java class. However when I am trying to display the values of the list in the front end, sightly is unable to read it.
Since the LinkedList is of CustomObject type(MiniNavBean) I suspect sightly is unable to read it as it doesn't know about this bean because we didn't refer that bean anywhere. Is there a way to fix this using sightly tags and read the data ?
Sightly would loop over Java objects too. I don't think it is issue with Sightly. Looks like your getters are wrong. Change your bean as shown below
public class MiniNavBean {
private String fPath;
private String activeAttr;
public MiniNavBean(String fPath, String activeAttr){
this.fPath = fPath;
this.activeAttr = activeAttr;
}
public String getfPath() {
return fPath;
}
public void setfPath(String fPath) {
this.fPath = fPath;
}
public String getActiveAttr() {
return activeAttr;
}
public void setActiveAttr(String activeAttr) {
this.activeAttr = activeAttr;
}
}
If you do not wish to change the bean, then you can access the getters directly in the Sightly file and check if it is working fine.
<div data-sly-include="/apps/project/components/global.jsp"></div>
<div data-sly-use.mininav="com.components.MiniNav" data-sly-unwrap>
<div data-sly-list.navlist="${mininav.navList}">
<li>
<p>${navlist.getFpath}</p>
<p>${navlist.getActiveattr}</p>
</li>
</div>
EDIT: To explain more based on the comments
You cannot access the fields which are private outside the class and are usually done using the public getter methods. However, in Sightly when you use the field name after the dot operator, you are not accessing the field directly, instead it calls the corresponding getter method based on the Java specification for naming getters / setters. So as per spec, your getters and setters were wrong in the bean due to which it didn't work.
Like I mentioned above, you can change only your bean and your code will work fine. Or you can leave your bean as is and change Sightly code to get things working.
In your example you are neither assigning a value to the navList member of MiniNav nor adding the MiniNavBean instance to it.
Add the following lines to your activate() method:
this.navList = new LinkedList<>();
this.navList.add(navList);
Also, the Java getters and HTL/Sightly accessors are not properly aligned, ie: for getFpath() you should use navlist.fpath
In case you already have those, are you getting any compile or runtime errors from HTL/Sightly?
HTL/Sightly is generally using reflection to lookup properties of objects so it does not care much about their type.
I'm serializing a form and returning JSON like so
var dataForm = JSON.stringify($('#form').serializeObject());
Then in my action class I create a JSON model object using gson.fromJson()
SomeObj so = gson.fromJson(dataForm, SomeObj.class);
In SomeObj I have a String array field
public class SomeObj {
private String[] someField;
public String[] getSomeField() {
return this.someField;
}
public void setSomeField(String[] someField) {
this.someField = someField;
}
}
I have several checkboxes with the name someField. When multiple checkboxes are selected there will be a json array created and correctly mapped on to the model class
So for example
{"someField":["someValue1", "someValue2"]}
The problem is when there is only one checkbox selected the json will look like this
{"someField":"someValue1"}
This will generate the below exception, because it's expecting an array instead of a String
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING
Any ideas how to fix this? someField is not the only value I'm returning. There are also Booleans and Strings that I omitted
I fixed this by adding a hidden field with an empty value. It's not a very elegant solution and should be a better way but it works
<input type="hidden" name="someField" value="">
I have a HashMap which looks pretty much like this..
class MyDTO
{
private Map<Long, StringListWrapper> myMap=new HashMap<>();
private List<Long> keys=new ArrayList<>();
private List<String> values=new ArrayList<>();
// setter and getter methods
}
class StringListWrapper
{
private List<String> st=new ArrayList<>();
// setter and getter methods
}
Now, for the map keys, I have a select which will contain the keys, and a list box which will be used for values.
<select th:field="*{myMap}">
<option th:each="key : *{keys} th:value="${key}" th:text="${key}"></option>
</select>
Here above, keys refer to the keys in MyDTO. I used it to show the keys in the <select>. However, this select must be mapped to the myMap to make sure that the option selected here acts as a key.
<select multiple="multiple">
<option th:each="value : *{values}" th:value="${value}" th:text="${value}"></option>
</select>
Now, also this above multiple select must be mapped to myMap so that the options selected here get into the StringListWrapper.st. Now, how and where to put the th:field attribute for multiple select above?
Thanks in advance. Hope you will reply as soon as possible.
There are a few things unclear about the question, but based on the code, I'm assuming that the myMap property is a Map because you will be providing multiple pairs of these select fields for uses to select the values for some number of keys.
If the assumption above is false, then why have myMap as a Map instead of two different properties/attributes of MyDTO?
Going with my assumption, you'll need the select pairs to be converted into a List or array in MyDTO and have a getter (getMyMap()) that creates a Map based of the list. The entry in the list above would be a simple value object with Long key and List<String> as its properties. Here is an working example of this use case. See how this is transformed by Thymeleaf and you might find a tweaked version that works with your solution.
Also, minor thing: IMHO, I don't believe it's appropriate to have the keys and values properties be within MyDTO, though it might just be simplified for this question only. They should be model attributes instead since they are not user inputs of the form. It technically works but doesn't strictly adhere to separation of concerns.
References/Credits: Dynamic Form Fields - http://www.thymeleaf.org/doc/thymeleafspring.html#dynamic-fields
Spring Controller:
package net.martian111.examples.spring.web;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller
#RequestMapping("/public/stackoverflow/q26181188")
public class StackoverflowQ26181188Controller {
public static class Entry {
private Long id;
private List<String> values;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<String> getValues() {
return values;
}
public void setValues(List<String> values) {
this.values = values;
}
}
public static class FormBackingBean {
List<Entry> entries;
public List<Entry> getEntries() {
return entries;
}
public void setEntries(List<Entry> entries) {
this.entries = entries;
}
public Map<Long, List<String>> getMyMap() {
Map<Long, List<String>> map = new HashMap<>();
for (Entry entry : entries) {
// StringListWrapper constructed from entry.getValues() here...
map.put(entry.getId(), entry.getValues());
}
return map;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
int i = 1;
for (Entry entry : entries) {
sb.append("Pair #" + i + ": ID=" + entry.getId() + ", Values="
+ entry.getValues() + "\n");
++i;
}
return sb.toString();
}
}
// Can be set within the #RequestMapping methods too (mv.addObject())
#ModelAttribute("keys")
public List<Long> getKeys() {
return Arrays.asList(null, 1L, 2L, 3L);
}
#ModelAttribute("values")
public List<String> getValues() {
return Arrays.asList(null, "abc", "def", "ghi");
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView get() {
ModelAndView mv = new ModelAndView("stackoverflow/q26181188");
// Blank Form Backing Bean
FormBackingBean fbb = new FormBackingBean();
fbb.setEntries(Arrays.asList(new Entry(), new Entry(), new Entry(),
new Entry(), new Entry()));
mv.addObject("fbb", fbb);
return mv;
}
#RequestMapping(method = RequestMethod.POST)
public ModelAndView post(FormBackingBean fbb) {
ModelAndView mv = new ModelAndView("stackoverflow/q26181188");
mv.addObject("fbb", fbb);
// Print Form Backing Bean
System.out.println("FBB: \n" + fbb);
// Redisplay submitted from
return mv;
}
}
Thymeleaf Template:
<div th:each="entry,entryStat : *{entries}">
Pair #<span th:text="${entryStat.count}">1</span>
<select th:field="*{entries[__${entryStat.index}__].id}">
<option th:each="key : ${keys}" th:value="${key}" th:text="${key}"></option>
</select>
<select multiple="multiple" th:field="*{entries[__${entryStat.index}__].values}">
<option th:each="value : ${values}" th:value="${value}" th:text="${value}"></option>
</select>
</div>
<button type="submit" name="submit" class="btn btn-primary">Submit</button>
</form>
</body>
</html>
EDIT: Additional details in response to the first comment
Both Map and List properties can be mapped to a collection of HTML form fields. Each Map.Entry or list element is mapped to a single HTML form field, with the name in the form propertyName[index], where index is the integer index of the element for the case of a List, or is the key value of the entry for the case of a Map. The solution above illustrates this for the List case.
To illustrate the Map case, say you want an HTML form to result in a myMap with the following contents:
123L : ["abc", "def"]
234L : ["abc", "ghi"]
Working backwards, the query string (before URL encoding) required for Spring MVC to create the Map above will need to look like: myMap[123]=abc&myMap[123]=def&myMap[234]=abc&myMap[234]=ghi. To get a browser to submit that query string, the HTML form will have to have two multi <select> form elements, one with name="myMap[123]" and the other with name="myMap[234]". However, the name of form elements cannot be set by another form field in standard HTML. In other words, there is no th:field value for the key <select> elements to do this (answering this Stackoverflow question).
With that said, an outside-the-box solution would be client side JavaScript scripting that gathers the necessary data from the form fields and create the required query string to submit the form. It would be a SO different question for a different audience, but I feel that would be an unnecessarily complex and specialized. Also, whereas the solution above works both to generate the HTML view from MyDTO and back to MyDTO from a form submission using the same HTML form, a JavaScript solution will require distinct specialized code for each direction.
I am new to JavaBeans and I need a little help to keep my first little JSF-project going.
I am writing a little web application where a user can search with certain criteria for buildings. So the user enters in the search form 'location', 'property type', 'asking price', 'number of rooms' and 'living space'.
My managed bean accept the requiry with setter/getter and now the data is to be transmitted to a SQL class, where they are processed and matching search results are returned. It sounds simple, but I can not find a solution.
My managed bean looks like this now:
package beans
//import statements
...
#ManagedBean
#RequestScoped
public class PropertySearchBean {
private String _place
private String _propertyType
private double _askingPrice
private int _rooms
private double _livingSpace
public ArrayList<SearchResults> results = new ArrayList<SearchResults>();
// empty constructor
...
// getter and setter for these 5 user inputs
...
public void initializeSearchResults() {
// do the SQL query, recieve search results
// add it as a new object of 'SearchResults'
SQLPropertySearch search = new SQLPropertySearch(_place, _propertyType,
_askingPrice, _rooms, _livingSpace);
ArrayList<Integer> idResults = search.getPropertyIDlist();
SQLProperty property;
if(!idResults.isEmpty()) {
for(int i=0; i<idResults.size(); i++) {
property = new SQLProperty(idResults.get(i));
results.add(new SearchResults(
property.getPropertyID(),
property.getPropertyName(),
// and so on..
));
}
}
}
public static class SearchResults {
int propertyID;
String propertyName;
// and so on..
public SearchResults(int propertyID, String propertyName) {
this.propertyID = propertyID;
this.propertyName = propertyName;
// and so on..
}
// getter and setter
public int getPropertyID() {
return propertyID;
}
public void setPropertyID(int propertyID) {
this.propertyID = propertyID;
}
// and so on..
}
public ArrayList<SearchResults> getResults() {
return results;
}
}
In my XHTML-file I go through each entry of my ArrayList results.
It looks like this:
<ui:repeat var="res" value="#{PropertySearchBean.results}">
<p>#{res.propertyID}</p>
<p>#{res.propertyName}</p>
</ui:repeat>
I don't have an idea how to initialize the ArrayList, because first thing to do is the search itself, with the user input.
I am thankful for any kind of help!
You've removed the getters and setters from your example to improve readability. I'll provide one implementation here to ensure a common understanding (especially regarding the leading underscores).
public String getPlace() {
return _place;
}
public void setPlace(String place) {
this._place = place;
}
The property 'place' will be accessible within your view by using the value binding #{propertySearchBean.place}(see below).
Your code is meant to perform a search. Therefore you'll have to transfer user input from your XHTML file (view) to your managed bean. To do so you need to add a form to your view. Each search query parameter is bound to your bean using a specific value binding. Additionally the form contains a <h:commandButton> tag which finally triggers initialization of the result list.
<h:form>
<h:outputLabel for="place" value="Place:" />
<h:inputText id="place" value="#{propertySearchBean.place}" />
<!-- Additional fields -->
<h:commandButton action="#{propertySearchBean.initializeSearchResults}"
value="Search"/>
</h:form>
Note: You've used the following code in your example
<ui:repeat var="res" value="#{PropertySearchBean.results}">
Make sure that the first letter of your bean name is lower-case (propertySearchBean instead of PropertySearchBean). So this needs to be updated to
<ui:repeat var="res" value="#{propertySearchBean.results}">
There is an object ObjectA which has a list of ObjectB. There is a TreeMap inside the ObjectB. This TreeMap has a String as key and a List of another object ObjectC as value. This TreeMap and the list inside has been displayed on the jsp using the s:iterator and s:textfield and it is being displayed correctly. i.e. the "values" inside the s:textfield are correct. Now, the problem arises when the textfield is modified. How do we capture the modified values inside ObjectC in the action class? With the code given here, the key ("Key1") comes in the action but the value is null.
Java Code
public class ObjectA implements Serializable {
private Integer attr1;
private List<ObjectB> objB;
//...getters and setters....
public class ObjectB implements Serializable {
private Integer attr11;
private TreeMap<String,List<ObjectC>> allPlainFields;
// ...getters and setters....
public class ObjectC implements Serializable {
private Integer attr111;
public String attr112;
// ...getters and setters....
JSP Code
<s:iterator value="objA.objB" var="currentObjB" status="currentGroupStatus">
<s:iterator value="#currentObjB.allPlainFields" var="parentMap" status="headerStatus">
<s:iterator value="#parentMap.value" var="fieldList" status="fieldStatus">
<s:textfield name="objA.objB[%{#currentGroupStatus.index}].allPlainFields['%{#parentMap.key}'][%{#fieldStatus.index}].attr112"/>
</s:iterator>
</s:iterator>
HTML rendered:
<input type="text" id="review-act1_objA_objB_0__allPlainFields_'Key1'__6__attr112" value="Correct Value" name="objA.objB[0].allPlainFields['Key1'][0].attr112">
The object structure in the "VAriables" view of eclipse shows:
objA Object A (id=955)
objB ArrayList<E> (id=966)
elementData Object[10] (id=967)
[0] ObjectB (id=968)
allPlainFields TreeMap<K,V> (id=972)
comparator null
descendingMap null
entrySet TreeMap$EntrySet (id=979)
keySet null
modCount 1
navigableKeySet null
root TreeMap$Entry<K,V> (id=980)
size 1
values null
[1] ObjectB (id=969)
[2] ObjectB (id=970)
[3] ObjectB (id=971)
[4] null
[5] null
[6] null
[7] null
[8] null
[9] null
modCount 4
size 4
****In the Eclipse "Variables" view, the value for allPlainFields is**:** {Key1=}
EDIT(27-Feb-2013):
Tried this but didn't work. The values appear on jsp but when submitted, they don't come in action:
In Action class:
private TreeMap<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>();
//get,set and setting two keys in map "mykey1" and "mykey2"
In ObjectCList class:
private ArrayList<ObjectC> paramMdlList;
//default constructor, get, set
In JSP:
<s:form id="test-map" method="post">
<s:iterator value="testTreeMap" var="pMap" status="hStatus">
<li><label><s:property value="%{#pMap.key}" /></label>
<s:iterator value="%{#pMap.value.paramMdlList}" var="pList" status="innerStatus">
<s:textfield name="testTreeMap['%{#pMap.key}'].paramMdlList[%{#innerStatus.index}].attr111"/>
<s:textfield name="testTreeMap['%{#pMap.key}'].paramMdlList[%{#innerStatus.index}].attr112"/>
</s:iterator>
</li>
</s:iterator>
<s:submit value=" " type='button' id="btnh1" action="saveTreeMap">
<span>Save TreeMap</span>
</s:submit>
</s:form>
When the form is submitted, updateTreeMap method of the action is called. The map is printed as mentioned here :
public String updateTreeMap(){
for (Map.Entry<String, ObjectCList> entry : testTreeMap.entrySet())
{
System.out.println(entry.getKey() + "/" + entry.getValue());
}
return SUCCESS;
}
What is "printed" :
mykey1/
mykey2/
i.e. null values
The screen below shows values coming in jsp
According to your latest update. If you are using TreeMap Struts2 cannot correctly determine type of elements inside it. Change declaration of testTreeMap from TreeMap to Map.
private Map<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>();
Or annotate testTreeMap with com.opensymphony.xwork2.util.Element annotation to tell Struts2 what type are elements inside map.
#Element(value = ObjectCList.class)
private TreeMap<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>();
I've become curious and did other experiments.
I found out that neither Lists inside Lists, nor Maps inside Maps (and all the interpolations), declared as interface (List, Map), or as their implementations (ArrayList, HashMap, TreeMap) are correctly handled by the XWork Converter.
All the test cases have failed.
Maybe it's my fault, if so we really need some OGNL Experts here, because in the whole web there's nothing talking about this.
Then i tried what I was pretty sure that would have worked: encapsulating this informations in custom objects, in pure OOP way.
And it worked :)
Instead of
private ArrayList<ArrayList<String>> outerObjects;
you can use in your Action
private ArrayList<OuterObject> outerObjects;
/* GETTERS AND SETTERS */
public ArrayList<OuterObject> getOuterObjects() {
return outerObjects;
}
public void setOuterObjects(ArrayList<OuterObject> outerObjects) {
this.outerObjects = outerObjects;
}
the OuterObject definition:
/* ELSEWHERE IN YOUR PROJECT... */
public class OuterObject{
private ArrayList<InnerObject> innerObjects;
/* GETTERS AND SETTERS */
public ArrayList<InnerObject> getInnerObjects() {
return innerObjects;
}
public void setInnerObjects(ArrayList<InnerObject> innerObjects) {
this.innerObjects = innerObjects;
}
}
the InnerObject definition:
public class InnerObject{
String innerField;
/* GETTERS AND SETTERS */
public String getInnerField() {
return innerField;
}
public void setInnerField(String innerField) {
this.innerField = innerField;
}
}
the optional execute() method of your Action to test the preset values:
InnerObject innerObj1 = new InnerObject();
innerObj1.setInnerField("Inner Value 1");
ArrayList<InnerObject> innerObjArrayList = new ArrayList<InnerObject>();
innerObjArrayList.add(innerObj1);
OuterObject outerObj1 = new OuterObject();
outerObj1.setInnerObjects(innerObjArrayList);
outerObjects = new ArrayList<OuterObject>();
outerObjects.add(outerObj1);
the JSP:
<s:form>
<s:textfield name="outerObjects[0].innerObjects[0].innerField" />
<s:submit/>
</s:form>
(when iterating, simply use [%{#stat.index}] for Lists and ['%{#stat.index}'] for Maps)
The same solution is applicable for every kind of iterable structure (probably except the Guava stuff that needs the .create() method to be invoked).
Of course this is not handy in every case, in your example you have already a huge structure and this will almost double it, but it works, it's OOP, your OGNL will be clearer (because of names) and however seems to be the only way.
Note: the Classes must be real stand-alone Classes, not Inner Classes, another case where OGNL fails to autowire the objects.
Hope that helps
EDIT
What you need then, is only one more level:
change this:
private TreeMap<String,List<ObjectC>> allPlainFields;
to this
private TreeMap<String,ObjectX> allPlainFields;
and create an ObjectX containing a private field that is a List<ObjectC>.
It will work.