org.unitils.core.reflect.ClassWrapper.java Source code

Java tutorial

Introduction

Here is the source code for org.unitils.core.reflect.ClassWrapper.java

Source

/*
 * Copyright 2013,  Unitils.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.unitils.core.reflect;

import org.unitils.core.UnitilsException;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

import static java.lang.reflect.Modifier.isStatic;
import static java.util.Arrays.asList;
import static org.apache.commons.lang.StringUtils.isBlank;

/**
 * @author Tim Ducheyne
 */
public class ClassWrapper extends TypeWrapper {

    protected Class<?> wrappedClass;

    public ClassWrapper(Class<?> wrappedClass) {
        super(wrappedClass);
        this.wrappedClass = wrappedClass;
    }

    public Class<?> getWrappedClass() {
        return wrappedClass;
    }

    public List<FieldWrapper> getFields() {
        List<FieldWrapper> fields = new ArrayList<FieldWrapper>();
        addFields(wrappedClass, false, fields);
        return fields;
    }

    public List<FieldWrapper> getStaticFields() {
        List<FieldWrapper> fields = new ArrayList<FieldWrapper>();
        addFields(wrappedClass, true, fields);
        return fields;
    }

    public FieldWrapper getField(String name) {
        if (isBlank(name)) {
            throw new UnitilsException("Unable to get field. Name cannot be null or empty.");
        }
        Field field = getSimpleField(name, wrappedClass);
        if (field == null) {
            throw new UnitilsException(
                    "Unable to get field with name '" + name + "'. No such field exists on class "
                            + wrappedClass.getName() + " or one of its superclasses.");
        }
        return new FieldWrapper(field);
    }

    public List<FieldWrapper> getFields(List<String> names) {
        List<FieldWrapper> fieldWrappers = new ArrayList<FieldWrapper>();
        for (String name : names) {
            FieldWrapper fieldWrapper = getField(name);
            fieldWrappers.add(fieldWrapper);
        }
        return fieldWrappers;
    }

    public CompositeFieldWrapper getCompositeField(String property) {
        if (isBlank(property)) {
            throw new UnitilsException("Unable to get field. Property cannot be null or empty.");
        }
        List<Field> fields = new ArrayList<Field>();
        String[] names = property.split("\\.", -1);

        Class<?> currentClass = wrappedClass;
        for (String name : names) {
            if (isBlank(name)) {
                throw new UnitilsException("Invalid property expression '" + property
                        + "'. Make sure the expression follows following pattern: field1(.field2.(field3)).");
            }
            Field field = getSimpleField(name, currentClass);
            if (field == null) {
                throw new UnitilsException("Unable to get field for property '" + property + "'. Field with name '"
                        + name + "' does not exist on class " + currentClass.getName()
                        + " or one of its superclasses.");
            }
            fields.add(field);
            currentClass = field.getType();
        }
        return new CompositeFieldWrapper(fields);
    }

    /**
     * Gets the non-static fields in this class or superclass that have the exact given type.
     *
     * @param type The type, not null
     * @return The fields, empty if none found
     */
    public List<FieldWrapper> getFieldsOfType(Type type) {
        if (type == null) {
            throw new UnitilsException("Unable to get fields of type. Type cannot be null.");
        }
        List<FieldWrapper> fields = getFields();
        return getFieldsOfType(type, fields);
    }

    /**
     * Gets the static fields in this class or superclass that have the exact given type.
     *
     * @param type The type, not null
     * @return The fields, empty if none found
     */
    public List<FieldWrapper> getStaticFieldsOfType(Type type) {
        if (type == null) {
            throw new UnitilsException("Unable to get static fields of type. Type cannot be null.");
        }
        List<FieldWrapper> fields = getStaticFields();
        return getFieldsOfType(type, fields);
    }

    /**
     * Gets the non-static fields in this class or superclass that have a type that is assignable from the given type.
     *
     * @param type The type, not null
     * @return The fields, empty if none found
     */
    public List<FieldWrapper> getFieldsAssignableFrom(Type type) {
        if (type == null) {
            throw new UnitilsException("Unable to get fields assignable from type. Type cannot be null.");
        }
        List<FieldWrapper> fields = getFields();
        return getFieldsAssignableFrom(type, fields);
    }

    /**
     * Gets the static fields in this class or superclass that have a type that is assignable from the given type.
     *
     * @param type The type, not null
     * @return The fields, empty if none found
     */
    public List<FieldWrapper> getStaticFieldsAssignableFrom(Type type) {
        if (type == null) {
            throw new UnitilsException("Unable to get static fields assignable from type. Type cannot be null.");
        }
        List<FieldWrapper> fields = getStaticFields();
        return getFieldsAssignableFrom(type, fields);
    }

    // note: gets all methods => overridden methods are returned twice
    public List<Method> getMethods() {
        List<Method> methods = new ArrayList<Method>();
        addMethods(wrappedClass, methods);
        return methods;
    }

    @SuppressWarnings("unchecked")
    public <A extends Annotation> List<A> getAnnotations(Class<A> annotationClass) {
        List<A> result = new ArrayList<A>(3);

        List<Annotation> annotations = getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation.annotationType().equals(annotationClass)) {
                result.add((A) annotation);
            }
        }
        return result;
    }

    public List<Annotation> getAnnotations() {
        List<Annotation> annotations = new ArrayList<Annotation>(3);
        addAnnotations(wrappedClass, annotations);
        return annotations;
    }

    public <A extends Annotation> boolean hasAnnotation(Class<A> annotationClass) {
        List<Annotation> annotations = getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation.annotationType().equals(annotationClass)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Creates an instance of this class using the default (no-arg) constructor.
     * An exception is raised when there is no such constructor
     *
     * @return An instance of this type, not null
     */
    public Object createInstance() {
        if (wrappedClass.isMemberClass() && !isStatic(wrappedClass.getModifiers())) {
            throw new UnitilsException("Unable to create instance of type " + getName()
                    + ". Type is a non-static inner class which is only know in the context of an instance of the enclosing class. Declare the inner class static to make construction possible.");
        }
        try {
            Constructor<?> constructor = wrappedClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            return constructor.newInstance();

        } catch (NoSuchMethodException e) {
            throw new UnitilsException("Unable to create instance of type " + getName()
                    + ". No default (no-argument) constructor found.", e);

        } catch (InstantiationException e) {
            throw new UnitilsException(
                    "Unable to create instance of type " + getName() + ". Type is an abstract class.", e);

        } catch (Exception e) {
            Throwable cause = (e instanceof InvocationTargetException) ? e.getCause() : e;
            throw new UnitilsException("Unable to create instance of type " + getName() + ".", cause);
        }
    }

    protected void addFields(Class<?> clazz, boolean staticFields, List<FieldWrapper> fields) {
        if (Object.class.equals(clazz)) {
            return;
        }
        Field[] classFields = clazz.getDeclaredFields();
        for (Field field : classFields) {
            // exclude static and special fields
            if (!field.isSynthetic() && staticFields == isStatic(field.getModifiers())) {
                FieldWrapper fieldWrapper = new FieldWrapper(field);
                fields.add(fieldWrapper);
            }
        }
        addFields(clazz.getSuperclass(), staticFields, fields);
    }

    protected void addMethods(Class<?> clazz, List<Method> methods) {
        if (Object.class.equals(clazz)) {
            return;
        }
        Method[] classMethods = clazz.getDeclaredMethods();
        for (Method method : classMethods) {
            // exclude special methods
            if (!method.isSynthetic() && !method.isBridge() && !isStatic(method.getModifiers())) {
                methods.add(method);
            }
        }
        addMethods(clazz.getSuperclass(), methods);
    }

    protected void addAnnotations(Class<?> clazz, List<Annotation> classAnnotations) {
        if (Object.class.equals(clazz)) {
            return;
        }
        Annotation[] annotations = clazz.getDeclaredAnnotations();
        classAnnotations.addAll(asList(annotations));
        addAnnotations(clazz.getSuperclass(), classAnnotations);
    }

    protected Field getSimpleField(String name, Class<?> clazz) {
        Class<?> currentClass = clazz;
        while (!Object.class.equals(currentClass)) {
            try {
                String trimmedName = name.trim();
                return currentClass.getDeclaredField(trimmedName);
            } catch (NoSuchFieldException e) {
                // not found, try the superclass
            }
            currentClass = currentClass.getSuperclass();
        }
        return null;
    }

    protected List<FieldWrapper> getFieldsOfType(Type type, List<FieldWrapper> fields) {
        List<FieldWrapper> result = new ArrayList<FieldWrapper>();
        for (FieldWrapper field : fields) {
            if (field.isOfType(type)) {
                result.add(field);
            }
        }
        return result;
    }

    protected List<FieldWrapper> getFieldsAssignableFrom(Type type, List<FieldWrapper> fields) {
        List<FieldWrapper> result = new ArrayList<FieldWrapper>();
        for (FieldWrapper field : fields) {
            if (field.isAssignableFrom(type)) {
                result.add(field);
            }
        }
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        ClassWrapper classWrapper1 = (ClassWrapper) o;
        if (wrappedClass != null ? !wrappedClass.equals(classWrapper1.wrappedClass)
                : classWrapper1.wrappedClass != null) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        return wrappedClass != null ? wrappedClass.hashCode() : 0;
    }

    @Override
    public String toString() {
        return getName();
    }
}