/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* 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 com.badlogic.gdx.utils.reflect;
import java.lang.annotation.Inherited;
import com.badlogic.gwtref.client.ReflectionCache;
import com.badlogic.gwtref.client.Type;
/** Utilities for Class reflection.
* @author nexsoftware */
public final class ClassReflection {
/** Returns the Class object associated with the class or interface with the supplied string name. */
static public Class forName (String name) throws ReflectionException {
try {
return ReflectionCache.forName(name).getClassOfType();
} catch (ClassNotFoundException e) {
throw new ReflectionException("Class not found: " + name);
}
}
/** Returns the simple name of the underlying class as supplied in the source code. */
static public String getSimpleName (Class c) {
return c.getSimpleName();
}
/** Determines if the supplied Object is assignment-compatible with the object represented by supplied Class. */
static public boolean isInstance (Class c, Object obj) {
return obj != null && isAssignableFrom(c, obj.getClass());
}
/** Determines if the class or interface represented by first Class parameter is either the same as, or is a superclass or
* superinterface of, the class or interface represented by the second Class parameter. */
static public boolean isAssignableFrom (Class c1, Class c2) {
Type c1Type = ReflectionCache.getType(c1);
Type c2Type = ReflectionCache.getType(c2);
return c1Type.isAssignableFrom(c2Type);
}
/** Returns true if the class or interface represented by the supplied Class is a member class. */
static public boolean isMemberClass (Class c) {
return ReflectionCache.getType(c).isMemberClass();
}
/** Returns true if the class or interface represented by the supplied Class is a static class. */
static public boolean isStaticClass (Class c) {
return ReflectionCache.getType(c).isStatic();
}
/** Determines if the supplied Class object represents an array class. */
static public boolean isArray (Class c) {
return ReflectionCache.getType(c).isArray();
}
/** Determines if the supplied Class object represents a primitive type. */
static public boolean isPrimitive (Class c) {
return ReflectionCache.getType(c).isPrimitive();
}
/** Determines if the supplied Class object represents an enum type. */
static public boolean isEnum (Class c) {
return ReflectionCache.getType(c).isEnum();
}
/** Determines if the supplied Class object represents an annotation type. */
static public boolean isAnnotation (Class c) {
return ReflectionCache.getType(c).isAnnotation();
}
/** Determines if the supplied Class object represents an interface type. */
static public boolean isInterface (Class c) {
return ReflectionCache.getType(c).isInterface();
}
/** Determines if the supplied Class object represents an abstract type. */
static public boolean isAbstract (Class c) {
return ReflectionCache.getType(c).isAbstract();
}
/** Creates a new instance of the class represented by the supplied Class. */
static public <T> T newInstance (Class<T> c) throws ReflectionException {
try {
return (T)ReflectionCache.getType(c).newInstance();
} catch (NoSuchMethodException e) {
throw new ReflectionException("Could not use default constructor of " + c.getName(), e);
}
}
/** Returns the Class representing the component type of an array. If this class does not represent an array class this method returns null. */
static public Class getComponentType(Class c){
return ReflectionCache.getType(c).getComponentType();
}
/** Returns an array of {@link Constructor} containing the public constructors of the class represented by the supplied Class. */
static public Constructor[] getConstructors (Class c) {
com.badlogic.gwtref.client.Constructor[] constructors = ReflectionCache.getType(c).getConstructors();
Constructor[] result = new Constructor[constructors.length];
for (int i = 0, j = constructors.length; i < j; i++) {
result[i] = new Constructor(constructors[i]);
}
return result;
}
/** Returns a {@link Constructor} that represents the public constructor for the supplied class which takes the supplied
* parameter types. */
static public Constructor getConstructor (Class c, Class... parameterTypes) throws ReflectionException {
try {
return new Constructor(ReflectionCache.getType(c).getConstructor(parameterTypes));
} catch (SecurityException e) {
throw new ReflectionException("Security violation while getting constructor for class: " + c.getName(), e);
} catch (NoSuchMethodException e) {
throw new ReflectionException("Constructor not found for class: " + c.getName(), e);
}
}
/** Returns a {@link Constructor} that represents the constructor for the supplied class which takes the supplied parameter
* types. */
static public Constructor getDeclaredConstructor (Class c, Class... parameterTypes) throws ReflectionException {
try {
return new Constructor(ReflectionCache.getType(c).getDeclaredConstructor(parameterTypes));
} catch (SecurityException e) {
throw new ReflectionException("Security violation while getting constructor for class: " + c.getName(), e);
} catch (NoSuchMethodException e) {
throw new ReflectionException("Constructor not found for class: " + c.getName(), e);
}
}
/** Returns the elements of this enum class or null if this Class object does not represent an enum type. */
static public Object[] getEnumConstants (Class c) {
return ReflectionCache.getType(c).getEnumConstants();
}
/** Returns an array of {@link Method} containing the public member methods of the class represented by the supplied Class. */
static public Method[] getMethods (Class c) {
com.badlogic.gwtref.client.Method[] methods = ReflectionCache.getType(c).getMethods();
Method[] result = new Method[methods.length];
for (int i = 0, j = methods.length; i < j; i++) {
result[i] = new Method(methods[i]);
}
return result;
}
/** Returns a {@link Method} that represents the public member method for the supplied class which takes the supplied parameter
* types. */
static public Method getMethod (Class c, String name, Class... parameterTypes) throws ReflectionException {
try {
return new Method(ReflectionCache.getType(c).getMethod(name, parameterTypes));
} catch (SecurityException e) {
throw new ReflectionException("Security violation while getting method: " + name + ", for class: " + c.getName(), e);
} catch (NoSuchMethodException e) {
throw new ReflectionException("Method not found: " + name + ", for class: " + c.getName(), e);
}
}
/** Returns an array of {@link Method} containing the methods declared by the class represented by the supplied Class. */
static public Method[] getDeclaredMethods (Class c) {
com.badlogic.gwtref.client.Method[] methods = ReflectionCache.getType(c).getDeclaredMethods();
Method[] result = new Method[methods.length];
for (int i = 0, j = methods.length; i < j; i++) {
result[i] = new Method(methods[i]);
}
return result;
}
/** Returns a {@link Method} that represents the method declared by the supplied class which takes the supplied parameter types. */
static public Method getDeclaredMethod (Class c, String name, Class... parameterTypes) throws ReflectionException {
try {
return new Method(ReflectionCache.getType(c).getDeclaredMethod(name, parameterTypes));
} catch (SecurityException e) {
throw new ReflectionException("Security violation while getting method: " + name + ", for class: " + c.getName(), e);
} catch (NoSuchMethodException e) {
throw new ReflectionException("Method not found: " + name + ", for class: " + c.getName(), e);
}
}
/** Returns an array of {@link Field} containing the public fields of the class represented by the supplied Class. */
static public Field[] getFields (Class c) {
com.badlogic.gwtref.client.Field[] fields = ReflectionCache.getType(c).getFields();
Field[] result = new Field[fields.length];
for (int i = 0, j = fields.length; i < j; i++) {
result[i] = new Field(fields[i]);
}
return result;
}
/** Returns a {@link Field} that represents the specified public member field for the supplied class. */
static public Field getField (Class c, String name) throws ReflectionException {
try {
return new Field(ReflectionCache.getType(c).getField(name));
} catch (SecurityException e) {
throw new ReflectionException("Security violation while getting field: " + name + ", for class: " + c.getName(), e);
} catch (NoSuchFieldException e) {
throw new ReflectionException("Field not found: " + name + ", for class: " + c.getName(), e);
}
}
/** Returns an array of {@link Field} objects reflecting all the fields declared by the supplied class. */
static public Field[] getDeclaredFields (Class c) {
com.badlogic.gwtref.client.Field[] fields = ReflectionCache.getType(c).getDeclaredFields();
Field[] result = new Field[fields.length];
for (int i = 0, j = fields.length; i < j; i++) {
result[i] = new Field(fields[i]);
}
return result;
}
/** Returns a {@link Field} that represents the specified declared field for the supplied class. */
static public Field getDeclaredField (Class c, String name) throws ReflectionException {
try {
return new Field(ReflectionCache.getType(c).getDeclaredField(name));
} catch (SecurityException e) {
throw new ReflectionException("Security violation while getting field: " + name + ", for class: " + c.getName(), e);
} catch (NoSuchFieldException e) {
throw new ReflectionException("Field not found: " + name + ", for class: " + c.getName(), e);
}
}
/** Returns true if the supplied class has an annotation of the given type. */
static public boolean isAnnotationPresent (Class c, Class<? extends java.lang.annotation.Annotation> annotationType) {
Annotation[] annotations = getAnnotations(c);
for (Annotation annotation : annotations) {
if (annotation.getAnnotationType().equals(annotationType)) return true;
}
return false;
}
/** Returns an array of {@link Annotation} objects reflecting all annotations declared by the supplied class, and inherited
* from its superclass. Returns an empty array if there are none. */
static public Annotation[] getAnnotations (Class c) {
Type declType = ReflectionCache.getType(c);
java.lang.annotation.Annotation[] annotations = declType.getDeclaredAnnotations();
// annotations of supplied class
Annotation[] result = new Annotation[annotations.length];
for (int i = 0; i < annotations.length; i++) {
result[i] = new Annotation(annotations[i]);
}
// search super classes, until Object.class is reached
Type superType = declType.getSuperclass();
java.lang.annotation.Annotation[] superAnnotations;
while (!superType.getClassOfType().equals(Object.class)) {
superAnnotations = superType.getDeclaredAnnotations();
for (int i = 0; i < superAnnotations.length; i++) {
// check for annotation types marked as Inherited
Type annotationType = ReflectionCache.getType(superAnnotations[i].annotationType());
if (annotationType.getDeclaredAnnotation(Inherited.class) != null) {
// ignore duplicates
boolean duplicate = false;
for (Annotation annotation : result) {
if (annotation.getAnnotationType().equals(annotationType)) {
duplicate = true;
break;
}
}
// append to result set
if (!duplicate) {
Annotation[] copy = new Annotation[result.length + 1];
for (int j = 0; j < result.length; j++) {
copy[j] = result[j];
}
copy[result.length] = new Annotation(superAnnotations[i]);
result = copy;
}
}
}
superType = superType.getSuperclass();
}
return result;
}
/** Returns an {@link Annotation} object reflecting the annotation provided, or null of this class doesn't have, or doesn't
* inherit, such an annotation. This is a convenience function if the caller knows already which annotation type he's looking
* for. */
static public Annotation getAnnotation (Class c, Class<? extends java.lang.annotation.Annotation> annotationType) {
Annotation[] annotations = getAnnotations(c);
for (Annotation annotation : annotations) {
if (annotation.getAnnotationType().equals(annotationType)) return annotation;
}
return null;
}
/** Returns an array of {@link Annotation} objects reflecting all annotations declared by the supplied class, or an empty
* array if there are none. Does not include inherited annotations. */
static public Annotation[] getDeclaredAnnotations (Class c) {
java.lang.annotation.Annotation[] annotations = ReflectionCache.getType(c).getDeclaredAnnotations();
Annotation[] result = new Annotation[annotations.length];
for (int i = 0; i < annotations.length; i++) {
result[i] = new Annotation(annotations[i]);
}
return result;
}
/** Returns an {@link Annotation} object reflecting the annotation provided, or null of this class doesn't have such an
* annotation. This is a convenience function if the caller knows already which annotation type he's looking for. */
static public Annotation getDeclaredAnnotation (Class c, Class<? extends java.lang.annotation.Annotation> annotationType) {
java.lang.annotation.Annotation annotation = ReflectionCache.getType(c).getDeclaredAnnotation(annotationType);
if (annotation != null) return new Annotation(annotation);
return null;
}
static public Class[] getInterfaces (Class c) {
return ReflectionCache.getType(c).getInterfaces();
}
}