There is an object (ObjectA) which has another object inside (ObjectB). There is a Guava TreeBasedTable inside the Object B. This Table has a string as row-key,column-key and another object "ObjectC" as value. This table has been displayed on the jsp using the <s:iterator/> and <s:textfield/> tags and it is being displayed correctly (the "values" inside the <s:textfield/> are correct but the "names" are not).
Now, the problem arises when the <s:textfield/> is modified. How do we capture the modified values inside ObjectC in the action class?
public class ObjectA implements Serializable {
private Integer attr1;
private List<ObjectB> objB;
//...getters and setters....
public class ObjectB implements Serializable {
private Integer attr11;
private Table<String,String,ObjectC> allPFields;
// ...getters and setters....
public class ObjectC implements Serializable {
private Integer attr111;
public String attr112;
// ...getters and setters....
jsp code:
<!-- language: lang-html -->
<s:iterator value="#objB.allPlainFields.row(#rowKey)" var="fieldMap"
status="fieldStatus">
<li><label><s:property value="#fieldMap.key" /></label><span>
<s:textfield name="<NOT SURE>" value="%{#fieldMap.value.attr12}" />
</span></li>
</s:iterator>
A TreeBasedTable in Guava is similar to a map inside a map, I tried doing allPFields[#outerkey][#innerkey].attr112 but, it didn't work.
The object structure when the screen is displayed with existing values in the database
<!-- language: lang-java -->
objA
objBList ArrayList<E> (id=668)
elementData Object[10] (id=7438)
[0] objB (id=7439)
allPFields TreeBasedTable<R,C,V> (id=7443)
backingMap TreeMap<K,V> (id=8116)
cellSet null
columnComparator NaturalOrdering (id=503)
columnKeySet null
columnMap null
factory TreeBasedTable$Factory<C,V> (id=8117)
rowKeySet null
rowKeySet StandardRowSortedTable$RowKeySortedSet (id=8118)
rowMap StandardRowSortedTable$RowSortedMap (id=8119)
rowMap null
values null
And the "allPFields" looks like the following in action:
{OuterKey1=
{InnerKey1=ObjectC[attr111=31, attr112=Hi there],
InnerKey2=ObjectC[attr111=40, attr112=How are you]
}
}
The "allPFields" value above has been picked up from the IDE console.
As I told you in your other question, I've never used Guava TreeBasedTable;
However, according to the Official Guava Documentation, a
TreeBasedTable , which is essentially backed by a TreeMap<R, TreeMap<C, V>>
and the get method is
V get(Object rowKey, Object columnKey)
Returns the value corresponding to the given row and column keys, or null if no such mapping exists.
In Java it would be:
Object value = objA.getObjB().get(listIndex).getAllPlainFields.get(rowKey, columnKey).getAttr112;
value = "new value";
Then in OGNL you could try something (totally untested) like:
<s:textfield value="%{#fieldMap.value.attr12}"
name="objA.objB[#fieldStatus.index].allPlainFields.get(#rowKey, #fieldMap.Key).attr112" />
P.S: BEWARE OF TYPO... you are using allPlainFields and allPFields together... one of them is wrong, make sure that all the notations point to the right variable name.
P.P.S: I don't know your requirements, but this structure seems a little "over-designed" to me... it definitely does not respect the KISS paradigm :)
Related
I'm still new to SpringMVC (and jstl for that matter). I'm trying to populate options in a select from a list of objects. I've found a way to do it using c:forEach, but I keep thinking there HAS to be a way to make the form:options method work.
I've browsed around, and about the closest thing I can find to official documentation on the items attribute is here >> http://static.springsource.org/spring/docs/2.0.x/reference/spring-form.tld.html#spring-form.tld.options
It says the items attribute is for
"The Collection, Map or array of objects used to generate the inner 'option' tags"
My confusion is what kind of Collection, Map, or array of objects it's looking for. What format do they need to be in? Is it looking for a Collection or array of type String specifically? Can I use
List<MyObject>
and if so, what would MyObject have to have in it in order for this to be valid (i.e. methods, variables)?
Currently, when I try to use MyObject, I get an exception that says -
ConverterNotFoundException: No converter found capable of converting from type com.example.MyObject to type java.lang.String
Do I need to make a converter? Where would that go? How would that work? I've googled that error message and haven't really turned up anything specific to what I'm trying to do... (Most are results about Roo)
the MyObject class looks like this:
public class MyObject{
private String company;
private Customer customer;
private Address customerAddress;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Address getCustomerAddress() {
return customerAddress;
}
public void setCustomerAddress(Address customerAddress) {
this.customerAddress = customerAddress;
}
}
and I'm trying to use it as such:
<form:select path="myObjectList">
<form:option value="0"/>
<form:options items="myObjectList" />
</form:select>
Does anyone know specifically what is incorrect about this method? Or, should I be using a
List<String>
to accomplish what I'm doing?
EDIT here's the stack trace >> http://pastebin.com/2c5XBCmG
The Spring Documentation says this about the items attribute of the form:options tag:
The items attribute is typically populated with a collection or array
of item objects. itemValue and itemLabel simply refer to bean
properties of those item objects, if specified; otherwise, the item
objects themselves will be stringified. Alternatively, you may specify
a Map of items, in which case the map keys are interpreted as option
values and the map values correspond to option labels. If itemValue
and/or itemLabel happen to be specified as well, the item value
property will apply to the map key and the item label property will
apply to the map value.
In a nutshell, if you need to use a List of your Custom Beans as the items attribute you need to use also the itemValue and itemLabel attributes. Personally, I'll prefer using Maps -LinkedHashMap instances speciffically- for populating my select tags, but that's a matter of taste.
Adapting an example from the Spring Documentation, your code should look like this:
<form:select path="commandAttribute">
<form:option value="-" label="--Please Select"/>
<form:options items="${countryList}" itemValue="company" itemLabel="company"/>
</form:select>
I'm using the company attribute as both itemValue and itemLabel, but you're free to choose the attributes that fit your requirements.
Usualy I am doing it with spring tag like this :
<springform:select path="myObjectList" id="selected_company">
<springform:option value="0" label="--- Select One ---"></springform:option>
<springform:options items="${myObjectList}" itemValue="company" itemLabel="company"></springform:options>
</springform:select>
don't forget including the namespace declaration :
xmlns:springform="http://www.springframework.org/tags/form"
i am getting error "Object reference not set to an instance of an object." my is here,
public class UserProfession
{
public UserProfession()
{
}
public System.String[] Designation
{
get;
set;
}
}
then i am using it like,
UserProfession.Designation[0] =txt_Search.Text.ToString();
Error i mentioned you hopes for your suggestions .
-Thanks
When you make an assignment to an array property, like this:
UserProfession.Designation[0] =txt_Search.Text.ToString();
what you are actually doing is calling the get section for that property... not the set. This returns the object supported the property... the whole object, and not just the index. Index lookup does not happen until after the object is returned. Once you have that object, accessing an index works in the normal way.
You get this specific exception because you have the expression UserProfession.Designation that should return a reference to an array object, but because you never initialize the array there is nothing there when you then try to find reference the 0th element. At this point the framework discovers that the array (your "object reference") is "not set to an instance of an object"... which is just a fancy way of saying it's null.
In other words, you need to have an already existing array to hold the value you want to assign. That means doing something like this:
Designation = new String[10];
public String[] Designation
{
get;
set;
}
However, notice that we never used the set section? So you can simplify that further, like this:
Designation = new String[10];
public String[] Designation {get;private set;}
This will keep client code from completely swapping an entire array out from under your object, but otherwise will provide the full functionality of an array property. If you provide your own backing store for the array, you could even get rid of the setter entirely with no loss of functionality:
private string[] _designation = new string[10];
public string[] Designation {get {return _designation;} }
But let's add one more wrinkle: your desire to assign the to array before initializing it indicates to me that you likely don't really know how big it will be up front. If that's the case, you probably want a collection of some kind instead of an array. A generic List is a convenient and very compatible replacement for an array. That would look like this:
private List<string> _designation = new List<string>();
public List<string> Designation {get {return _designation;}}
You can still access items in that list by index, just like you would with an array. The only difference you need to worry about right now is how you add new items:
UserProfession.Designation.Add(txt_Search.Text);
Also notice that I removed the .ToString() call. Since your .Text property is almost certainly already a string, calling the .ToString() method is just silly.
You will have to initialize the object, before assigning the value. The initialization should be done just once. I have initialized the array size to ten. You can have your own values here. If you want to resize dynamically, you can use ArrayList
int length = 10;
UserProfession.Designation = new System.String[length];
UserProfession.Designation[0] =txt_Search.Text.ToString();
For more information: http://msdn.microsoft.com/en-us/library/aa287601(v=vs.71).aspx
it must initialize the value before we use because, currently, it is null.
you better add the initialization code in the constructor function.
I have two classes in two separate libraries (one VB, one C#):
Public Class Item
...
Public Overridable ReadOnly Property TotalPrice() As String
Get
Return FormatCurrency(Price + SelectedOptionsTotal())
End Get
End Property
End Class
and
public class DerivedItem : Item {
...
public new Decimal TotalPrice
{
get { return Price + OptionsPrice; }
}
}
As you can see, the DerivedItem.TotalPrice shadows the Item.TotalPrice property. However, when trying to retrieve the DerivedItem.TotalPrice value, I'm still getting the base object's TotalPrice value.
Why is the DerivedItem's property not being returned?
EDIT
I've actually found the problem! I am getting the wrong value in the JSON string being returned via AJAX. It turns out that the TotalPrice is being returned correctly, it's just being overwritten by the shadowed property call being made later in the JSON string. My new question, then, is how to I prevent the shadowed property from being serialized?
(This question has been rescoped here)
It may depend on how you are instantiating the object.
For example:
DerivedItem i = new DerivedItem();
i.TotalPrice();
Will call the shadowed version.
However:
Item i = new DerivedItem();
i.TotalPrice();
Will actually call the base.
Here's a nice explanation.
Of course if at all possible I would avoid shadowing.... :-)
Are you referecing TotalPrice from a reference to the base type?
Item item = new DerivedItem;
string s = item.TotalPrice;
Does setting <NonSerialized()> attribute on the base class property work?
Hello I'd like to ask if you can assign arrays of beans as a form
for example i have a form:
PageForm{
Group[] groupArray;
Group[] getGroupArray(){
return groupArray;
}
void setGroupArray( Group[] groupArray ){
this.groupArray = groupArray;
}
}
Group{
boolean isChecked;
boolean getIsChecked(){
return isChecked;
}
void setIsChecked( boolean ischecked ){
this.isChecked = ischecked;
}
}
id like to access this group array in my jsp.
can i do that using this:
<spring:form>
<spring:checkbox path="groupArray[0].isChecked" />
<spring:checkbox path="groupArray[1].isChecked" />
<spring:checkbox path="groupArray[2].isChecked" />
</spring:form>
What i get is an exception:
org.springframework.beans.NullValueInNestedPathException:
Invalid property 'groupArray[0]' of
bean class [PageForm]: Cannot access
indexed value of property referenced
in indexed property path
'groupArray[0]': returned null
Please help me.
Thanks.
The problem is that Group[] groupArray has not been initialized, so when it goes to the array and looks for the object Group at position 0 it cannot find the Group object.
If you know in advance the number of objects which there can be in the array you can insert as many Group objects as you need in the array groupArray in the constructor of PageForm.
In case you don't know how many object you'll have in the array (because you'll create them from data coming from a form) you'll need to provide a way to create new Group objects when the object has not been instantiated in that position before. I think the easiest way toget this is to change your Group[] array to a List<Group> and use a lazy list like Spring AutoPopulatingList, Apache Commons Collections LazyList or the one provided by the library Guava.
try to change your attribute name maybe myChecked and getter/setter as well
e.g. getChecked and setChecked
I have some objects like the two below
public class SavedSearch {
String title;
ArrayList<SearchParameters> params;
}
public class SearchParameter {
String field;
int operator;
String match;
}
On the JSP page in the input form, I use
<input type="text" name="title">
and when I breakpoint inside the FormController, the SavedSearch object has title filled in.
But the ArrayList is always empty. It's not Spring's fault that it can't read my mind, but how do I indicate that field, operator and match are part of params? I tried naming them paramsField, paramsOperator, paramsMatch but no luck.
I know this is not a hard question, but I'm a bit stumped.
for binding a List you must use special wrapper instead of ArrayList: AutoPopulatingList from Spring or LazyList from Apache Commons Collections.
some examples:
using LazyList
using AutoPopulatingList