commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bugzi...@apache.org
Subject DO NOT REPLY [Bug 35882] New: - [jxpath] Suggested BeanPropertyFactory implementation
Date Tue, 26 Jul 2005 23:46:37 GMT
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG·
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=35882>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND·
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=35882

           Summary: [jxpath] Suggested BeanPropertyFactory implementation
           Product: Commons
           Version: unspecified
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: JXPath
        AssignedTo: commons-dev@jakarta.apache.org
        ReportedBy: kweiner@gmail.com


I ended up writing a somewhat generic implementation of AbstractFactory for the
purpose of on-the-fly object creation of bean properties.  I think that this
implementation is appropriate for inclusion in the JXpath code base so that
others can use it if they'd like to.

Basically, it reduces the need for a lot of if/else statements in the
AbstractFactory.createObject() method by using reflection to determine the type
of the current field as indicated by the name parameter, instantiating that type
and then passing it to a setter method on the parent object.

Here is the code. It requires Java 1.5 at the moment.  Please let me know if
this code would be useful to others and if there is anything I can do to help
clean it up so it matches the project's code conventions.

---

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.apache.commons.jxpath.AbstractFactory;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.Pointer;

/**
 * JXPath factory for objects with JavaBean-style properties.
 * This class assumes that for a given property name,
 * there is a corresponding getter and setter method on the
 * parent class.
 * <p/>
 * For example, if the name is <code>address</code> and the
 * parent class is <code>Employee</code>, then there should be
 * accessor methods on Employee named as follows:<br/>
 * <code>public Address getAddress()</code><br/>
 * <code>public void setAddress(Address address)</code><br/>
 * <p/>
 * If that is the case, then this method would create a new
 * instance of <code>Address</code> and pass it as follows:<br/>
 * <code>employee.setAddress(new Address)</code>.
 *
 * @author Ken Weiner, kweiner@gmail.com
 * @version $Revision: #1 $
 */
public class BeanPropertyFactory extends AbstractFactory {

    @Override
    public boolean createObject(JXPathContext context, Pointer pointer, Object
parent, String name, int index) {
        Object object = makeObject(parent.getClass(), name);
        setObject(parent, object, name);
        return true;
    }

    /**
     * Instantiates an object whose type is the same as
     * the declared type of the field with name
     * <code>fieldName</code>.
     * @param clazz the class containing the field
     * @param fieldName the name of the field
     * @return a new object instance
     */
    private Object makeObject(Class clazz, String fieldName) {
        Object object = null;
        final Field field = findField(clazz, fieldName);
        if (field != null) {
            field.setAccessible(true);
            try {
                object = field.getType().newInstance();
            } catch (Exception e) {
                object = null;
            }
        }
        return object;
    }

    /**
     * Recursively search through a class and its superclasses
     * until a field with name <code>fieldName</code> is found.
     * If not field is found, <code>null</code> is returned.
     * @param clazz the class to start searching
     * @param fieldName the name of the field to find
     * @return the field matching the given fieldName
     */
    private Field findField(Class clazz, String fieldName) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
        } catch (Exception e) {
            field = findField(clazz.getSuperclass(), fieldName);
        }
        return field;
    }

    /**
     * Calls the setter method, which is derived from the name,
     * of the parent object, passing the object as an argument.
     * @param parent the parent object containing a setter method
     * @param object the argument to the setter method
     * @param name the String used to derive the setter method name
     */
    private void setObject(Object parent, Object object, String name) {
        try {
            final String setterMethodName = "set" + getBaseMethodName(name);
            final Class parentClass = parent.getClass();
            final Class objectClass = object.getClass();
            final Method setterMethod = parentClass.getMethod(setterMethodName,
objectClass);
            setterMethod.invoke(parent, object);
        } catch (Exception e) {
            return;
        }
    }

    /**
     * Changes the first character of the name to
     * an uppercase character.
     * @param name the name
     * @return the name with an uppercase first letter
     */
    private String getBaseMethodName(String name) {
        return name.substring(0, 1).toUpperCase() + name.substring(1);
    }
}

-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message