com.px100systems.util.PropertyAccessor.java Source code

Java tutorial

Introduction

Here is the source code for com.px100systems.util.PropertyAccessor.java

Source

/*
 * This file is part of Px100 Data.
 *
 * Px100 Data is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
    
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/
 */
package com.px100systems.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.ReflectionUtils;

/**
 * Bean property accessor. Supports dot-separated nested sub-object properties "x.y.z"
 * 
 * @version 0.3 <br>Copyright (c) 2015 Px100 Systems. All Rights Reserved.<br>
 * @author Alex Rogachevsky
 */
public class PropertyAccessor {
    private List<Method> accessorMethods;
    private List<Method> mutatorMethods;
    private Class<?> lastClass;
    private String lastField;
    private Class<?> lastType;

    @SuppressWarnings("unused")
    public PropertyAccessor(PropertyAccessor copy) {
        accessorMethods = copy.accessorMethods;
        mutatorMethods = copy.mutatorMethods;
        lastClass = copy.lastClass;
        lastField = copy.lastField;
    }

    /**
     * Constructor
     * @param srcClass class
     * @param srcProperty property
     */
    public PropertyAccessor(Class<?> srcClass, String srcProperty) {
        accessorMethods = new ArrayList<Method>();
        mutatorMethods = new ArrayList<Method>();

        String[] properties = srcProperty.split("\\.");
        lastClass = srcClass;
        for (int i = 0; i < properties.length; i++) {
            lastField = properties[i];

            Method getter = ReflectionUtils.findMethod(lastClass, methodName("get", lastField));
            if (getter == null)
                throw new RuntimeException("Couldn't find getter for " + lastField + " in " + lastClass.getName());
            accessorMethods.add(getter);

            Class<?> fieldType = getter.getReturnType();

            if (mutatorMethods != null) {
                Method setter = ReflectionUtils.findMethod(lastClass, methodName("set", lastField), fieldType);
                if (setter != null)
                    mutatorMethods.add(setter);
                else
                    mutatorMethods = null;
            }

            if (i < properties.length - 1)
                lastClass = fieldType;
            else
                lastType = fieldType;
        }
    }

    @SuppressWarnings("unused")
    public Class<?> getLastClass() {
        return lastClass;
    }

    @SuppressWarnings("unused")
    public String getLastField() {
        return lastField;
    }

    @SuppressWarnings("unused")
    public Class<?> getLastType() {
        return lastType;
    }

    @SuppressWarnings("unused")
    public Method getLastAccessor() {
        return accessorMethods.isEmpty() ? null : accessorMethods.get(accessorMethods.size() - 1);
    }

    /**
     * Get the property
     * @param item the bean
     * @return property value
     */
    public Object get(Object item) {
        Object result = null;
        Object o = item;
        for (Method accessor : accessorMethods)
            try {
                o = accessor.invoke(o);
                result = o;
                if (result == null)
                    break;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        return result;
    }

    /**
     * Get property's enclosing (parent) class
     * @param item the bean
     * @return the bean the property is declared in
     */
    public Object getParent(Object item) {
        Object target = item;
        for (int i = 0, n = accessorMethods.size(); i < n - 1; i++)
            try {
                Object subObject = accessorMethods.get(i).invoke(target);
                if (subObject == null) {
                    subObject = accessorMethods.get(i).getReturnType().newInstance();
                    BeanPropertySetter.assignField(target, mutatorMethods.get(i), subObject);
                }
                target = subObject;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        return target;
    }

    /**
     * Set the property
     * @param item the bean
     * @param value property value
     */
    public void set(Object item, Object value) {
        BeanPropertySetter.assignField(getParent(item), mutatorMethods.get(accessorMethods.size() - 1), value);
    }

    @SuppressWarnings("unused")
    public static String findAnnotatedField(Class<?> topClass, Class<? extends Annotation> annotation) {
        for (Class<?> cls = topClass; cls != null; cls = cls.getSuperclass())
            for (Field field : cls.getDeclaredFields())
                if (field.getAnnotation(annotation) != null)
                    return field.getName();
        return null;
    }

    /**
     * Helper method to convert a field "xyz" name into "[prefix]Xyz"
     * @param prefix typically "get" or "set"
     * @param propertyName field name
     * @return the getter/setter name
     */
    public static String methodName(String prefix, String propertyName) {
        return prefix + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
    }
}