All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sql2o.reflection.PojoIntrospector Maven / Gradle / Ivy

There is a newer version: 0.2.6
Show newest version
package org.sql2o.reflection;

import org.sql2o.tools.AbstractCache;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.*;

import static java.beans.Introspector.decapitalize;
import static java.lang.reflect.Modifier.isPrivate;
import static java.lang.reflect.Modifier.isStatic;

/**
 * User: dimzon
 * Date: 4/9/14
 * Time: 1:10 AM
 */

// TODO: move introspection code from PojoMetadata to PojoIntrospector

@SuppressWarnings("UnusedDeclaration")
public class PojoIntrospector {
    private static final AbstractCache, Map, Void> rpCache =
            new AbstractCache, Map, Void>() {
                @Override
                protected Map evaluate(Class key, Void param) {
                    return collectReadableProperties(key);
                }
            };

    private static Map collectReadableProperties(Class cls) {
        Map map = new HashMap();
        List> classList = classInheritanceHierarhy(cls, Object.class);
        for (Class aClass : classList) {
            collectPropertyGetters(map, aClass);
        }
        for (Class aClass : classList) {
            collectReadableFields(map, aClass);
        }
        return Collections.unmodifiableMap(map);
    }

    public static Map readableProperties(Class ofClass) {
        return rpCache.get(ofClass, null);
    }

    private static void collectReadableFields(Map map, Class cls) {
        for (final Field m : cls.getDeclaredFields()) {
            if (isStaticOrPrivate(m)) continue;
            String propName = m.getName();
            if (map.containsKey(propName)) continue;
            Class returnType = m.getType();
            m.setAccessible(true);
            ReadableProperty rp = new ReadableProperty(propName, returnType) {
                @Override
                public Object get(Object instance) throws InvocationTargetException, IllegalAccessException {
                    return m.get(instance);
                }
            };
            map.put(propName, rp);
        }
    }

    private static boolean isStaticOrPrivate(Member m) {
        final int modifiers = m.getModifiers();
        return isStatic(modifiers) || isPrivate(modifiers);
    }

    private static void collectPropertyGetters(Map map, Class cls) {
        for (final Method m : cls.getDeclaredMethods()) {
            if (isStatic(m.getModifiers())) continue;
            if (isPrivate(m.getModifiers())) continue;
            if (0 != m.getParameterTypes().length) continue;
            Class returnType = m.getReturnType();
            if (returnType == Void.TYPE || returnType == Void.class) continue;
            String name = m.getName();
            String propName = null;
            if (name.startsWith("get") && name.length() > 3) {
                propName = decapitalize(name.substring(3));
            } else if (name.startsWith("is") && name.length() > 2 && returnType == Boolean.TYPE) {
                propName = decapitalize(name.substring(2));
            }
            if (propName == null) continue;
            if (map.containsKey(propName)) continue;
            m.setAccessible(true);
            ReadableProperty rp = new ReadableProperty(propName, returnType) {
                @Override
                public Object get(Object instance) throws InvocationTargetException, IllegalAccessException {
                    return m.invoke(instance, (Object[]) null);
                }
            };
            map.put(propName, rp);
        }
    }

    private static List> classInheritanceHierarhy(Class cls, Class stopAt) {
        ArrayList> list = new ArrayList>();
        while (cls != null && cls != stopAt) {
            list.add(cls);
            cls = cls.getSuperclass();
        }
        return list;
    }

    public abstract static class ReadableProperty {
        public final String name;
        public final Class type;

        private ReadableProperty(String name, Class type) {
            this.name = name;
            this.type = type;
        }

        public abstract Object get(Object instance) throws InvocationTargetException, IllegalAccessException;
    }
}