Details

    • Type: New Feature New Feature
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 1.7.0
    • Fix Version/s: 1.8.0
    • Component/s: Expression Syntax
    • Labels:
      None

      Description

      There are a number of outstanding bugs against the BeanUtils expression syntax with people wanting BeanUtils to support different variations. There is also a duplication of the "expression evaluation" code in various methods which can't be tested in isolation and is difficult to maintain as changes have to be applied uniformly to various places.

      The main places where the code is duplicated:
      PropertyUtilsBean

      • getNestedProperty
      • setNestedProperty
      • getPropertyDescriptor
        BeanUtilsBean
      • copyProperty
      • setProperty

      LocaleBeanUtils has also implemented an alternative mechanism - using a Descriptor object to resolve references. BeanUtils and PropertyUtils also work in slightly different ways. There are also other methods (e.g. PropertyUtilsBean's getIndexedProperty() method) which also have related code.

      I propose to add a new "expression resolver" interface, which would be a singleton and everywhere would delegate to to resolve property expressions. This will allow easy testing as it can be tested in isolation and provide a uniform mechanism accross BeanUtils. It will also allow alternative syntax to be implemented if the resolver implementation can be configured.

      1. BasicResolver.java
        7 kB
        Niall Pemberton
      2. BasicResolverTestCase.java
        8 kB
        Niall Pemberton
      3. Resolver.java
        2 kB
        Niall Pemberton

        Issue Links

          Activity

          Hide
          Niall Pemberton added a comment -

          Great, thanks for taking a look.

          I think I already deprecated the PropertyUtils constants.

          Show
          Niall Pemberton added a comment - Great, thanks for taking a look. I think I already deprecated the PropertyUtils constants.
          Hide
          Henri Yandell added a comment -

          Looks good.

          The constants in PropertyUtils aren't available anymore - do you think anyone uses those?

          Seems that making them available via the Resolver interface would limit the interace, while making them available from DefaultResolver would be largely pointless. So unless people use those properties, I think it's okay to be deprecating and remove them in 2.0.

          Show
          Henri Yandell added a comment - Looks good. The constants in PropertyUtils aren't available anymore - do you think anyone uses those? Seems that making them available via the Resolver interface would limit the interace, while making them available from DefaultResolver would be largely pointless. So unless people use those properties, I think it's okay to be deprecating and remove them in 2.0.
          Hide
          Niall Pemberton added a comment -

          I've added the Resolver, an implementation called DefaultResolver and I've plugged it into BeanUtils and PropertyUtils:

          http://svn.apache.org/viewvc?view=rev&revision=473888

          Show
          Niall Pemberton added a comment - I've added the Resolver, an implementation called DefaultResolver and I've plugged it into BeanUtils and PropertyUtils: http://svn.apache.org/viewvc?view=rev&revision=473888
          Hide
          Niall Pemberton added a comment -

          I'm attaching an example implementation for review. Its not well tested and I haven't done the analysis to ensure that the implementation is backwardly compatible. However it demonstrates the main concept.

          As an example, the PropertyUtilsBean's getNestedPropertyMethod() would (hopefully) look something like the following:

          public Object getNestedProperty(Object bean, String name)
          throws IllegalAccessException, InvocationTargetException,
          NoSuchMethodException {

          if (bean == null)

          { throw new IllegalArgumentException("No bean specified"); }

          if (name == null)

          { throw new IllegalArgumentException("No name specified"); }

          while (true) {
          String next = resolver.next(name);
          String propName = resolver.getName(next);
          String mapKey = resolver.getMapKey(next);
          int index = resolver.getIndex(next);
          if (bean instanceof Map)

          { bean = getPropertyOfMapBean((Map) bean, next); }

          else if (mapKey != null)

          { bean = getMappedProperty(bean, propName, mapKey); }

          else if (index >= 0)

          { bean = getIndexedProperty(bean, propName, index); }

          else

          { bean = getSimpleProperty(bean, propName); }

          if (bean == null)

          { throw new NestedNullException ("Null property value for '" + next + "'"); }

          name = resolver.remove(name);
          if (name == null)

          { return bean; }

          }
          }

          Show
          Niall Pemberton added a comment - I'm attaching an example implementation for review. Its not well tested and I haven't done the analysis to ensure that the implementation is backwardly compatible. However it demonstrates the main concept. As an example, the PropertyUtilsBean's getNestedPropertyMethod() would (hopefully) look something like the following: public Object getNestedProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { if (bean == null) { throw new IllegalArgumentException("No bean specified"); } if (name == null) { throw new IllegalArgumentException("No name specified"); } while (true) { String next = resolver.next(name); String propName = resolver.getName(next); String mapKey = resolver.getMapKey(next); int index = resolver.getIndex(next); if (bean instanceof Map) { bean = getPropertyOfMapBean((Map) bean, next); } else if (mapKey != null) { bean = getMappedProperty(bean, propName, mapKey); } else if (index >= 0) { bean = getIndexedProperty(bean, propName, index); } else { bean = getSimpleProperty(bean, propName); } if (bean == null) { throw new NestedNullException ("Null property value for '" + next + "'"); } name = resolver.remove(name); if (name == null) { return bean; } } }

            People

            • Assignee:
              Niall Pemberton
              Reporter:
              Niall Pemberton
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development