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

se.hiq.oss.commons.reflection.annotation.AnnotationBuilder Maven / Gradle / Ivy

The newest version!
package se.hiq.oss.commons.reflection.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import net.sf.cglib.proxy.Enhancer;
import se.hiq.oss.commons.reflection.annotation.cglib.AnnotationMethodInterceptor;

public class AnnotationBuilder {
    private static final String ERROR_MESSAGE = "Invalid attribute type: %s, attribute '%s"
            + "' of @%s should be %s";
    private Class annotationClass;
    private Map attributes = new HashMap();
    private Map attributeData = new HashMap();

    public AnnotationBuilder(final Class annotationClass) {
        this.annotationClass = annotationClass;
        setAttributes();
        setAttributeData();
    }

    public AnnotationBuilder(final Class annotationClass, final Object value) {
        this(annotationClass);
        value(value);
    }

    public AnnotationBuilder value(Object value) {
        validateAttributeName("value");
        validateAttributeType("value", value.getClass());
        setAttributeData("value", value);
        return this;
    }

    public AnnotationBuilder attr(String name, Object value) {
        validateAttributeName(name);
        validateAttributeType(name, value.getClass());
        setAttributeData(name, value);
        return this;
    }


    @SuppressWarnings("unchecked")
    public T build() {
        validateAttributeData();
        Object instance = Enhancer.create(annotationClass, new AnnotationMethodInterceptor(annotationClass, attributes, attributeData));
        return (T) instance;
    }

    private void setAttributeData(String name, Object value) {
        Method method = attributes.get(name);
        Class returnType = method.getReturnType();
        if (returnType.isArray() && !value.getClass().isArray()) {
            Object array = Array.newInstance(returnType.getComponentType(), 1);
            Array.set(array, 0, value);
            attributeData.put(name, array);
        } else {
            attributeData.put(name, value);
        }
    }

    private void validateAttributeName(String name) {
        if (!attributes.containsKey(name)) {
            throw new IllegalArgumentException("Invalid attribute: @" + annotationClass.getName()
                    + " does not have any attribute named '" + name + "'");
        }
    }

    private void validateAttributeType(String name, Class type) {
        Method method = attributes.get(name);
        Class returnType = method.getReturnType();
        if (returnType.isArray()) {
            validateArrayReturnType(name, type, returnType);
        } else if (returnType.isPrimitive()) {
            validatePrimitiveReturnType(name, type, returnType);
        } else {
            if (!returnType.isAssignableFrom(type)) {
                throw new IllegalArgumentException(String.format(ERROR_MESSAGE,
                        type.getName(),
                        name,
                        annotationClass.getName(),
                        returnType.getName()));
            }

        }

    }

    private void validatePrimitiveReturnType(String name, Class type, Class returnType) {
        if (type.isPrimitive()) {
            if (!returnType.equals(type)) {
                throw new IllegalArgumentException(String.format(ERROR_MESSAGE,
                        type.getName(),
                        name,
                        annotationClass.getName(),
                        returnType.getName()));
            }
        } else {
            // If wrapper class TYPE field should be present
            try {
                Class wrappedType = (Class) type.getField("TYPE").get(null);
                if (!returnType.equals(wrappedType)) {
                    throw new IllegalArgumentException(String.format(ERROR_MESSAGE,
                            type.getName(),
                            name,
                            annotationClass.getName(),
                            returnType.getName()));
                }
            } catch (final NoSuchFieldException  e) {
                throw new IllegalArgumentException(String.format(ERROR_MESSAGE,
                        type.getName(),
                        name,
                        annotationClass.getName(),
                        returnType.getName()));
            } catch (final IllegalAccessException e) {
                throw new IllegalArgumentException(String.format(ERROR_MESSAGE,
                        type.getName(),
                        name,
                        annotationClass.getName(),
                        returnType.getName()));
            }
        }
    }

    private void validateArrayReturnType(String name, Class type, Class returnType) {
        if (!type.isArray() && !returnType.getComponentType().isAssignableFrom(type)) {
            throw new IllegalArgumentException(String.format(ERROR_MESSAGE,
                    type.getName(),
                    name,
                    annotationClass.getName(),
                    returnType.getComponentType().getName()) + "[]");
        } else if (type.isArray() && !returnType.isAssignableFrom(type)) {
            throw new IllegalArgumentException(String.format(ERROR_MESSAGE,
                    type.getComponentType().getName() + "[]",
                    name,
                    annotationClass.getName(),
                    returnType.getComponentType().getName() + "[]"));
        }
    }

    private void validateAttributeData() {
        for (Map.Entry data : attributeData.entrySet()) {
            if (data.getValue() == null) {
                throw new IllegalStateException("Missing attribute value: attribute '" + data.getKey()
                        + "' of @" + annotationClass.getName() + " has not been set");
            }
        }
    }

    private void setAttributes() {
        for (Method method : annotationClass.getMethods()) {

            setAttribute(method);
        }
    }

    @SuppressWarnings("checkstyle:booleanexpressioncomplexity")
    private void setAttribute(Method method) {
        if (method.getParameterTypes().length == 0
                && !method.getName().equals("annotationType")
                && !method.getName().equals("hashCode")
                && !method.getName().equals("toString")
                && !method.getReturnType().equals(Void.TYPE)) {

            attributes.put(method.getName(), method);
        }
    }

    private void setAttributeData() {
        for (Map.Entry attribute : attributes.entrySet()) {
            attributeData.put(attribute.getKey(), attribute.getValue().getDefaultValue());
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy