se.hiq.oss.commons.reflection.annotation.AnnotationBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-reflection Show documentation
Show all versions of commons-reflection Show documentation
Common utilities and classes for reflection
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());
}
}
}