Newsflash

A good friend has spent his lunch time to create a new page header for my new site. You can already see it - I hope you like it.
 
Fun with reflection PDF Print
Written by Matthias Mann   
Setting a property of a object (or even a object graph) can be very useful - especially when used in parsing code. This small class allows very easy access to any getter and setter that can be reached by public getXXX methods.

Ok, lets start with a small usage example. Assume you have the following java code:

obj.getBla().getBlub().setValue(10);

That's easy to write - but what if need to put this in a callbacks - and ofcourse each callback has different code. This will create a lot of class files relatively fast.

So now try to image that you could write the above code as a string - and pass this string as a paramter to your callback class ? Then you have reduce everything down to 2 classes - your callback and a utility class.

Lets take a look at how the above code would look like when using our utility class:

new PropertyAccessor("bla", "blub", "value").setProperty(obj, int.class, 10);

Here I assumed that the setValue() method from above takes an int as a parameter. As you can see it's a bit longer - but you can even change the class of the object without any code changed. Lets create an example callback which uses ourt class:

class MyCallback implements SomeInterface {
    /** the accessor which does all the work */
    final PropertyAccessor accessor;
    public MyCallback (String ... propertyPath) {
        accessor = new PropertyAccessor(propertyPath);
    }
    public void myCallbackMethod(Object dataObject, int parsedValue) {
        accessor.setProperty(dataObject, int.class, parsedValue);
    }
}

Now you can use this callback to set any int property on any object - as long as the object has the getter and setter methods required by the propertyPath.


Now enough with examples - here comes the code:

public class PropertyAccessor {
    private static final Class[] EMPTY_PARAMS = new Class[0];
    private static final Object[] EMPTY_ARGS = new Object[0];
    
    final String[] pathMethods;
    final String getMethod;
    final String setMethod;
    
    /** Creates a new instance of PropertyAccessor
     * If more then one property is specified then the first act as a path.
     * @param path Contains the name of properties as defined by the java beans spec
     */
    public PropertyAccessor(String ... path) {
        int n = path.length - 1;
        
        pathMethods = new String[n];
        for(int i=0 ; i<n ; i++) {
            pathMethods[i] = "get".concat(upcaseFirst(path[i]));
        }
        
        String lastPart = upcaseFirst(path[n]);
        getMethod = "get".concat(lastPart);
        setMethod = "set".concat(lastPart);
    }
    
    /**
     * Sets the property specified by the path of this PropertyAccessor
     * to the given value.
     * @param obj The object where the path starts
     * @param clazz The type of the property (used to select the right setXXX method)
     * @param value The new value of the property
     */
    public<T> void setProperty(Object obj, Class<T> clazz, T value) {
        try {
            obj = getObj(obj);
            Method m = obj.getClass().getMethod(setMethod, clazz);
            m.invoke(obj, value);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
    /**
     * Gets the value of the property specified by the path of this PropertyAccessor.
     * @param obj The object where the path starts
     * @param clazz The type of the property - used to get the right return type
     * @return The value of the property - or null in case of an error
     */
    public<T> T getProperty(Object obj, Class<T> clazz) {
        try {
            obj = getObj(obj);
            Method m = obj.getClass().getMethod(getMethod, EMPTY_PARAMS);
            return clazz.cast(m.invoke(obj, EMPTY_ARGS));
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
    
    private Object getObj(Object obj) throws Exception {
        for(String pathMethod : pathMethods) {
            Method m = obj.getClass().getMethod(pathMethod, EMPTY_PARAMS);
            obj = m.invoke(obj, EMPTY_ARGS);
        }
        return obj;
    }
    
    private static String upcaseFirst(String property) {
        return Character.toUpperCase(property.charAt(0))+property.substring(1);
    }
}

I hope you find this useful. It was fun to write :D

Comments
Add NewSearch
Write comment
Name:
Title:
Security Image

Powered by JoomlaCommentCopyright (C) 2006 Frantisek Hliva. All rights reserved.Homepage: http://cavo.co.nr/

TheSmit - reflection Unregistered | 2006-09-19 01:04:05
Ohhhh! shiny :)
Kevin Glass - Ello Unregistered | 2006-09-19 01:00:56
I like the flexibility of the reflection system, but I prefer the tight simpicity of the hand coded approach.
Last Updated ( Sunday, 17 September 2006 )
 
< Prev
2012 Matthias Mann, www.matthiasmann.de
Joomla! is Free Software released under the GNU/GPL License.