PDA

View Full Version : Very special custom PropertyEditor (PropertyEditorSupport)


dhukas
Jul 18th, 2007, 10:01 AM
Hello,

I would like to write some custom property editor (extending PropertyEditorSupport) which transforms between String[] and long in the following way (by example):

{"1", "4"} <-> (long)5 = 101 in binary notation.

The direction from String[] to long can be done in the following way:


public class TestBinding {

public static void main(String[] args) {
test();
}

public static void test() {
Bean bean = new Bean();
MockHttpServletRequest request = new MockHttpServletRequest();
ServletRequestDataBinder binder = new ServletRequestDataBinder(bean, "command");
binder.registerCustomEditor(Long.TYPE, "bits", new BitBinder());

request.addParameter("bits", "1");
request.addParameter("bits", "4");
request.addParameter("_bits", "1");

binder.bind(request);

System.out.println(bean.getBits()); // 5
}

static class BitBinder extends PropertyEditorSupport {

/**
* @see java.beans.PropertyEditorSupport#setValue(java.lan g.Object)
*/
@Override
public void setValue(Object value) {
if (value instanceof String[]) {
long tmp = 0;
for (String s: ((String[]) value)) {
tmp |= Integer.parseInt(s);
}
super.setValue(Long.valueOf(tmp));
}
}
}

static class Bean {

private long bits;

public long getBits() {
return bits;
}

public void setBits(long bits) {
this.bits = bits;
}
}
}


Unfortunately I'm stuck converting from long to String[] with the very same class (BitBinder) without destroying the working transformation from String[] to long...

Any ideas?

Regards,

Burkhard

Jörg Heinicke
Jul 18th, 2007, 08:21 PM
You have to implement setAsText(String) and getAsText() and you should let setValue(Object) and getValue() untouched.

Jörg

dhukas
Jul 19th, 2007, 04:02 AM
Hello Jörg, thanks for your answer!

Implementing setAsText() instead of setValue() works, but "the other direction" is still not working.

In my JSP I would like to write something like (simplified)

<form:select path="bits" multiple="multiple">
<form:option value="1">one</form:option>
<form:option value="2">two</form:option>
<form:option value="4">four</form:option>
<form:option value="8">eight</form:option>
</form:select>

But if I use

public class BitBinder extends PropertyEditorSupport {

public String getAsText() {
return new String("1,4");
}

public void setAsText(String text) throws IllegalArgumentException {
setValue(new Long(5));
}
}

to simulate getting/setting 101 (in binary notation), options "1" and "4" are not selected in my JSP.

Am I doing something wrong?

Regards,

Burkhard

Jörg Heinicke
Jul 20th, 2007, 01:10 AM
Hmm, String("1,4") is not a String[].

Jörg

dhukas
Jul 20th, 2007, 03:36 AM
Hmm, String("1,4") is not a String[].

;) Of course it's not, but getAsText() has to return a String (not String[]).

Moreover setAsText(String text) is called with "1,4" if the form is submitted with options 'one' and 'four' selected. Therfore "1,4" should be the correct value returned by getAsText() in my opinion...

Regards,

Burkhard

Jörg Heinicke
Jul 21st, 2007, 01:16 AM
getAsText() has to return a String (not String[]).

Stupid me. It was really too late yesterday - and today again :)

Moreover setAsText(String text) is called with "1,4" if the form is submitted with options 'one' and 'four' selected. Therfore "1,4" should be the correct value returned by getAsText() in my opinion...

That's really a tricky one! Spring tries a lot (http://springframework.cvs.sourceforge.net/springframework/spring/src/org/springframework/web/servlet/tags/form/SelectedValueComparator.java?revision=1.11&view=markup) (see isSelected()) to find matches, but it can't handle your case of actually coupled values.

The last (and also called exhaustive) compare it tries is to use the option value and convert it back to an object using the property editor. But obviously it does that one by one (1, 2, 4, etc.), not in combination. It then compares the resulting long with actual Long(5) - and fails in your case. Adding an option 5 should confirm this.

I first had the idea not letting Spring get to exhaustiveCompare() by returning a String[] on PropertyEditor.getValue() - but then you can't convert that one to a Long. You would need a second step. Spring does not support something like chained property editors.

So you are on your own to handle your case. The simplest is probably to add a setter and getter for the String[] on your bean and do the conversion from and to Long in them. An additional setter/getter pair can handle the Long without any conversion.

Jörg

dhukas
Jul 22nd, 2007, 06:02 AM
So you are on your own to handle your case. The simplest is probably to add a setter and getter for the String[] on your bean and do the conversion from and to Long in them. An additional setter/getter pair can handle the Long without any conversion.

Jörg

Yes, actually that's the way I'm doing it, but I thought it would be possible to find a more generic solution (using a PropertyEditor).

Anyway, thanks for your investigation!

Regards,

Burkhard