Details
-
Improvement
-
Status: Open
-
Major
-
Resolution: Unresolved
-
None
-
None
-
java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode, sharing)
Description
Unfortunately, the new org.apache.commons.beanutils.expression.DefaultResolver class is unable to handle mapped property key names that contain parenthesis "(" and ")". Following properties cause an exception when using BeanUtils.populate().
job[0].param(anotherParam(key))=value
// JavaBean class public class Bean { private List<Job> job; public static class Job { private Map<String, String> param; // appropriate public getters and setters here } // appropriate public getters and setters here }
java.lang.IllegalArgumentException: No bean specified at org.apache.commons.beanutils.PropertyUtilsBean.getPropertyDescriptor(PropertyUtilsBean.java:874) at org.apache.commons.beanutils.BeanUtilsBean.setProperty(BeanUtilsBean.java:933) at org.apache.commons.beanutils.BeanUtilsBean.populate(BeanUtilsBean.java:830) ...
I slightly modified the getKey() and next() methods so that they can handle multiple nested mapped delimiters. Now, when using a BeanUtilsBean instance with a PropertyUtilsBean and my new resolver, the above properties are accepted without exception:
public class MyResolver extends DefaultResolver { // delimiter constants here public String getKey(String expression) { if (expression == null || expression.length() == 0) { return null; } for (int i = 0; i < expression.length(); i++) { char c = expression.charAt(i); if (c == NESTED || c == INDEXED_START) { return null; } else if (c == MAPPED_START) { int end = getMappedEnd(expression, i); if (end < 0) { throw new IllegalArgumentException("Missing End Delimiter"); } return expression.substring(i + 1, end); } } return null; } public String next(String expression) { if (expression == null || expression.length() == 0) { return null; } boolean indexed = false; int mappedCount = 0; for (int i = 0; i < expression.length(); i++) { char c = expression.charAt(i); if (indexed) { if (c == INDEXED_END) { return expression.substring(0, i + 1); } } else if (mappedCount > 0) { if (c == MAPPED_START) { mappedCount++; } else if (c == MAPPED_END) { mappedCount--; if (mappedCount == 0) { return expression.substring(0, i + 1); } } } else { if (c == NESTED) { return expression.substring(0, i); } else if (c == MAPPED_START) { mappedCount++; } else if (c == INDEXED_START) { indexed = true; } } } return expression; } private int getMappedEnd(String expression, int start) { int count = 0; for (int i = start; i < expression.length(); i++) { char c = expression.charAt(i); if (c == MAPPED_START) { count++; } else if (c == MAPPED_END) { count--; if (count == 0) { return i; } } } return -1; } }
If the changes don't affect the other uses of a resolver, I would recommend to adapt DefaultResolver accordingly as nothing forbids to have "(" and ")" in a key name if I correctly understand.
Best regards,
Pierre