Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
471 views
in Technique[技术] by (71.8m points)

java - Combining Mapped properties with Indexed properties in Struts

I'm trying to have a dynamic form and, depending on an attribute type, I would like to display a different input style (textfield, radio buttons, dropdown, checklist, ...).

In order to have the dynamic form, I've set up the ActionForm with a Map.

Map<String, Object> values;
public void setValue(String key, Object value);
public Object getValue(String key);

My problem comes when I try to set up a checklist or multibox. The ActionForm only passes one value, although I would have expected that the String[] would be mapped to the Object argument.

Any idea about how can I solve this?

EDIT: in the JSP:

<input type=checkbox name="value(foo)" />
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I looked into this issue and found out what was happening. The problem is not with Struts but with BeanUtils (which Struts uses for populating the form with the request parameters).

I managed to duplicate this by extracting a (test only) snippet of code from the framework:

public class MyForm {
  // assume this is your Struts ActionForm
  public void setValue(String key, Object val) {
    System.out.println(key + "=" + val);
  }
}

public class Test {
  public static void main(String[] args) 
      throws IllegalAccessException, InvocationTargetException {
    MyForm s = new MyForm();
    Map<String, Object> properties = new HashMap<String, Object>();
    // Your request should be like yourActionUrl?value(foo)=1&value(foo)=2&value(foo)=3 
    // and Struts calls bean utils with something like:
    properties.put("value(foo)", new String[] {"1", "2", "3"});
    BeanUtils.populate(s, properties);
  }
}

When your run this you get printed one value only (just as you desrbibed):

foo=1

The thing is that BeanUtils considers this a mapped property and treats it as such, going for a scalar value for the key. Since your value is an array it just uses the first element:

...
} else if (value instanceof String[]) {
  newValue = getConvertUtils().convert(((String[]) value)[0], type);
...

What you can do is modify your JSP and ActionForm to treat the list of values separately. Example modified:

public class MyForm {
  private Map<String, Object> map = new HashMap<String, Object>();

  public void setValue(String key, Object val) {
    map.put(key, val);
  }

  public void setPlainValue(String[] values) {
    // this is correctly called; now delegate to what you really wanted 
    setValue("foo", values);
  }
}

public class Test {
  public static void main(String[] args) 
      throws IllegalAccessException, InvocationTargetException {
    MyForm s = new MyForm();
    Map<String, Object> properties = new HashMap<String, Object>();
    // Notice the change to your URL..
    // yourActionUrl?plainValue=1&plainValue=2&plainValue=3
    properties.put("plainValue", new String[] {"1", "2", "3"});
    BeanUtils.populate(s, properties);
  }
}

The above means that you use

<input type="..." name="value(foo)" ... />

for all the single elements in your JSP, while for your checkboxes (extending it to multivalue elements in general) you use

<input type="checkbox" name="plainValue" ... />

and you delegate to the map once in your ActionForm.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...