/**
* 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.ext.apispark.internal.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.restlet.ext.apispark.internal.introspection.util.UnsupportedTypeException;
/**
* Handles Java reflection operations.
*
* @author Thierry Boileau
*/
public class ReflectUtils {
@SuppressWarnings("rawtypes")
public static Field[] getAllDeclaredFields(Class type) {
List<Field> fields = new ArrayList<Field>();
Class currentType = type;
while (currentType != null) {
Field[] currentFields = currentType.getDeclaredFields();
Collections.addAll(fields, currentFields);
currentType = currentType.getSuperclass();
if (currentType != null && currentType.equals(Object.class)) {
currentType = null;
}
}
return fields.toArray(new Field[fields.size()]);
}
/**
* Extracts the first segment of a path. Will retrieve "/pet" from
* "/pet/{petId}" for example.
*
* @param path
* The path of which the segment will be extracted.
* @return The first segment of the given path.
*/
public static String getFirstSegment(String path) {
String segment = null;
if (path != null) {
int start = (path.startsWith("/")) ? 1 : 0;
int index = path.indexOf("/", start);
if (index != -1) {
segment = "/" + path.substring(start, index);
} else {
segment = "/" + path.substring(start);
}
}
return segment;
}
public static Class<?> getComponentClass(java.lang.reflect.Type type) {
if (type instanceof Class<?>) {
Class<?> c = (Class<?>) type;
if (c.isArray()) {
return c.getComponentType();
} else if (Collection.class.isAssignableFrom(c)) {
// Simple class that extends Collection<E>. Should inspect
// superclass.
return getComponentClass(c.getGenericSuperclass());
} else {
return c;
}
} else if (type instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) type;
return getComponentClass(gat.getGenericComponentType());
} else if (type instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType) type;
if (t.getActualTypeArguments().length != 1) {
throw new UnsupportedTypeException("Type " + type + " is a generic type with zero or several arguments. This is not supported.");
}
if (t.getActualTypeArguments()[0] instanceof TypeVariable) {
throw new UnsupportedTypeException("Type " + type + " is a generic type with unkwnown type. This is not supported.");
}
return getComponentClass(t.getActualTypeArguments()[0]);
}
return (type != null) ? type.getClass() : null;
}
/**
* TODO: need Javadocs
*
* @param clazz
* @return
*/
public static boolean isJdkClass(Class<?> clazz) {
if (clazz != null) {
if (clazz.isPrimitive()) {
return true;
} else if (clazz.getPackage() != null) {
return (clazz.getPackage().getName().startsWith("java.") || clazz
.getPackage().getName().startsWith("javax."));
}
}
return false;
}
/**
* TODO: need Javadocs
*
* @param type
* @return
*/
public static boolean isListType(Class<?> type) {
return Collection.class.isAssignableFrom(type) || type.isArray();
}
/**
* Returns a new instance of classname and check that it's assignable from
* expected class
*
* @param className
* The class Name
* @param instanceClazz
* The expected class
* @param <T>
* The expected class
*/
@SuppressWarnings("unchecked")
public static <T> T newInstance(String className,
Class<? extends T> instanceClazz) {
if (className == null) {
return null;
}
try {
Class<?> clazz = Class.forName(className);
if (instanceClazz.isAssignableFrom(clazz)) {
return (T) clazz.getConstructor().newInstance();
} else {
throw new RuntimeException(className
+ " does not seem to be a valid subclass of "
+ instanceClazz.getName() + " class.");
}
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot locate the class " + className
+ " in the classpath.", e);
} catch (Exception e) {
throw new RuntimeException("Cannot instantiate the class. "
+ "Check that the class has an empty constructor.", e);
}
}
/**
* Generates the name of the given parameter's type.
*
* @param parameterType
* the Java parameter's type.
* @param genericParameterType
* I'ts
* @param parameterizedType
* @return
*/
public String buildParameterTypeName(Class<?> parameterType,
java.lang.reflect.Type genericParameterType,
ParameterizedType parameterizedType) {
java.lang.reflect.Type type;
if (parameterizedType != null) {
type = parameterizedType.getActualTypeArguments()[0];
} else {
type = null;
}
StringBuilder sb = new StringBuilder();
if (type == null) {
buildTypeName(parameterType, sb);
} else {
buildTypeName(genericParameterType, sb);
}
return sb.toString();
}
/**
* Generates the name of the given type into the given StringBuilder.
*
* @param type
* The type.
* @param sb
* The stringBuilder to complete.
*/
private void buildTypeName(java.lang.reflect.Type type, StringBuilder sb) {
if (type instanceof Class<?>) {
if (((Class<?>) type).isArray()) {
buildTypeName(((Class<?>) type).getComponentType(), sb);
sb.append("[]");
} else {
sb.append(((Class<?>) type).getName());
}
} else if (type instanceof GenericArrayType) {
buildTypeName(((GenericArrayType) type).getGenericComponentType(),
sb);
sb.append("[]");
} else if (type instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType) type;
buildTypeName(t.getRawType(), sb);
sb.append("<");
if (t.getActualTypeArguments().length >= 1) {
buildTypeName(t.getActualTypeArguments()[0], sb);
for (int i = 1; i < t.getActualTypeArguments().length; i++) {
sb.append(", ");
buildTypeName(t.getActualTypeArguments()[i], sb);
}
}
sb.append(">");
} else {
sb.append(type.toString());
}
}
}