#

Extending Commons-BeanUtils

In some cases it’s usefull to concat the values of BeanProperties when using the BeanUtils from Apaches Commons. I just extended some few functionality to achiev this within the property-identifier itself.

With the help of a simple and weak parser one can use property descriptions like propertyA+' '+propertyB. For example with some Person bean one can write

ExtendedBeanUtil.getProperty(personBean, "lastname+', '+firstname");

The parser supports text within single quotes ' as well as + for concatenation. Also \ within a text can be used to escape values, like\\' to escape a single quote (the first backslash is for the Java parser to escape the second backslash).
Of course such extended property descriptions can only be used for display issues, not for setting values of beans.

package de.keyboardsamurais.narcanti.commons.beans;
 
import org.apache.commons.beanutils.BeanUtils;
 
/**
 * Supports concatenation and stringliterals within property descriptions.
 * 
 * @author M. Serhat Cinar
 */
public class ExtendedBeanUtil {
  public static class Token{
    private boolean aProperty;
    private String value;
 
    public Token(boolean aProperty, String value) {
      this.aProperty = property;
      this.value = value;
    }
 
    public boolean isAProperty() {
      return aProperty;
    }
 
    public void setAProperty(boolean property) {
      aProperty = property;
    }
 
    public String getValue() {
      return value;
    }
 
    public void setValue(String value) {
      this.value = value;
    }
  }
 
  public static class TokenParser{
    private static enum State{Property, Concat, Text, Escape};
    private ArrayList<Token> tokens = new ArrayList<Token>();
 
    public TokenParser(String content){
      State state = State.Property;
      final StringBuilder value = new StringBuilder();
      for (final char c:content.toCharArray()){
        // System.out.println("c: \""+c+"\" cur. state: "+state);
        switch (state){
          case Property:
            // end of a property, change to concatenation
            if (c=='+'){
              // only if there is a property name at all
              if (value.length()>0){
                tokens.add(new Token(true, value.toString()));
                value.delete(0, value.length());
              }
              state = State.Concat;
            }
            // skip whitespaces wihtin property names
            else if (!Character.isWhitespace(c)){
              value.append(c);
            }
            break;
          case Concat:
            // skip double concatenations (++) and whitespaces
            if (c!='+' && !Character.isWhitespace(c)){
              // next comes a text
              if (c=='\''){
                state = State.Text;
              }
              // as this is not a text, it must be a property
              else{
                value.append(c);
                state = State.Property;
              }
            }
            break;
          case Text:
            // escape some character
            if (c=='\\'){
              state = State.Escape;
            }
            // end of a string
            else if (c=='\''){
              // only if it's not empty
              if (value.length()>0){
                tokens.add(new Token(false, value.toString()));
                value.delete(0, value.length());
              }
              state = State.Property;
            }
            // append anything else (incl. whitespaces)
            else{
              value.append(c);
            }
            break;
          case Escape:
            // no matter which character, just append as it has been escaped
            value.append(c);
            state = State.Text;
            break;
        }
      }
      // fini
      if (value.length()>0){
        switch (state){
          case Property:
            tokens.add(new Token(true, value.toString()));
            break;
          case Text:
            tokens.add(new Token(false, value.toString()));
            break;
        }
      }
    }
 
    public List<Token> getTokens(){
      return tokens;
    }
  }
 
  private ExtendedBeanUtil(){}
 
  // this method does the work of buzilding a result string from the property
  public static String getProperty(Object targetBean, String property){
    final TokenParser parser = new TokenParser(property);
    final StringBuilder result = new StringBuilder();
    for (final Token token:parser.getTokens()){
      if (!token.isAProperty()){
        result.append(token.getValue());
      }
      else{
        result.append(BeanUtils.getProperty(targetBean, token.getValue()));
      }
    return result.toString();
  }
}

Leave a Reply »»

Note: All comments are manually approved to avoid spam. So if your comment doesn't appear immediately, that's ok. Have patience, it can take some days until I have the time to approve my comments.