Uploaded image for project: 'Commons BeanUtils'
  1. Commons BeanUtils
  2. BEANUTILS-330

DefaultResolver being able to handle parenthesis "(" and ")" in mapped property key names

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Open
    • Major
    • Resolution: Unresolved
    • None
    • 2.0.0
    • Expression Syntax
    • 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().

      Bean.properties
      job[0].param(anotherParam(key))=value
      Bean.java
      // 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:

      MyResolver.java
      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

      Attachments

        Activity

          People

            Unassigned Unassigned
            pierrepost Pierre Post
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:

              Time Tracking

                Estimated:
                Original Estimate - 2h
                2h
                Remaining:
                Remaining Estimate - 2h
                2h
                Logged:
                Time Spent - Not Specified
                Not Specified