org.modelcc.io.java.Reflection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ModelCC Show documentation
Show all versions of ModelCC Show documentation
ModelCC is a model-based parser generator (a.k.a. compiler compiler) that decouples language specification from language processing, avoiding some of the problems caused by grammar-driven parser generators. ModelCC receives a conceptual model as input, along with constraints that annotate it. It is then able to create a parser for the desired textual language and the generated parser fully automates the instantiation of the language conceptual model. ModelCC also includes a built-in reference resolution mechanism that results in abstract syntax graphs, rather than mere abstract syntax trees.
The newest version!
/*
* ModelCC, distributed under ModelCC Shared Software License, www.modelcc.org
*/
package org.modelcc.io.java;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.modelcc.language.metamodel.MemberCollectionType;
/**
* Reflection utilities
*
* @author Luis Quesada ([email protected]) & Fernando Berzal
* ([email protected]), with contributions by Evan Klinger
*/
public class Reflection
{
public static Field findField(Class c, String fieldName)
{
try {
return c.getDeclaredField(fieldName);
} catch (Exception e) {
if (c.getSuperclass() != null)
return findField(c.getSuperclass(), fieldName);
return null;
}
}
public static Field[] getAllFields(Class type)
{
List list = new ArrayList();
getAllFields(list, type);
Field[] fl = new Field[list.size()];
for (int i = 0; i < list.size(); i++)
fl[i] = list.get(i);
return fl;
}
private static List getAllFields(List fields, Class type)
{
for (Field field : type.getDeclaredFields()) {
fields.add(field);
}
if (type.getSuperclass() != null) {
fields = getAllFields(fields, type.getSuperclass());
}
return fields;
}
// Class cache
private static Map> cache = new HashMap>();
/**
* Detect all the classes within a specified package or its subpackages.
*
* @param packageName
* the package name
* @return a set of classes
* @throws ClassNotFoundException
*/
public static Set findClasses(String packageName, Class type)
throws ClassNotFoundException
{
// Cache lookup
Set classes = cache.get(packageName);
if (classes == null) {
// Cache miss: Look for classes
List urls = null;
try {
urls = getResourceURL(packageName);
} catch (IOException e) {
Logger.getLogger(Reflection.class.getName()).log(Level.INFO,"Unable to get class resource URLs",e);
}
if (urls != null) {
for (URL url : urls) {
classes = new HashSet();
File directory = new File(url.getFile());
if (directory.exists()) { // class within the file system
String[] files = directory.list();
for (int i = 0; i < files.length; i++) {
if (files[i].endsWith(".class") && !files[i].contains("")) {
String classname = files[i].substring(0, files[i].length() - 6);
Class newClass = Reflection.getClass(packageName + "." + classname);
if (newClass != null)
classes.add(newClass);
} else {
classes.addAll(findClasses(packageName + "." + files[i], type));
}
}
} else { // class within a jar file
classes = findJarClasses(type);
}
}
}
// Cache update
cache.put(packageName, classes);
}
return classes;
}
/**
* Find classes in the same JAR file than the specified class.
*
* @param type
* the class
* @return classes in the JAR file
* @throws ClassNotFoundException
*/
private static Set findJarClasses(Class type)
throws ClassNotFoundException
{
Set classes = new HashSet();
JarInputStream jarFile;
try {
jarFile = new JarInputStream(
new FileInputStream(type.getProtectionDomain().getCodeSource().getLocation().toString().substring(5)));
try {
JarEntry e = jarFile.getNextJarEntry();
while (e != null) {
String entryname = e.getName();
if (entryname.endsWith(".class") && !entryname.contains("")) {
String classname = entryname.substring(0, entryname.length() - 6);
if (classname.startsWith("/")) {
classname = classname.substring(1);
}
classname = classname.replace('/', '.');
Class newClass = Reflection.getClass(classname);
if (newClass != null)
classes.add(newClass);
}
e = jarFile.getNextJarEntry();
}
} catch (IOException error) {
Logger.getLogger(Reflection.class.getName()).log(Level.INFO,"Unable to process class JAR entry",error);
}
jarFile.close();
} catch (IOException error) {
Logger.getLogger(Reflection.class.getName()).log(Level.INFO,"Unable to process JAR file",error);
}
return classes;
}
/**
* Detect all the classes that extend a class or implement an interface.
*
* @param type
* the class
* @return a set of subclasses
* @throws ClassNotFoundException
*/
public static Set findSubclasses(Class type)
throws ClassNotFoundException
{
String packageName = "";
if (type.getPackage() != null)
packageName = type.getPackage().getName();
return findSubclasses(packageName, type);
}
/**
* Detect all the classes that extend a class or implement an interface
* within a specified set of packages.
*
* @param packages
* the set of package names
* @param type
* the class
* @return a set of subclasses
* @throws ClassNotFoundException
*/
public static Set findSubclasses(Set packages, Class type)
throws ClassNotFoundException
{
Set subclasses = new HashSet();
for (String packageName : packages) {
subclasses.addAll(findSubclasses(packageName, type));
}
return subclasses;
}
/**
* Detect all the classes that extend a class or implement an interface
* within a specified package or its subpackages.
*
* @param packageName
* the package name
* @param type
* the class
* @return a set of subclasses
* @throws ClassNotFoundException
*/
public static Set findSubclasses(String packageName, Class type)
throws ClassNotFoundException
{
Set classes = findClasses(packageName, type);
Set subclasses = new HashSet();
for (Class candidate : classes) {
if (type.isAssignableFrom(candidate) && !type.equals(candidate)) {
subclasses.add(candidate);
}
}
return subclasses;
}
private static List getResourceURL(String packageName)
throws IOException
{
String name = packageName;
name = name.replace('.', '/');
Enumeration resources = Thread.currentThread().getContextClassLoader().getResources(name);
List results = new ArrayList<>();
while (resources.hasMoreElements()) {
results.add(resources.nextElement());
}
return results;
}
public static boolean hasConstructor(Class elementClass)
{
try {
if (elementClass.getConstructor() != null)
return true;
} catch (Exception e) {
}
return false;
}
/**
* Checks whether a class (or one of its members) has a given annotation
*
* @param type
* the class
* @param annotation
* the annotation
* @return true if it has a pattern or value annotation, false otherwise
*/
public static boolean hasAnnotation(Class type, Class annotation)
{
if (type.isAnnotationPresent(annotation))
return true;
else {
Field fl[] = type.getDeclaredFields();
int i;
for (i = 0; i < fl.length; i++) {
if (fl[i].isAnnotationPresent(annotation)) {
return true;
}
}
return false;
}
}
/**
* Returns an element type
*
* @param collection
* the collection type (null if no collection)
* @param field
* the field
* @return the component type
*/
public static Class getType(MemberCollectionType collection, Field field)
{
if (collection == null)
return field.getType();
switch (collection) {
case ARRAY:
return field.getType().getComponentType();
case LIST:
case SET:
String name = field.getType().getName();
String fname = field.getGenericType().toString();
int ini = name.length() + 1;
int fin = fname.length() - 1;
if (ini < fin && fname.endsWith(">")) {
try {
return Reflection.getClass(fname.substring(ini, fin));
} catch (ClassNotFoundException ex) {
return null;
}
}
}
return null;
}
/**
* Obtain the Class object corresponding to a primitive or non-primitive
* type name.
*
* @param className
* the class name
* @return the Class object
* @throws ClassNotFoundException
*/
public static Class getClass(String className)
throws ClassNotFoundException
{
if (!className.contains(".")) {
if ("int".equals(className))
return int.class;
if ("long".equals(className))
return long.class;
if ("byte".equals(className))
return byte.class;
if ("short".equals(className))
return short.class;
if ("float".equals(className))
return float.class;
if ("double".equals(className))
return double.class;
if ("boolean".equals(className))
return boolean.class;
if ("char".equals(className))
return char.class;
}
return Class.forName(className);
}
}