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

org.deephacks.tools4j.config.internal.core.runtime.ClassIntrospector Maven / Gradle / Ivy

There is a newer version: 0.15.0
Show newest version
package org.deephacks.tools4j.config.internal.core.runtime;

import com.google.common.base.Optional;
import org.deephacks.tools4j.config.Config;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.deephacks.tools4j.config.internal.core.Reflections.*;

public class ClassIntrospector {
    private Class clazz;
    private Map fields;

    public ClassIntrospector(Class clazz) {
        this.clazz = clazz;
        if(Modifier.isFinal(clazz.getModifiers())){
            throw new UnsupportedOperationException(
                    "Class ["+clazz+"] is final. Configurable classes are not allowed to be final since it " +
                            "breaks the API of proxies that extends configurable classes.");
        }
        fields = findFields(clazz);

    }

    /**
     * Get the class name of the class.
     * @return
     */
    public String getName() {
        return clazz.getName();
    }

    public Class getTarget() {
        return clazz;
    }

    /**
     * Get class level annotation for class.
     *
     * @param annotation
     * @return
     */
    public  T getAnnotation(Class annotation) {
        return clazz.getAnnotation(annotation);
    }

    public  List getFieldList(Class clazz) {
        ArrayList wrap = new ArrayList<>();
        for (Field f : fields.values()) {
            if (f.isAnnotationPresent(clazz)) {
                wrap.add(new FieldWrap(f, f.getAnnotation(clazz)));
            }
        }
        return wrap;
    }

    public Collection getFieldList() {
        ArrayList wrap = new ArrayList<>();
        for (Field f : fields.values()) {
            wrap.add(new FieldWrap(f));
        }
        return wrap;
    }

    public  Map getFieldMap(Class clazz) {
        HashMap wrap = new HashMap<>();
        for (Field f : fields.values()) {
            if (f.isAnnotationPresent(clazz)) {
                wrap.put(f.getName(), new FieldWrap(f, f.getAnnotation(clazz)));
            }
        }
        return wrap;
    }



    public static class FieldWrap {
        private Optional annotation;
        private Field field;
        private boolean isCollection = false;
        private boolean isMap = false;
        private Object defaultDeclaringInstance;

        public FieldWrap(Field f, Annotation annotation) {
            this.field = f;
            this.annotation = Optional.of(annotation);
            this.isCollection = Collection.class.isAssignableFrom(f.getType());
            this.isMap = Map.class.isAssignableFrom(f.getType());
        }
        public FieldWrap(Field f) {
            this.field = f;
            Annotation config = f.getAnnotation(Config.class);
            if (config == null) {
                this.annotation = Optional.absent();
            } else {
                this.annotation = Optional.of(config);
            }
            this.isCollection = Collection.class.isAssignableFrom(f.getType());
            this.isMap = Map.class.isAssignableFrom(f.getType());
        }

        public Optional getAnnotation() {
            return annotation;
        }

        public String getFieldName() {
            return field.getName();
        }

        public Class getType() {
            if (!isCollection) {
                return field.getType();
            }
            List> p = getParameterizedType(field);
            if (p.size() == 0) {
                throw new UnsupportedOperationException("Collection of field [" + field
                        + "] does not have parameterized arguments, which is not allowed.");
            }
            return p.get(0);
        }

        public List> getMapParamTypes() {
            if (!isMap) {
                throw new UnsupportedOperationException("Field [" + field + "] is not a map.");
            }
            List> p = getParameterizedType(field);
            if (p.size() == 0) {
                throw new UnsupportedOperationException("Map of field [" + field
                        + "] does not have parameterized arguments, which is not allowed.");
            }
            return p;
        }

        public boolean isCollection() {
            return isCollection;
        }

        public boolean isMap() {
            return isMap;
        }

        public boolean isFinal() {
            return Modifier.isFinal(field.getModifiers());
        }

        public boolean isStatic() {
            return Modifier.isStatic(field.getModifiers());
        }

        public boolean isTransient() {
            return Modifier.isTransient(field.getModifiers());
        }

        public boolean isAnnotationPresent(Class cls) {
            return field.isAnnotationPresent(cls);
        }

        public List getEnums() {
            if (!isCollection) {
                if (field.getType().isEnum()) {
                    List s = new ArrayList<>();
                    for (Object o : field.getType().getEnumConstants()) {
                        s.add(o.toString());
                    }
                    return s;
                } else {
                    return new ArrayList<>();
                }
            }
            List> p = getParameterizedType(field);
            if (p.size() == 0) {
                throw new UnsupportedOperationException("Collection of field [" + field
                        + "] does not have parameterized arguments, which is not allowed.");
            }
            if (p.get(0).isEnum()) {
                List s = new ArrayList<>();
                for (Object o : p.get(0).getEnumConstants()) {
                    s.add(o.toString());
                }
                return s;
            }
            return new ArrayList<>();

        }

        /**
         * Return the raw collection type
         * @return
         */
        public Class getCollRawType() {
            if (!isCollection) {
                throw new UnsupportedOperationException("This field is not a collection.");
            }
            return field.getType();
        }

        /**
         * Return the raw map type
         * @return
         */
        public Class getMapRawType() {
            if (!isMap) {
                throw new UnsupportedOperationException("This field is not a map.");
            }
            return field.getType();
        }

        public Object getDefaultValue() {
            if (defaultDeclaringInstance == null) {
                try {
                    defaultDeclaringInstance = newInstance(field.getDeclaringClass());
                } catch (InstantiationException e) {
                    throw new UnsupportedOperationException("Cannot access default values "
                            + "from fields of class which cannot be constructed.", e);
                } catch (IllegalAccessException e) {
                    throw new UnsupportedOperationException("Cannot access default values "
                            + "from fields of class which cannot be constructed.", e);
                } catch (InvocationTargetException e) {
                    throw new UnsupportedOperationException("Cannot access default values "
                            + "from fields of class which cannot be constructed.", e);
                } catch (NoSuchMethodException e) {
                    throw new UnsupportedOperationException("Cannot access default values "
                            + "from fields of class which cannot be constructed.", e);
                }
            }
            try {

                return field.get(defaultDeclaringInstance);
            } catch (IllegalArgumentException e) {
                throw new UnsupportedOperationException("Cannot access default values "
                        + "from fields of instances which cannot be accessed.", e);

            } catch (IllegalAccessException e) {
                throw new UnsupportedOperationException("Cannot access default values "
                        + "from fields of class which cannot be accessed.", e);
            }
        }

        public Object getStaticValue() {
            try {
                return field.get(null);
            } catch (Exception e) {
                throw new IllegalArgumentException(
                        "Cannot access values from fields that arent static.");
            }
        }

        @SuppressWarnings("unchecked")
        public Collection getDefaultValues() {
            if (!isCollection) {
                throw new UnsupportedOperationException("This field is not a collection.");
            }
            return (Collection) getDefaultValue();
        }

        public Object getValue(Object source) {
            try {
                return field.get(source);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        public void checkNotPublic() {
            if(Modifier.isPublic(field.getModifiers())) {
                throw new UnsupportedOperationException(
                        "Field ["+field+"] is public. Public fields are not allowed since it " +
                                "breaks the API of having cached proxies.");
            }
        }
    }

    public  List getFieldsAnnotatedWith(Class clazz) {
        ArrayList f = new ArrayList<>();
        for (Field field : fields.values()) {
            if (field.isAnnotationPresent(clazz)) {
                f.add(field);
            }
        }
        return f;

    }

}