package org.dyndns.jkiddo.dmp.tools; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.annotation.Annotation; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableSet; public final class ReflectionsHelper { private ReflectionsHelper() throws InstantiationException { throw new InstantiationException("This class is not created for instantiation"); } public static ImmutableSet<Class<? extends Object>> getClasses(final String packageName, final Class<? extends Annotation> annotation) { try { return ImmutableSet.copyOf(FluentIterable.from(getClasses(packageName)).filter(new Predicate<Class<? extends Object>>() { @Override public boolean apply(Class<? extends Object> input) { return input.getAnnotation(annotation) != null ? true : false; } }).filter(Predicates.notNull())); } catch(Exception e) { throw new RuntimeException(e); } } /** * http://snippets.dzone.com/posts/show/4831 Scans all classes accessible from the context class loader which belong to the given package and subpackages. * * @param packageName * The base package * @return The classes * @throws Exception * @throws ClassNotFoundException */ private static List<Class<? extends Object>> getClasses(final String packageName) throws ClassNotFoundException, IOException { final ArrayList<Class<? extends Object>> classes = new ArrayList<>(); final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); assert classLoader != null; final String path = packageName.replace('.', '/'); final Enumeration<URL> resources = classLoader.getResources(path); while(resources.hasMoreElements()) { final URL resource = resources.nextElement(); final String protocol = resource.getProtocol(); if(protocol.equals("jar")) { classes.addAll(handleJar(resource)); } if(protocol.equals("file")) { classes.addAll(handleFile(resource, packageName)); } } return classes; } private static Collection<Class<? extends Object>> handleJar(final URL resource) { final Set<Class<? extends Object>> result = new HashSet<>(); final String fileName = resource.getFile(); final File file = new File(fileName.split("!")[0].replace("file:", "")); if(file.exists()) { JarFile jarFile = null; try { jarFile = new JarFile(file); final Enumeration<JarEntry> entries = jarFile.entries(); while(entries.hasMoreElements()) { String name = entries.nextElement().getName(); if(name.endsWith(".class")) { name = name.replace(".class", ""); name = name.replaceAll("/", "."); // replace / with . final Class<?> clazz = Class.forName(name); result.add(clazz); } } } catch(final Exception e) { throw new RuntimeException(e); } finally { try { jarFile.close(); } catch(final IOException e) { throw new RuntimeException(e); } } } return result; } private static Collection<Class<? extends Object>> handleFile(final URL resource, final String packageName) throws UnsupportedEncodingException, ClassNotFoundException { final String fileName = resource.getFile(); final String fileNameDecoded = URLDecoder.decode(fileName, "UTF-8"); final File file = new File(fileNameDecoded); return findClasses(file, packageName); } /** * http://snippets.dzone.com/posts/show/4831 Recursive method used to find all classes in a given directory and subdirs. * * @param directory * The base directory * @param packageName * The package name for classes found inside the base directory * @return The classes * @throws ClassNotFoundException */ private static List<Class<? extends Object>> findClasses(final File directory, final String packageName) throws ClassNotFoundException { final List<Class<? extends Object>> classes = new ArrayList<>(); if(!directory.exists()) { return classes; } final File[] files = directory.listFiles(); for(final File file : files) { final String fileName = file.getName(); if(file.isDirectory()) { assert !fileName.contains("."); classes.addAll(findClasses(file, packageName + "." + fileName)); } else if(fileName.endsWith(".class") && !fileName.contains("$")) { Class<? extends Object> _class; try { _class = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6)); } catch(final ExceptionInInitializerError e) { // happen, for example, in classes, which depend on // Spring to inject some beans, and which fail, // if dependency is not fulfilled _class = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6), false, Thread.currentThread().getContextClassLoader()); } classes.add(_class); } } return classes; } }