// Class you need package com.luna.lib.reflection; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import com.luna.lib.loggers.BasicLogger; import com.luna.lib.loggers.enums.EnumLogType; public class ClassEnumerator { /** * Singleton instance */ private static volatile ClassEnumerator instance; /** * Returns the singleton instance creates one if the instance is null * * @return instance */ public static ClassEnumerator getInstance() { if( instance == null ) { BasicLogger.getInstance().setDebug( true ); instance = new ClassEnumerator(); } return instance; } /** * Parses a directory for jar files and class files * * Recurses through if necessary * * @param directory * directory to parse * @return class array */ public List< Class< ? >> getClassesFromExternalDirectory( final File directory ) { final List< Class< ? >> classes = new ArrayList< Class< ? >>(); for( final File file : directory.listFiles() ) { try { final ClassLoader classLoader = new URLClassLoader( new URL[ ] { file.toURI().toURL() }, /* this */directory.getClass().getClassLoader() ); if( file.getName().toLowerCase().trim().endsWith( ".class" ) ) { BasicLogger.getInstance().log( EnumLogType.DEBUG, file.getName() ); classes.add( classLoader.loadClass( file.getName().replace( ".class", "" ) .replace( "/", "." ) ) ); } if( file.getName().toLowerCase().trim().endsWith( ".jar" ) ) { classes.addAll( getClassesFromJar( file, classLoader ) ); } if( file.isDirectory() ) { classes.addAll( getClassesFromExternalDirectory( file ) ); } } catch( final MalformedURLException e ) { e.printStackTrace(); } catch( final ClassNotFoundException e ) { e.printStackTrace(); } } return classes; } /** * Returns the class array of all classes within a package * * @param classe * class to get code source location for * * @return class array */ public Class< ? >[ ] getClassesFromPackage( final Class< ? > classe ) { final List< Class< ? >> classes = new ArrayList< Class< ? >>(); URI uri = null; try { uri = classe.getProtectionDomain().getCodeSource().getLocation().toURI(); } catch( final URISyntaxException e ) { e.printStackTrace(); } if( uri == null ) { throw new RuntimeException( "No uri for " + classe.getProtectionDomain().getCodeSource().getLocation() ); } BasicLogger.getInstance().log( EnumLogType.DEBUG, "URI: " + uri.toString() ); classes.addAll( processDirectory( new File( uri ), "" ) ); return classes.toArray( new Class[ classes.size() ] ); } /** * Returns all class files inside a jar * * @param file * jar file * @param classLoader * classloader created previously using the jar file * @return class list */ public List< Class< ? >> getClassesFromJar( final File file, final ClassLoader classLoader ) { final List< Class< ? >> classes = new ArrayList< Class< ? >>(); try { final JarFile jarFile = new JarFile( file ); final Enumeration< JarEntry > enumeration = jarFile.entries(); while( enumeration.hasMoreElements() ) { final JarEntry jarEntry = enumeration.nextElement(); if( jarEntry.isDirectory() || !jarEntry.getName().toLowerCase().trim().endsWith( ".class" ) ) { continue; } classes.add( classLoader.loadClass( jarEntry.getName().replace( ".class", "" ) .replace( "/", "." ) ) ); } jarFile.close(); } catch( final IOException e ) { e.printStackTrace(); } catch( final ClassNotFoundException e ) { e.printStackTrace(); } return classes; } /** * Processes a directory and retrieves all classes from it and its * subdirectories * * Recurses if necessary * * @param directory * directory file to traverse * @return list of classes */ private List< Class< ? >> processDirectory( final File directory, final String append ) { final List< Class< ? >> classes = new ArrayList< Class< ? >>(); final String[ ] files = directory.list(); for( final String fileName : files ) { String className = null; if( fileName.endsWith( ".class" ) ) { className = append + '.' + fileName.replace( ".class", "" ); } if( className != null ) { classes.add( loadClass( className.substring( 1 ) ) ); } final File subdir = new File( directory, fileName ); if( subdir.isDirectory() ) { classes.addAll( processDirectory( subdir, append + "." + fileName ) ); } } return classes; } /** * Loads a class based upon the name * * @param className * name of class (.class is pre removed) * @return Class if it was loaded properly */ private Class< ? > loadClass( final String className ) { try { return Class.forName( className ); } catch( final ClassNotFoundException e ) { throw new RuntimeException( "Error loading class '" + className + "'" ); } } } // In your Module Manager class, use this to get the list of classes that are modules /** * Parses the class code source to get modules from the retrieved classes * * @param classe * class to get code source for * @return module array from package */ private Module[ ] getModulesFromPackage( final Class< ? > classe ) { final List< Module > modules = new ArrayList<>(); final Class< ? >[ ] classes = ClassEnumerator.getInstance().getClassesFromPackage( classe ); for ( final Class< ? > c : classes ) { if ( Module.class.isAssignableFrom( c ) && !c.equals( Module.class ) ) { try { modules.add( ( Module ) c.newInstance() ); } catch ( final InstantiationException e ) { e.printStackTrace(); } catch ( final IllegalAccessException e ) { e.printStackTrace(); } } } return modules.toArray( new Module[ modules.size() ] ); } // And then use the returned array to load your modules!