Copyright (C) 2010 Olafur Gauti Gudmundsson
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.
/**
* Copyright (C) 2010 Olafur Gauti Gudmundsson
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 org.mongodb.morphia.utils;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
import org.bson.types.CodeWScope;
import org.bson.types.ObjectId;
import org.mongodb.morphia.Key;
import org.mongodb.morphia.annotations.Embedded;
import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.logging.Logger;
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
import org.mongodb.morphia.mapping.MappingException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.regex.Pattern;
Various reflection utility methods, used mainly in the Mapper.
Author: Olafur Gauti Gudmundsson
/**
* Various reflection utility methods, used mainly in the Mapper.
*
* @author Olafur Gauti Gudmundsson
*/
public final class ReflectionUtils {
private static final Logger LOG = MorphiaLoggerFactory.get(ReflectionUtils.class);
private ReflectionUtils() {
}
Get an array of all fields declared in the supplied class, and all its superclasses (except java.lang.Object).
Params: - type – the class for which we want to retrieve the Fields
- returnFinalFields – specifies whether to return final fields
Returns: an array of all declared and inherited fields
/**
* Get an array of all fields declared in the supplied class, and all its superclasses (except java.lang.Object).
*
* @param type the class for which we want to retrieve the Fields
* @param returnFinalFields specifies whether to return final fields
* @return an array of all declared and inherited fields
*/
public static Field[] getDeclaredAndInheritedFields(final Class type, final boolean returnFinalFields) {
final List<Field> allFields = new ArrayList<Field>();
allFields.addAll(getValidFields(type.getDeclaredFields(), returnFinalFields));
Class parent = type.getSuperclass();
while ((parent != null) && (parent != Object.class)) {
allFields.addAll(getValidFields(parent.getDeclaredFields(), returnFinalFields));
parent = parent.getSuperclass();
}
return allFields.toArray(new Field[allFields.size()]);
}
Scans the array fields and returns any fields that are not static or (optionally) final.
Params: - fields – the fields to process
- returnFinalFields – include final fields in the results
Returns: the valid fields
/**
* Scans the array fields and returns any fields that are not static or (optionally) final.
*
* @param fields the fields to process
* @param returnFinalFields include final fields in the results
* @return the valid fields
*/
public static List<Field> getValidFields(final Field[] fields, final boolean returnFinalFields) {
final List<Field> validFields = new ArrayList<Field>();
// we ignore static and final fields
for (final Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()) && (returnFinalFields || !Modifier.isFinal(field.getModifiers()))) {
validFields.add(field);
}
}
return validFields;
}
Get a list of all methods declared in the supplied class, and all its superclasses (except java.lang.Object), recursively.
Params: - type – the class for which we want to retrieve the Methods
Returns: an array of all declared and inherited fields
/**
* Get a list of all methods declared in the supplied class, and all its superclasses (except java.lang.Object), recursively.
*
* @param type the class for which we want to retrieve the Methods
* @return an array of all declared and inherited fields
*/
public static List<Method> getDeclaredAndInheritedMethods(final Class type) {
return getDeclaredAndInheritedMethods(type, new ArrayList<Method>());
}
private static List<Method> getDeclaredAndInheritedMethods(final Class type, final List<Method> methods) {
if ((type == null) || (type == Object.class)) {
return methods;
}
final Class parent = type.getSuperclass();
final List<Method> list = getDeclaredAndInheritedMethods(parent, methods == null ? new ArrayList<Method>() : methods);
for (final Method m : type.getDeclaredMethods()) {
if (!Modifier.isStatic(m.getModifiers())) {
list.add(m);
}
}
return list;
}
// public static boolean implementsAnyInterface(final Class type, final Class... interfaceClasses)
// {
// for (Class iF : interfaceClasses)
// {
// if (implementsInterface(type, iF))
// {
// return true;
// }
// }
// return false;
// }
Checks if the class is an integer type, i.e., is numeric but not a floating point type.
Params: - type – the class we want to check
Returns: true if the type is an integral type
/**
* Checks if the class is an integer type, i.e., is numeric but not a floating point type.
*
* @param type the class we want to check
* @return true if the type is an integral type
*/
public static boolean isIntegerType(final Class type) {
return Arrays.<Class>asList(Integer.class, int.class, Long.class, long.class, Short.class, short.class, Byte.class,
byte.class).contains(type);
}
Check if the class supplied represents a valid property type.
Params: - type – the class we want to check
Returns: true if the class represents a valid property type
/**
* Check if the class supplied represents a valid property type.
*
* @param type the class we want to check
* @return true if the class represents a valid property type
*/
public static boolean isPropertyType(final Type type) {
if (type instanceof GenericArrayType) {
return isPropertyType(((GenericArrayType) type).getGenericComponentType());
}
if (type instanceof ParameterizedType) {
return isPropertyType(((ParameterizedType) type).getRawType());
}
return type instanceof Class && isPropertyType((Class) type);
}
Get the (first) class that parameterizes the Field supplied.
Params: - field – the field
Returns: the class that parameterizes the field, or null if field is not parameterized
/**
* Get the (first) class that parameterizes the Field supplied.
*
* @param field the field
* @return the class that parameterizes the field, or null if field is not parameterized
*/
public static Class getParameterizedClass(final Field field) {
return getParameterizedClass(field, 0);
}
Get the class that parameterizes the Field supplied, at the index supplied (field can be parameterized with multiple param classes).
Params: - field – the field
- index – the index of the parameterizing class
Returns: the class that parameterizes the field, or null if field is not parameterized
/**
* Get the class that parameterizes the Field supplied, at the index supplied (field can be parameterized with multiple param classes).
*
* @param field the field
* @param index the index of the parameterizing class
* @return the class that parameterizes the field, or null if field is not parameterized
*/
public static Class getParameterizedClass(final Field field, final int index) {
if (field.getGenericType() instanceof ParameterizedType) {
final ParameterizedType type = (ParameterizedType) field.getGenericType();
if ((type.getActualTypeArguments() != null) && (type.getActualTypeArguments().length <= index)) {
return null;
}
final Type paramType = type.getActualTypeArguments()[index];
if (paramType instanceof GenericArrayType) {
final Class arrayType = (Class) ((GenericArrayType) paramType).getGenericComponentType();
return Array.newInstance(arrayType, 0)
.getClass();
} else {
if (paramType instanceof ParameterizedType) {
final ParameterizedType paramPType = (ParameterizedType) paramType;
return (Class) paramPType.getRawType();
} else {
if (paramType instanceof TypeVariable) {
// TODO: Figure out what to do... Walk back up the to
// the parent class and try to get the variable type
// from the T/V/X
throw new MappingException("Generic Typed Class not supported: <" + ((TypeVariable) paramType).getName() + "> = "
+ ((TypeVariable) paramType).getBounds()[0]);
} else if (paramType instanceof Class) {
return (Class) paramType;
} else {
throw new MappingException("Unknown type... pretty bad... call for help, wave your hands... yeah!");
}
}
}
}
return getParameterizedClass(field.getType());
}
Returns the parameterized type for a field
Params: - field – the field to examine
- index – the location of the parameter to return
Returns: the type
/**
* Returns the parameterized type for a field
*
* @param field the field to examine
* @param index the location of the parameter to return
* @return the type
*/
public static Type getParameterizedType(final Field field, final int index) {
if (field != null) {
if (field.getGenericType() instanceof ParameterizedType) {
final ParameterizedType type = (ParameterizedType) field.getGenericType();
if ((type.getActualTypeArguments() != null) && (type.getActualTypeArguments().length <= index)) {
return null;
}
final Type paramType = type.getActualTypeArguments()[index];
if (paramType instanceof GenericArrayType) {
return paramType; //((GenericArrayType) paramType).getGenericComponentType();
} else {
if (paramType instanceof ParameterizedType) {
return paramType;
} else {
if (paramType instanceof TypeVariable) {
// TODO: Figure out what to do... Walk back up the to
// the parent class and try to get the variable type
// from the T/V/X
// throw new MappingException("Generic Typed Class not supported: <" + ((TypeVariable)
// paramType).getName() + "> = " + ((TypeVariable) paramType).getBounds()[0]);
return paramType;
} else if (paramType instanceof WildcardType) {
return paramType;
} else if (paramType instanceof Class) {
return paramType;
} else {
throw new MappingException("Unknown type... pretty bad... call for help, wave your hands... yeah!");
}
}
}
}
// Not defined on field, but may be on class or super class...
return getParameterizedClass(field.getType());
}
return null;
}
Returns the parameterized type of a Class
Params: - c – the class to examine
Returns: the type
/**
* Returns the parameterized type of a Class
*
* @param c the class to examine
* @return the type
*/
public static Class getParameterizedClass(final Class c) {
return getParameterizedClass(c, 0);
}
Returns the parameterized type in the given position
Params: - c – the class to examine
- index – the position of the type to return
Returns: the type
/**
* Returns the parameterized type in the given position
*
* @param c the class to examine
* @param index the position of the type to return
* @return the type
*/
public static Class getParameterizedClass(final Class c, final int index) {
final TypeVariable[] typeVars = c.getTypeParameters();
if (typeVars.length > 0) {
final TypeVariable typeVariable = typeVars[index];
final Type[] bounds = typeVariable.getBounds();
final Type type = bounds[0];
if (type instanceof Class) {
return (Class) type; // broke for EnumSet, cause bounds contain
// type instead of class
} else {
return null;
}
} else {
Type superclass = c.getGenericSuperclass();
if (superclass == null && c.isInterface()) {
Type[] interfaces = c.getGenericInterfaces();
if (interfaces.length > 0) {
superclass = interfaces[index];
}
}
if (superclass instanceof ParameterizedType) {
final Type[] actualTypeArguments = ((ParameterizedType) superclass).getActualTypeArguments();
return actualTypeArguments.length > index ? (Class<?>) actualTypeArguments[index] : null;
} else if (!Object.class.equals(superclass)) {
return getParameterizedClass((Class) superclass);
} else {
return null;
}
}
}
Check if a field is parameterized with a specific class.
Params: - field – the field
- c – the class to check against
Returns: true if the field is parameterized and c is the class that parameterizes the field, or is an interface that the parameterized
class implements, else false Deprecated: this class is unused in morphia and will be removed in a future release
/**
* Check if a field is parameterized with a specific class.
*
* @param field the field
* @param c the class to check against
* @return true if the field is parameterized and c is the class that parameterizes the field, or is an interface that the parameterized
* class implements, else false
* @deprecated this class is unused in morphia and will be removed in a future release
*/
public static boolean isFieldParameterizedWithClass(final Field field, final Class c) {
if (field.getGenericType() instanceof ParameterizedType) {
final ParameterizedType genericType = (ParameterizedType) field.getGenericType();
for (final Type type : genericType.getActualTypeArguments()) {
if (type == c) {
return true;
}
if (c.isInterface() && implementsInterface((Class) type, c)) {
return true;
}
}
}
return false;
}
Check if a class implements a specific interface.
Params: - type – the class we want to check
- interfaceClass – the interface class we want to check against
Returns: true if type implements interfaceClass, else false
/**
* Check if a class implements a specific interface.
*
* @param type the class we want to check
* @param interfaceClass the interface class we want to check against
* @return true if type implements interfaceClass, else false
*/
public static boolean implementsInterface(final Class<?> type, final Class<?> interfaceClass) {
return interfaceClass.isAssignableFrom(type);
}
Check if the field supplied is parameterized with a valid JCR property type.
Params: - field – the field
Returns: true if the field is parameterized with a valid JCR property type, else false Deprecated: this class is unused in morphia and will be removed in a future release
/**
* Check if the field supplied is parameterized with a valid JCR property type.
*
* @param field the field
* @return true if the field is parameterized with a valid JCR property type, else false
* @deprecated this class is unused in morphia and will be removed in a future release
*/
public static boolean isFieldParameterizedWithPropertyType(final Field field) {
if (field.getGenericType() instanceof ParameterizedType) {
final ParameterizedType genericType = (ParameterizedType) field.getGenericType();
for (final Type type : genericType.getActualTypeArguments()) {
if (isPropertyType((Class) type)) {
return true;
}
}
}
return false;
}
Checks if the Class given is a property type
Params: - type – the Class to examine
Returns: true if the Class's type is considered a property type
/**
* Checks if the Class given is a property type
*
* @param type the Class to examine
* @return true if the Class's type is considered a property type
*/
public static boolean isPropertyType(final Class type) {
return type != null && (isPrimitiveLike(type) || type == DBRef.class || type == Pattern.class
|| type == CodeWScope.class || type == ObjectId.class || type == Key.class
|| type == DBObject.class || type == BasicDBObject.class);
}
Checks if the Class given is a primitive type. This includes the Java primitive types and their wrapper types.
Params: - type – the Class to examine
Returns: true if the Class's type is considered a primitive type
/**
* Checks if the Class given is a primitive type. This includes the Java primitive types and their wrapper types.
*
* @param type the Class to examine
* @return true if the Class's type is considered a primitive type
*/
public static boolean isPrimitiveLike(final Class type) {
return type != null && (type == String.class || type == char.class
|| type == Character.class || type == short.class || type == Short.class
|| type == Integer.class || type == int.class || type == Long.class || type == long.class
|| type == Double.class || type == double.class || type == float.class || type == Float.class
|| type == Boolean.class || type == boolean.class || type == Byte.class || type == byte.class
|| type == Date.class || type == Locale.class || type == Class.class || type == UUID.class
|| type == URI.class || type.isEnum());
}
Returns the @Embedded annotation on a Class if present
Params: - c – the class to examine
Returns: the annotation. may be null.
/**
* Returns the @Embedded annotation on a Class if present
*
* @param c the class to examine
* @return the annotation. may be null.
*/
public static Embedded getClassEmbeddedAnnotation(final Class c) {
return getAnnotation(c, Embedded.class);
}
Returns an annotation on a Class if present
Params: - c – the class to examine
- annotation – the annotation to find
Type parameters: - <T> – the type of the annotation
Returns: the annotation. may be null.
/**
* Returns an annotation on a Class if present
*
* @param c the class to examine
* @param annotation the annotation to find
* @param <T> the type of the annotation
* @return the annotation. may be null.
*/
public static <T> T getAnnotation(final Class c, final Class<T> annotation) {
final List<T> found = getAnnotations(c, annotation);
if (found != null && !found.isEmpty()) {
return found.get(0);
} else {
return null;
}
}
Returns the (first) instance of the annotation, on the class (or any superclass, or interfaces implemented).
Params: - c – the class to examine
- annotation – the annotation to find
Type parameters: - <T> – the type of the annotation
Returns: the list of annotations
/**
* Returns the (first) instance of the annotation, on the class (or any superclass, or interfaces implemented).
*
* @param c the class to examine
* @param annotation the annotation to find
* @param <T> the type of the annotation
* @return the list of annotations
*/
@SuppressWarnings("unchecked")
public static <T> List<T> getAnnotations(final Class c, final Class<T> annotation) {
final List<T> found = new ArrayList<T>();
// TODO isn't that actually breaking the contract of @Inherited?
if (c.isAnnotationPresent(annotation)) {
found.add((T) c.getAnnotation(annotation));
}
Class parent = c.getSuperclass();
while ((parent != null) && (parent != Object.class)) {
if (parent.isAnnotationPresent(annotation)) {
found.add((T) parent.getAnnotation(annotation));
}
// ...and interfaces that the superclass implements
for (final Class interfaceClass : parent.getInterfaces()) {
if (interfaceClass.isAnnotationPresent(annotation)) {
found.add((T) interfaceClass.getAnnotation(annotation));
}
}
parent = parent.getSuperclass();
}
// ...and all implemented interfaces
for (final Class interfaceClass : c.getInterfaces()) {
if (interfaceClass.isAnnotationPresent(annotation)) {
found.add((T) interfaceClass.getAnnotation(annotation));
}
}
// no annotation found, use the defaults
return found;
}
Returns the @Entity annotation on a Class if present
Params: - c – the class to examine
Returns: the annotation. may be null.
/**
* Returns the @Entity annotation on a Class if present
*
* @param c the class to examine
* @return the annotation. may be null.
*/
public static Entity getClassEntityAnnotation(final Class c) {
return getAnnotation(c, Entity.class);
}
Returns the classes in a package
Params: - packageName – the package to scan
Throws: - IOException – thrown if an error is encountered scanning packages
- ClassNotFoundException – thrown if a class can not be found
Returns: the list of classes
/**
* Returns the classes in a package
*
* @param packageName the package to scan
* @return the list of classes
* @throws IOException thrown if an error is encountered scanning packages
* @throws ClassNotFoundException thrown if a class can not be found
*/
public static Set<Class<?>> getClasses(final String packageName) throws IOException, ClassNotFoundException {
return getClasses(packageName, false);
}
Returns the classes in a package
Params: - packageName – the package to scan
- mapSubPackages – whether to map the sub-packages while scanning
Throws: - IOException – thrown if an error is encountered scanning packages
- ClassNotFoundException – thrown if a class can not be found
Returns: the list of classes
/**
* Returns the classes in a package
*
* @param packageName the package to scan
* @param mapSubPackages whether to map the sub-packages while scanning
* @return the list of classes
* @throws IOException thrown if an error is encountered scanning packages
* @throws ClassNotFoundException thrown if a class can not be found
*/
public static Set<Class<?>> getClasses(final String packageName, final boolean mapSubPackages) throws IOException,
ClassNotFoundException {
final ClassLoader loader = Thread.currentThread()
.getContextClassLoader();
return getClasses(loader, packageName, mapSubPackages);
}
Returns the classes in a package
Params: - loader – the ClassLoader to use
- packageName – the package to scan
Throws: - IOException – thrown if an error is encountered scanning packages
- ClassNotFoundException – thrown if a class can not be found
Returns: the list of classes
/**
* Returns the classes in a package
*
* @param loader the ClassLoader to use
* @param packageName the package to scan
* @return the list of classes
* @throws IOException thrown if an error is encountered scanning packages
* @throws ClassNotFoundException thrown if a class can not be found
*/
public static Set<Class<?>> getClasses(final ClassLoader loader, final String packageName) throws IOException, ClassNotFoundException {
return getClasses(loader, packageName, false);
}
Returns the classes in a package
Params: - loader – the ClassLoader to use
- packageName – the package to scan
- mapSubPackages – whether to map the sub-packages while scanning
Throws: - IOException – thrown if an error is encountered scanning packages
- ClassNotFoundException – thrown if a class can not be found
Returns: the list of classes
/**
* Returns the classes in a package
*
* @param loader the ClassLoader to use
* @param packageName the package to scan
* @param mapSubPackages whether to map the sub-packages while scanning
* @return the list of classes
* @throws IOException thrown if an error is encountered scanning packages
* @throws ClassNotFoundException thrown if a class can not be found
*/
public static Set<Class<?>> getClasses(final ClassLoader loader, final String packageName, final boolean mapSubPackages) throws
IOException, ClassNotFoundException {
final Set<Class<?>> classes = new HashSet<Class<?>>();
final String path = packageName.replace('.', '/');
final Enumeration<URL> resources = loader.getResources(path);
if (resources != null) {
while (resources.hasMoreElements()) {
String filePath = resources.nextElement()
.getFile();
// WINDOWS HACK
if (filePath.indexOf("%20") > 0) {
filePath = filePath.replaceAll("%20", " ");
}
// # in the jar name
if (filePath.indexOf("%23") > 0) {
filePath = filePath.replaceAll("%23", "#");
}
if (filePath != null) {
if ((filePath.indexOf("!") > 0) && (filePath.indexOf(".jar") > 0)) {
String jarPath = filePath.substring(0, filePath.indexOf("!"))
.substring(filePath.indexOf(":") + 1);
// WINDOWS HACK
if (jarPath.contains(":")) {
jarPath = jarPath.substring(1);
}
classes.addAll(getFromJARFile(loader, jarPath, path, mapSubPackages));
} else {
classes.addAll(getFromDirectory(loader, new File(filePath), packageName, mapSubPackages));
}
}
}
}
return classes;
}
Returns the classes in a package found in a jar
Params: - loader – the ClassLoader to use
- jar – the jar to scan
- packageName – the package to scan
Throws: - IOException – thrown if an error is encountered scanning packages
- ClassNotFoundException – thrown if a class can not be found
Returns: the list of classes
/**
* Returns the classes in a package found in a jar
*
* @param loader the ClassLoader to use
* @param jar the jar to scan
* @param packageName the package to scan
* @return the list of classes
* @throws IOException thrown if an error is encountered scanning packages
* @throws ClassNotFoundException thrown if a class can not be found
*/
public static Set<Class<?>> getFromJARFile(final ClassLoader loader, final String jar, final String packageName)
throws IOException, ClassNotFoundException {
return getFromJARFile(loader, jar, packageName, false);
}
Returns the classes in a package found in a jar
Params: - loader – the ClassLoader to use
- jar – the jar to scan
- packageName – the package to scan
- mapSubPackages – whether to map the sub-packages while scanning
Throws: - IOException – thrown if an error is encountered scanning packages
- ClassNotFoundException – thrown if a class can not be found
Returns: the list of classes
/**
* Returns the classes in a package found in a jar
*
* @param loader the ClassLoader to use
* @param jar the jar to scan
* @param packageName the package to scan
* @param mapSubPackages whether to map the sub-packages while scanning
* @return the list of classes
* @throws IOException thrown if an error is encountered scanning packages
* @throws ClassNotFoundException thrown if a class can not be found
*/
public static Set<Class<?>> getFromJARFile(final ClassLoader loader, final String jar, final String packageName, final boolean
mapSubPackages) throws IOException, ClassNotFoundException {
final Set<Class<?>> classes = new HashSet<Class<?>>();
final JarInputStream jarFile = new JarInputStream(new FileInputStream(jar));
try {
JarEntry jarEntry;
do {
jarEntry = jarFile.getNextJarEntry();
if (jarEntry != null) {
String className = jarEntry.getName();
if (className.endsWith(".class")) {
String classPackageName = getPackageName(className);
if (classPackageName.equals(packageName) || (mapSubPackages && isSubPackage(classPackageName, packageName))) {
className = stripFilenameExtension(className);
classes.add(Class.forName(className.replace('/', '.'), true, loader));
}
}
}
} while (jarEntry != null);
} finally {
jarFile.close();
}
return classes;
}
Returns the classes in a package found in a directory
Params: - loader – the ClassLoader to use
- directory – the directory to scan
- packageName – the package to scan
Throws: - ClassNotFoundException – thrown if a class can not be found
Returns: the list of classes
/**
* Returns the classes in a package found in a directory
*
* @param loader the ClassLoader to use
* @param directory the directory to scan
* @param packageName the package to scan
* @return the list of classes
* @throws ClassNotFoundException thrown if a class can not be found
*/
public static Set<Class<?>> getFromDirectory(final ClassLoader loader, final File directory, final String packageName)
throws ClassNotFoundException {
return getFromDirectory(loader, directory, packageName, false);
}
Returns the classes in a package found in a directory
Params: - loader – the ClassLoader to use
- directory – the directory to scan
- packageName – the package to scan
- mapSubPackages – whether to map the sub-packages while scanning
Throws: - ClassNotFoundException – thrown if a class can not be found
Returns: the list of classes
/**
* Returns the classes in a package found in a directory
*
* @param loader the ClassLoader to use
* @param directory the directory to scan
* @param packageName the package to scan
* @param mapSubPackages whether to map the sub-packages while scanning
* @return the list of classes
* @throws ClassNotFoundException thrown if a class can not be found
*/
public static Set<Class<?>> getFromDirectory(final ClassLoader loader, final File directory, final String packageName,
final boolean mapSubPackages) throws ClassNotFoundException {
final Set<Class<?>> classes = new HashSet<Class<?>>();
if (directory.exists()) {
for (final String file : getFileNames(directory, packageName, mapSubPackages)) {
if (file.endsWith(".class")) {
final String name = stripFilenameExtension(file);
final Class<?> clazz = Class.forName(name, true, loader);
classes.add(clazz);
}
}
}
return classes;
}
private static Set<String> getFileNames(final File directory, final String packageName, final boolean mapSubPackages) {
Set<String> fileNames = new HashSet<String>();
for (File file: directory.listFiles()) {
if (file.isFile()) {
fileNames.add(packageName + '.' + file.getName());
} else if (mapSubPackages){
fileNames.addAll(getFileNames(file, packageName + '.' + file.getName(), true));
}
}
return fileNames;
}
private static String getPackageName(final String filename) {
return filename.contains("/") ? filename.substring(0, filename.lastIndexOf('/')) : filename;
}
private static String stripFilenameExtension(final String filename) {
if (filename.indexOf('.') != -1) {
return filename.substring(0, filename.lastIndexOf('.'));
} else {
return filename;
}
}
private static boolean isSubPackage(final String fullPackageName, final String parentPackageName) {
return fullPackageName.startsWith(parentPackageName);
}
Converts an Iterable to a List
Params: - it – the Iterable
Type parameters: - <T> – the types of the elements in the Iterable
Returns: the List
/**
* Converts an Iterable to a List
*
* @param it the Iterable
* @param <T> the types of the elements in the Iterable
* @return the List
*/
public static <T> List<T> iterToList(final Iterable<T> it) {
if (it instanceof List) {
return (List<T>) it;
}
if (it == null) {
return null;
}
final List<T> ar = new ArrayList<T>();
for (final T o : it) {
ar.add(o);
}
return ar;
}
Converts a List to an array
Params: - type – the Class type of the elements of the List
- values – the List to convert
Returns: the array
/**
* Converts a List to an array
*
* @param type the Class type of the elements of the List
* @param values the List to convert
* @return the array
*/
public static Object convertToArray(final Class type, final List<?> values) {
final Object exampleArray = Array.newInstance(type, values.size());
try {
return values.toArray((Object[]) exampleArray);
} catch (ClassCastException e) {
for (int i = 0; i < values.size(); i++) {
Array.set(exampleArray, i, values.get(i));
}
return exampleArray;
}
}
Get the underlying class for a type, or null if the type is a variable type.
Params: - type – the type
Returns: the underlying class
/**
* Get the underlying class for a type, or null if the type is a variable type.
*
* @param type the type
* @return the underlying class
*/
public static Class<?> getClass(final Type type) {
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
} else if (type instanceof GenericArrayType) {
final Type componentType = ((GenericArrayType) type).getGenericComponentType();
final Class<?> componentClass = getClass(componentType);
if (componentClass != null) {
return Array.newInstance(componentClass, 0).getClass();
} else {
LOG.debug("************ ReflectionUtils.getClass 1st else");
LOG.debug("************ type = " + type);
return null;
}
} else {
LOG.debug("************ ReflectionUtils.getClass final else");
LOG.debug("************ type = " + type);
return null;
}
}
Get the actual type arguments a child class has used to extend a generic base class.
Params: - baseClass – the base class
- childClass – the child class
Type parameters: - <T> – the type of the base class
Returns: a list of the raw classes for the actual type arguments. Deprecated: this class is unused in morphia and will be removed in a future release
/**
* Get the actual type arguments a child class has used to extend a generic base class.
*
* @param baseClass the base class
* @param childClass the child class
* @param <T> the type of the base class
* @return a list of the raw classes for the actual type arguments.
* @deprecated this class is unused in morphia and will be removed in a future release
*/
public static <T> List<Class<?>> getTypeArguments(final Class<T> baseClass, final Class<? extends T> childClass) {
final Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
Type type = childClass;
// start walking up the inheritance hierarchy until we hit baseClass
while (!getClass(type).equals(baseClass)) {
if (type instanceof Class) {
// there is no useful information for us in raw types, so just
// keep going.
type = ((Class) type).getGenericSuperclass();
} else {
final ParameterizedType parameterizedType = (ParameterizedType) type;
final Class<?> rawType = (Class) parameterizedType.getRawType();
final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
final TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
}
if (!rawType.equals(baseClass)) {
type = rawType.getGenericSuperclass();
}
}
}
// finally, for each actual type argument provided to baseClass,
// determine (if possible)
// the raw class for that type argument.
final Type[] actualTypeArguments;
if (type instanceof Class) {
actualTypeArguments = ((Class) type).getTypeParameters();
} else {
actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
}
final List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
// resolve types by chasing down type variables.
for (Type baseType : actualTypeArguments) {
while (resolvedTypes.containsKey(baseType)) {
baseType = resolvedTypes.get(baseType);
}
typeArgumentsAsClasses.add(getClass(baseType));
}
return typeArgumentsAsClasses;
}
Returns the type argument
Params: - clazz – the Class to examine
- tv – the TypeVariable to look for
Type parameters: - <T> – the type of the Class
Returns: the Class type
/**
* Returns the type argument
*
* @param clazz the Class to examine
* @param tv the TypeVariable to look for
* @param <T> the type of the Class
* @return the Class type
*/
public static <T> Class<?> getTypeArgument(final Class<? extends T> clazz, final TypeVariable<? extends GenericDeclaration> tv) {
final Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
Type type = clazz;
// start walking up the inheritance hierarchy until we hit the end
while (type != null && !Object.class.equals(getClass(type))) {
if (type instanceof Class) {
// there is no useful information for us in raw types, so just
// keep going.
type = ((Class) type).getGenericSuperclass();
} else {
final ParameterizedType parameterizedType = (ParameterizedType) type;
final Class<?> rawType = (Class) parameterizedType.getRawType();
final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
final TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
if (typeParameters[i].equals(tv)) {
final Class cls = getClass(actualTypeArguments[i]);
if (cls != null) {
return cls;
}
//We don't know that the type we want is the one in the map, if this argument has been
//passed through multiple levels of the hierarchy. Walk back until we run out.
Type typeToTest = resolvedTypes.get(actualTypeArguments[i]);
while (typeToTest != null) {
final Class classToTest = getClass(typeToTest);
if (classToTest != null) {
return classToTest;
}
typeToTest = resolvedTypes.get(typeToTest);
}
}
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
}
if (!rawType.equals(Object.class)) {
type = rawType.getGenericSuperclass();
}
}
}
return null;
}
}