/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.engine.resource;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
// [excludes gwt]
/**
* Descriptor for Restlet annotations.
*
* @author Jerome Louvel
*/
public abstract class AnnotationInfo {
/**
* Returns the actual type for a given generic type name.
*
* @param currentClass
* The current class to walk up.
* @param genericTypeName
* The generic type name to resolve.
* @return The actual type.
*/
protected static Class<?> getJavaActualType(Class<?> currentClass,
String genericTypeName) {
Class<?> result = null;
// Lookup in the super class
result = getJavaActualType(currentClass.getGenericSuperclass(),
genericTypeName);
if (result == null) {
// Lookup in the implemented interfaces
Type[] interfaceTypes = currentClass.getGenericInterfaces();
for (int i = 0; (result == null) && (i < interfaceTypes.length); i++) {
result = getJavaActualType(interfaceTypes[i], genericTypeName);
}
}
return result;
}
/**
* Returns the actual type for a given generic type name.
*
* @param currentType
* The current type to start with.
* @param genericTypeName
* The generic type name to resolve.
* @return The actual type.
*/
protected static Class<?> getJavaActualType(Type currentType,
String genericTypeName) {
Class<?> result = null;
if (currentType != null) {
if (currentType instanceof Class<?>) {
// Look in the generic super class or the implemented interfaces
result = getJavaActualType((Class<?>) currentType,
genericTypeName);
} else if (currentType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) currentType;
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
Type[] actualTypeArguments = parameterizedType
.getActualTypeArguments();
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; (result == null)
&& (i < actualTypeArguments.length); i++) {
if (genericTypeName.equals(typeParameters[i].getName())) {
result = getTypeClass(actualTypeArguments[i]);
}
}
}
}
return result;
}
/**
* Returns the underlying class for a type or null.
*
* @param type
* The generic type.
* @return The underlying class
*/
protected static Class<?> getTypeClass(Type type) {
Class<?> result = null;
if (type instanceof Class<?>) {
result = (Class<?>) type;
} else if (type instanceof ParameterizedType) {
result = getTypeClass(((ParameterizedType) type).getRawType());
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type)
.getGenericComponentType();
Class<?> componentClass = getTypeClass(componentType);
if (componentClass != null) {
result = Array.newInstance(componentClass, 0).getClass();
}
}
return result;
}
/** The raw annotation value. */
protected final String annotationValue;
/** The class that hosts the annotated Java method. */
protected final Class<?> javaClass;
/** The annotated Java method. */
protected final java.lang.reflect.Method javaMethod;
/** The upper implementation of the annotated Java method. */
protected final java.lang.reflect.Method javaMethodImpl;
/**
* Constructor.
*
* @param javaClass
* The annotated Java class or parent Java class.
* @param javaMethod
* The annotated Java method.
* @param annotationValue
* The annotation value.
*/
public AnnotationInfo(Class<?> javaClass,
java.lang.reflect.Method javaMethod, String annotationValue) {
super();
this.javaClass = javaClass;
this.javaMethod = javaMethod;
this.annotationValue = annotationValue;
java.lang.reflect.Method m = null;
try {
m = javaClass.getMethod(javaMethod.getName(),
javaMethod.getParameterTypes());
} catch (Exception e) {
m = javaMethod;
}
if (m != null) {
this.javaMethodImpl = m;
} else {
this.javaMethodImpl = javaMethod;
}
}
/**
* Constructor.
*
* @param javaClass
* The annotated Java class or parent Java class.
* @param annotationValue
* The annotation value.
*/
public AnnotationInfo(Class<?> javaClass, String annotationValue) {
this(javaClass, null, annotationValue);
}
/**
* Indicates if the current variant is equal to the given object.
*
* @param other
* The other object.
* @return True if the current object is equal to the given object.
*/
@Override
public boolean equals(Object other) {
boolean result = (other instanceof AnnotationInfo);
if (result && (other != this)) {
AnnotationInfo otherAnnotation = (AnnotationInfo) other;
// Compare the method
if (result) {
result = ((getJavaMethod() == null)
&& (otherAnnotation.getJavaMethod() == null) || (getJavaMethod() != null)
&& getJavaMethod().equals(
otherAnnotation.getJavaMethod()));
}
// Compare the resource interface
if (result) {
result = ((getJavaClass() == null)
&& (otherAnnotation.getJavaClass() == null) || (getJavaClass() != null)
&& getJavaClass()
.equals(otherAnnotation.getJavaClass()));
}
// Compare the annotation value
if (result) {
result = ((getAnnotationValue() == null)
&& (otherAnnotation.getAnnotationValue() == null) || (getAnnotationValue() != null)
&& getAnnotationValue().equals(
otherAnnotation.getAnnotationValue()));
}
}
return result;
}
/**
* Returns the raw annotation value.
*
* @return The raw annotation value.
*/
public String getAnnotationValue() {
return annotationValue;
}
/**
* Returns the actual type for a given generic type.
*
* @param initialType
* The initial type, which may be generic.
* @param genericType
* The generic type information if any.
* @return The actual type.
*/
protected Class<?> getJavaActualType(Class<?> initialType, Type genericType) {
Class<?> result = initialType;
try {
if (genericType instanceof TypeVariable<?>) {
TypeVariable<?> genericTypeVariable = (TypeVariable<?>) genericType;
String genericTypeName = genericTypeVariable.getName();
result = getJavaActualType(getJavaClass(), genericTypeName);
}
} catch (Throwable t) {
t.printStackTrace();
}
return result;
}
/**
* Returns the resource interface value.
*
* @return The resource interface value.
*/
public Class<?> getJavaClass() {
return javaClass;
}
/**
* Returns the annotated Java method.
*
* @return The annotated Java method.
*/
public java.lang.reflect.Method getJavaMethod() {
return javaMethod;
}
@Override
public String toString() {
return "AnnotationInfo [javaMethod: " + javaMethod + ", javaClass: "
+ javaClass + ", value: " + annotationValue + "]";
}
}