Apache Commons Bean Utils Tutorial


The Bean Utilities component of the Apache Commons subproject offers low-level utility classes that assist in getting and setting property values on Java classes that follow the naming design patterns outlined in the JavaBeans Specification, as well as mechanisms for dynamically defining and accessing bean properties.
We have a JavaBean named “Person” with two fields name and phone.

public class Person {
    private String name;
    private String phone;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }            
}

If we want to set the value to a field and get the value we will create the Person object and we will set the value and get the value in the following way.

/**
 * Creating the Person object
 */
Person person = new Person();

 /**
  * setting the Values.
  */
 person.setName("Codesuggestions");
 person.setPhone("999-999-9999");

 /**
  * getting the Values.
  */
  System.out.println("Person Name is::" + person.getName());
  System.out.println("Person Phone is::" + person.getPhone());

Suppose if we don’t know the field names and we want to set the values and get the values we will use Reflection API and BeanUtils API. Here is the following code.

/**
 * getting the Fields using Reflection API.
 */
 Field[] fields = person.getClass().getDeclaredFields();

 /**
  * Settign the Values..
  */
  for (Field field : fields) {
       System.out.println("Field Name::" + field.getName());
       if (field.getName().equalsIgnoreCase("name")) {
           BeanUtils.setProperty(person, field.getName(), "codesuggestions");
       } else {
          BeanUtils.setProperty(person, field.getName(), "999-999-9999");
       }
   }

  /**
   * gettign the Values..
   */
  for (Field field : fields) {
     String property = BeanUtils.getProperty(person, field.getName());
     System.out.println("Bean Values Using BeanUtils.getProperty()::" + property);
  }

But there is a BUG in BeanUtils API.
Suppose if the Bean is having the Field with name starting with A_** and if we invoke the getter method then the BeanUtils.getProperty() will throw “java.lang.NoSuchMethodException: Unknown property 'A_** on class 'class Person'”.
I am creating the Person Bean with the following two fields.

public class Person {
    private String A_NAME;
    private String AB_NAME;
    public String getA_NAME() {
        return A_NAME;
    }
    public void setA_NAME(String A_NAME) {
        this.A_NAME = A_NAME;
    }
    public String getAB_NAME() {
        return AB_NAME;
    }
    public void setAB_NAME(String AB_NAME) {
        this.AB_NAME = AB_NAME;
    }    
}

If we invoke BeanUtils.getProperty() on this Person Bean with Property “A_NAME” then it will throw “java.lang.NoSuchMethodException: Unknown property 'A_NAME' on class 'class .Person'”.
Here is the following code to test the Exception.

import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.beanutils.BeanUtils;

public class BeanUtils_Issue {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {
            Person person = new Person();
            /**
             * getting the Fields using Reflection API.
             */
            Field[] fields = person.getClass().getDeclaredFields();
            /**
             * Settign the Values..
             */
            for (Field field : fields) {
                System.out.println("Field Name::" + field.getName());
                BeanUtils.setProperty(person, field.getName(), "codesuggestions");
            }
            System.out.println("---"+person.getAB_NAME());
            /**
             * gettign the Values..
             */
            for (Field field : fields) {
                String property = BeanUtils.getProperty(person, field.getName());
                System.out.println("Bean Values Using BeanUtils.getProperty()::" + property);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            Logger.getLogger(BeanUtils_Issue.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

To Resolve this issue use the following code to avoid the Exception.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class BeanIssueUtil {

    /**
     *
     * @param bean
     * @param name
     * @return
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     * @throws NoSuchFieldException
     */
    public static String getProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {

        Method method;

        if (null == bean) {
            throw new NullPointerException("Object Cannot be Null.");
        }
        if (null == name) {
            throw new NullPointerException("Field Name Cannot be Null.");
        }
        method = bean.getClass().getMethod("get" + name.substring(0, 1).toUpperCase() + name.substring(1));

        return (String) method.invoke(bean, (Object[]) null);

    }
    
    /**
     * 
     * @param bean
     * @param name
     * @param value
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException 
     */
    public static void setProperty(Object bean, String name, String value) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        if (null == bean) {
            throw new NullPointerException("Object Cannot be Null.");
        }
        if (null == name) {
            throw new NullPointerException("Field Name Cannot be Null.");
        }
        Class[] parameterTypes = new Class[]{String.class};
        Object[] argumentsList = new Object[]{value};
        Method setterMethod = bean.getClass().getMethod("set" + name.substring(0, 1).toUpperCase() + name.substring(1), parameterTypes);
        setterMethod.invoke(bean, argumentsList);
    }
}

We can call this method to avoid the Exception.

Person person = new Person();

/**
 * getting the Fields using Reflection API.
 */
 Field[] fields = person.getClass().getDeclaredFields();

 /**
  * Settign the Values..
  */
  for (Field field : fields) {
      System.out.println("Field Name::" + field.getName());
      BeanIssueUtil.setProperty(person, field.getName(), "codesuggestions");
  }
  System.out.println("---" + person.getA_NAME());
            
 /**
  * gettign the Values..
  */
  for (Field field : fields) {
     String property = BeanIssueUtil.getProperty(person, field.getName());
     System.out.println("Bean Values Using BeanUtils.getProperty()::" + property);
  }

Then we will get the following output instead of Exception.
Field Name::A_NAME
Field Name::AB_NAME
-A_NAME--codesuggestions
Bean Values Using BeanUtils.getProperty()::codesuggestions
Bean Values Using BeanUtils.getProperty()::codesuggestions.

No comments

Powered by Blogger.