Is it possible to determine descendants solely through Java reflection API? [duplicate] - java
How does one go about and try to find all subclasses of a given class (or all implementors of a given interface) in Java?
As of now, I have a method to do this, but I find it quite inefficient (to say the least).
The method is:
Get a list of all class names that exist on the class path
Load each class and test to see if it is a subclass or implementor of the desired class or interface
In Eclipse, there is a nice feature called the Type Hierarchy that manages to show this quite efficiently.
How does one go about and do it programmatically?
Scanning for classes is not easy with pure Java.
The spring framework offers a class called ClassPathScanningCandidateComponentProvider that can do what you need. The following example would find all subclasses of MyClass in the package org.example.package
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class));
// scan in org.example.package
Set<BeanDefinition> components = provider.findCandidateComponents("org/example/package");
for (BeanDefinition component : components)
{
Class cls = Class.forName(component.getBeanClassName());
// use class cls found
}
This method has the additional benefit of using a bytecode analyzer to find the candidates which means it will not load all classes it scans.
There is no other way to do it other than what you described. Think about it - how can anyone know what classes extend ClassX without scanning each class on the classpath?
Eclipse can only tell you about the super and subclasses in what seems to be an "efficient" amount of time because it already has all of the type data loaded at the point where you press the "Display in Type Hierarchy" button (since it is constantly compiling your classes, knows about everything on the classpath, etc).
This is not possible to do using only the built-in Java Reflections API.
A project exists that does the necessary scanning and indexing of your classpath so you can get access this information...
Reflections
A Java runtime metadata analysis, in the spirit of Scannotations
Reflections scans your classpath, indexes the metadata, allows you to query it on runtime and may save and collect that information for many modules within your project.
Using Reflections you can query your metadata for:
get all subtypes of some type
get all types annotated with some annotation
get all types annotated with some annotation, including annotation parameters matching
get all methods annotated with some
(disclaimer: I have not used it, but the project's description seems to be an exact fit for your needs.)
Try ClassGraph. (Disclaimer, I am the author). ClassGraph supports scanning for subclasses of a given class, either at runtime or at build time, but also much more. ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in selected packages, and you can query this class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.
Don't forget that the generated Javadoc for a class will include a list of known subclasses (and for interfaces, known implementing classes).
I know I'm a few years late to this party, but I came across this question trying to solve the same problem. You can use Eclipse's internal searching programatically, if you're writing an Eclipse Plugin (and thus take advantage of their caching, etc), to find classes which implement an interface. Here's my (very rough) first cut:
protected void listImplementingClasses( String iface ) throws CoreException
{
final IJavaProject project = <get your project here>;
try
{
final IType ifaceType = project.findType( iface );
final SearchPattern ifacePattern = SearchPattern.createPattern( ifaceType, IJavaSearchConstants.IMPLEMENTORS );
final IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
final SearchEngine searchEngine = new SearchEngine();
final LinkedList<SearchMatch> results = new LinkedList<SearchMatch>();
searchEngine.search( ifacePattern,
new SearchParticipant[]{ SearchEngine.getDefaultSearchParticipant() }, scope, new SearchRequestor() {
#Override
public void acceptSearchMatch( SearchMatch match ) throws CoreException
{
results.add( match );
}
}, new IProgressMonitor() {
#Override
public void beginTask( String name, int totalWork )
{
}
#Override
public void done()
{
System.out.println( results );
}
#Override
public void internalWorked( double work )
{
}
#Override
public boolean isCanceled()
{
return false;
}
#Override
public void setCanceled( boolean value )
{
}
#Override
public void setTaskName( String name )
{
}
#Override
public void subTask( String name )
{
}
#Override
public void worked( int work )
{
}
});
} catch( JavaModelException e )
{
e.printStackTrace();
}
}
The first problem I see so far is that I'm only catching classes which directly implement the interface, not all their subclasses - but a little recursion never hurt anyone.
I did this several years ago. The most reliable way to do this (i.e. with official Java APIs and no external dependencies) is to write a custom doclet to produce a list that can be read at runtime.
You can run it from the command line like this:
javadoc -d build -doclet com.example.ObjectListDoclet -sourcepath java/src -subpackages com.example
or run it from ant like this:
<javadoc sourcepath="${src}" packagenames="*" >
<doclet name="com.example.ObjectListDoclet" path="${build}"/>
</javadoc>
Here's the basic code:
public final class ObjectListDoclet {
public static final String TOP_CLASS_NAME = "com.example.MyClass";
/** Doclet entry point. */
public static boolean start(RootDoc root) throws Exception {
try {
ClassDoc topClassDoc = root.classNamed(TOP_CLASS_NAME);
for (ClassDoc classDoc : root.classes()) {
if (classDoc.subclassOf(topClassDoc)) {
System.out.println(classDoc);
}
}
return true;
}
catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
}
For simplicity, I've removed command line argument parsing and I'm writing to System.out rather than a file.
Keeping in mind the limitations mentioned in the other answers, you can also use openpojo's PojoClassFactory (available on Maven) in the following manner:
for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(packageRoot, Superclass.class, null)) {
System.out.println(pojoClass.getClazz());
}
Where packageRoot is the root String of the packages you wish to search in (e.g. "com.mycompany" or even just "com"), and Superclass is your supertype (this works on interfaces as well).
Depending on your particular requirements, in some cases Java's service loader mechanism might achieve what you're after.
In short, it allows developers to explicitly declare that a class subclasses some other class (or implements some interface) by listing it in a file in the JAR/WAR file's META-INF/services directory. It can then be discovered using the java.util.ServiceLoader class which, when given a Class object, will generate instances of all the declared subclasses of that class (or, if the Class represents an interface, all the classes implementing that interface).
The main advantage of this approach is that there is no need to manually scan the entire classpath for subclasses - all the discovery logic is contained within the ServiceLoader class, and it only loads the classes explicitly declared in the META-INF/services directory (not every class on the classpath).
There are, however, some disadvantages:
It won't find all subclasses, only those that are explicitly declared. As such, if you need to truly find all subclasses, this approach may be insufficient.
It requires the developer to explicitly declare the class under the META-INF/services directory. This is an additional burden on the developer, and can be error-prone.
The ServiceLoader.iterator() generates subclass instances, not their Class objects. This causes two issues:
You don't get any say on how the subclasses are constructed - the no-arg constructor is used to create the instances.
As such, the subclasses must have a default constructor, or must explicity declare a no-arg constructor.
Apparently Java 9 will be addressing some of these shortcomings (in particular, the ones regarding instantiation of subclasses).
An Example
Suppose you're interested in finding classes that implement an interface com.example.Example:
package com.example;
public interface Example {
public String getStr();
}
The class com.example.ExampleImpl implements that interface:
package com.example;
public class ExampleImpl implements Example {
public String getStr() {
return "ExampleImpl's string.";
}
}
You would declare the class ExampleImpl is an implementation of Example by creating a file META-INF/services/com.example.Example containing the text com.example.ExampleImpl.
Then, you could obtain an instance of each implementation of Example (including an instance of ExampleImpl) as follows:
ServiceLoader<Example> loader = ServiceLoader.load(Example.class)
for (Example example : loader) {
System.out.println(example.getStr());
}
// Prints "ExampleImpl's string.", plus whatever is returned
// by other declared implementations of com.example.Example.
It should be noted as well that this will of course only find all those subclasses that exist on your current classpath. Presumably this is OK for what you are currently looking at, and chances are you did consider this, but if you have at any point released a non-final class into the wild (for varying levels of "wild") then it is entirely feasible that someone else has written their own subclass that you will not know about.
Thus if you happened to be wanting to see all subclasses because you want to make a change and are going to see how it affects subclasses' behaviour - then bear in mind the subclasses that you can't see. Ideally all of your non-private methods, and the class itself should be well-documented; make changes according to this documentation without changing the semantics of methods/non-private fields and your changes should be backwards-compatible, for any subclass that followed your definition of the superclass at least.
The reason you see a difference between your implementation and Eclipse is because you scan each time, while Eclipse (and other tools) scan only once (during project load most of the times) and create an index. Next time you ask for the data it doesn't scan again, but look at the index.
I'm using a reflection lib, which scans your classpath for all subclasses: https://github.com/ronmamo/reflections
This is how it would be done:
Reflections reflections = new Reflections("my.project");
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);
You can use org.reflections library and then, create an object of Reflections class. Using this object, you can get list of all subclasses of given class.
https://www.javadoc.io/doc/org.reflections/reflections/0.9.10/org/reflections/Reflections.html
Reflections reflections = new Reflections("my.project.prefix");
System.out.println(reflections.getSubTypesOf(A.class)));
Add them to a static map inside (this.getClass().getName()) the parent classes constructor (or create a default one) but this will get updated in runtime. If lazy initialization is an option you can try this approach.
I just write a simple demo to use the org.reflections.Reflections to get subclasses of abstract class:
https://github.com/xmeng1/ReflectionsDemo
I needed to do this as a test case, to see if new classes had been added to the code. This is what I did
final static File rootFolder = new File(SuperClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
private static ArrayList<String> files = new ArrayList<String>();
listFilesForFolder(rootFolder);
#Test(timeout = 1000)
public void testNumberOfSubclasses(){
ArrayList<String> listSubclasses = new ArrayList<>(files);
listSubclasses.removeIf(s -> !s.contains("Superclass.class"));
for(String subclass : listSubclasses){
System.out.println(subclass);
}
assertTrue("You did not create a new subclass!", listSubclasses.size() >1);
}
public static void listFilesForFolder(final File folder) {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
files.add(fileEntry.getName().toString());
}
}
}
If you intend to load all subclassess of given class which are in the same package, you can do so:
public static List<Class> loadAllSubClasses(Class pClazz) throws IOException, ClassNotFoundException {
ClassLoader classLoader = pClazz.getClassLoader();
assert classLoader != null;
String packageName = pClazz.getPackage().getName();
String dirPath = packageName.replace(".", "/");
Enumeration<URL> srcList = classLoader.getResources(dirPath);
List<Class> subClassList = new ArrayList<>();
while (srcList.hasMoreElements()) {
File dirFile = new File(srcList.nextElement().getFile());
File[] files = dirFile.listFiles();
if (files != null) {
for (File file : files) {
String subClassName = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
if (! subClassName.equals(pClazz.getName())) {
subClassList.add(Class.forName(subClassName));
}
}
}
}
return subClassList;
}
find all classes in classpath
public static List<String> getClasses() {
URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
List<String> classes = new ArrayList<>();
for (URL url : urlClassLoader.getURLs()) {
try {
if (url.toURI().getScheme().equals("file")) {
File file = new File(url.toURI());
if (file.exists()) {
try {
if (file.isDirectory()) {
for (File listFile : FileUtils.listFiles(file, new String[]{"class"}, true)) {
String classFile = listFile.getAbsolutePath().replace(file.getAbsolutePath(), "").replace(".class", "");
if (classFile.startsWith(File.separator)) {
classFile = classFile.substring(1);
}
classes.add(classFile.replace(File.separator, "."));
}
} else {
JarFile jarFile = new JarFile(file);
if (url.getFile().endsWith(".jar")) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (jarEntry.getName().endsWith(".class")) {
classes.add(jarEntry.getName().replace(".class", "").replace("/", "."));
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
return classes;
}
enter link description hereService Manager in java will get all implementing classes for an interface in J
Related
Java reflection java.lang.ClassNotFoundException. Related to finding the full class name
I am currently trying to develop a method for invoking a specific class. The problem I am having is that I need to get the fully-qualified name or full class name when I invoke the class. public static void testAlgorithm(String className, String methodName, long n) throws Exception { Class<?> myClass = null; Object myObject = null; try { myClass = Class.forName(className); myObject = myClass.newInstance(); Class<?>[] params = new Class[1]; params[0]=Long.TYPE; Method m = myClass.getMethod(methodName, params); m.invoke(myObject, n); }catch(Throwable e) { System.err.println(e); } } I call it from main try { testAlgorithm("Algorithms", "linear", 50); } catch (Exception e) { e.printStackTrace(); } I tried passing different arguments for className and I also directly modified the method inside to try to get the full class name but I didn't get anything to work. I have the class in the same project file Session01 and in the same package as well lab01. I also checked out a similar question here. And it leed me to also trying out: Class currentClass = new Object() {}.getClass().getEnclosingClass(); inside the Algorithms class but I don't get the java.lang.String that I need to use for the method I am working on.
If you just want to invoke method on given class - you can always refer to it using .class so you could change parameter of your method from String className to Class<?> myClass and simply remove Class<?> myClass = null; from your method's body. However, if you want to keep your method's signature as it is and find a class by its simple name instead of fully-qualified name - you can also do this. I could suggest usage of https://github.com/ronmamo/reflections which makes things a lot easier. Then you can find your class using code like this: Set<Class<? extends Object>> classes = new Reflections("packageName").getSubTypesOf(Object.class); Class<?> myClass = classes.stream().filter(clazz -> clazz.getSimpleName().equals(className)) .findAny() .orElseThrow(() -> new IllegalArgumentException("No class with name: " + className)); Keep in mind that you need to replace "packageName" with root package where you want to scan classes so only classes inside this package or its subpackages will be found. The less classes in a package - the faster will be the scan but you need to make sure that you class will be in the package. Also keep in mind that you can have multiple classes with same name in different packages - this method will any of them. You can change this behaviour if you need. You can also restrict classes to subtype of more concrete class than Object.class.
Is it possible to fake missing classes using ClassLoader?
I'm loading in classes from a JAR that implement an interface from a public API. The interface itself will remain constant but other classes associated with the API may change over time. Clearly once the API changes we will no longer be able to support implementations of the interface that were written with the old version. However some of the interface methods provide simple meta-data of type String that we can assume will never change and never rely on the other parts of the API that may change. I would like to be able to extract this meta-data even when the API has changed. For example consider the following implementation that might be loaded in where Foo is the interface and Bar is an another class in the API. I want to call the name method even when the class Bar no longer exists. class MyFoo implements Foo { Bar bar = null; #Override public String name() { return "MyFoo" } } As far as I can see the obvious approach is to override loadClass(String name) in my custom ClassLoader and return some "fake" class for Bar. The meta-data methods can be assumed to never create or use a Bar object. The question is how to generate this "fake" class when asked to load Bar. I've thought about the following approaches: Simply return any old existing class. I've tried returning Object.class but this still results in a NoClassDefFoundError for Bar when I try to instantiate an instance of Foo. Use ASM to generate the byte code for a new class from scratch. Use ASM to rename some sort of empty template class to match Bar and load that. Both 2. and 3. seem quite involved, so I was wondering if there was an easier way to achieve my goal?
Here is a class loader which will create a dummy class for every class it didn’t find on the search path, in a very simple way: public class DummyGeneratorLoader extends URLClassLoader { public DummyGeneratorLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } public DummyGeneratorLoader(URL[] urls) { super(urls); } public DummyGeneratorLoader( URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { super(urls, parent, factory); } static final byte[] template = ("Êþº¾\0\0\0002\0\n\1\7\0\1\1\0\20java/lang/Object" + "\7\0\3\1\0\6<init>\1\0\3()V\14\0\5\0\6\n\0\4\0\7\1\0\4Code\0\1\0\2\0\4\0" + "\0\0\0\0\1\0\1\0\5\0\6\0\1\0\t\0\0\0\21\0\1\0\1\0\0\0\5*·\0\b±\0\0\0\0\0\0") .getBytes(StandardCharsets.ISO_8859_1); #Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { return super.findClass(name); } catch(ClassNotFoundException ex) { } return new ByteArrayOutputStream(template.length + name.length() + 10) { { write(template, 0, 11); try { new DataOutputStream(this).writeUTF(name.replace('.', '/')); } catch (IOException ex) { throw new AssertionError(); } write(template, 11, template.length - 11); } Class<?> toClass(String name) { return defineClass(name, buf, 0, count); } }.toClass(name); } } However, there might be a lot of expectations or structural constraints imposed by the using code which the dummy class can’t fulfill. After all, before you can invoke the interface method, you have to create an instance of the class, so it has to pass verification and a successful execution of its constructor. If the methods truly have the assumed structure like public String name() { return "MyFoo"; } using ASM may be the simpler choice, but not to generate an arbitrarily complex fake environment, but to parse these methods and predict the constant value they’d return. Such a method would consist of two instructions only, ldc value and areturn. You only need to check that this is the case and extract the value from the first instruction.
JAXB bind subclasses dynamically
I have sort of a deep class hierarchy and i want to tell JAXB to bind all the classes. I have sort of the following : #XmlSeeAlso(B.class) Class A {} #XmlSeeAlso(C.class) Class B extends A{} #XmlSeeAlso(D.class,E.class,...) Class C extends B{} Class D extends C{}; Class E extends C{} ... and so on Is there any way i can get to bind all these classes without using the #XmlSeeAlso in every super class and without mentioning all subclasses because i have many.
As mentioned in comments, Java doesn't support requested feature of getting all subclasses at runtime viaa reflection. But it should be possible to inspect all classes in a project at it's compilation time, and generate a jaxb.index in your jar file. An example (not complete, thus not directly working, but to demonstrate the idea) of such annotation processor can look like this: #SupportedAnnotationTypes("*") #SupportedSourceVersion(SourceVersion.RELEASE_8) public class JaxbProcessor extends AbstractProcessor { #Override public synchronized void init(ProcessingEnvironment env) { super.init(env); // Java 8 compiler plugin API to hook on compilation of every single class. JavacTask.instance(env).addTaskListener(new TaskListener() { // Prepare the writer PrintWriter writer = new PrintWriter(env.getFiler().createResource(/* Details of output jaxb.index file */).openWriter()); Set<TypeElement> jaxbParents = new HashSet<>(); #Override public void started(TaskEvent taskEvent) { // Nothing needs to be done here. } #Override public void finished(TaskEvent taskEvent) { if(taskEvent.getKind() == ANALYZE) { // This is where the compiler invokes our code. // Side effect of this inspection is to collect all classes, that should be included in our jaxb.index // into the jaxbParents set. inspect(taskEvent.getTypeElement()); // Now simply write it to the file (output details to be provided). // We should actually only write down difference from previous invocation. Let me fix it later. jaxbParents.forEach(writer::println); } } private void inspect(TypeElement type) { // First inspect current class element testForJaxbParent(type); // Do not forget to inspect also inner classes. type.getEnclosedElements().stream().filter(TypeElement.class::isInstance).map(TypeElement.class::cast).forEach(this::testForJaxbParent); } /** * Test if the type should be added to JAXB index file. */ private boolean testForJaxbParent(TypeElement type) { if(jaxbParents.contains(type)) { // It's already in the set, so no need to bother with it. return true; } if(type.getAnnotation(JaxbRoot.class) != null || testForJaxbParent((TypeElement) env.getTypeUtils().asElement(type.getSuperclass()))) { // If our type is annotated with our special "extension" to JAXB - JaxbRoot, it means, that it is our // root class, that needs to be added to the jaxb.index. // // If it is not annotated, then still test hierarchy of superclasses recursively, and if there is any // superclass being the root, then add it including all children on the stack at the return from the // recursion. return jaxbParents.add(type); } return false; } }); } #Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { // No real annotation processing needed. return false; } } Once you have the annotation JaxbRoot and this processor in a jar, and ideally also the service descriptor to let Java automatically find this processor in the jar, then simply add the jar to your classpath, annotate only your root class, and you'll get generated jaxb.index with all it's subclasses. And even if you have your project split into multiple jars, and have your root class in one, and children in another, still the processor get's invoked and generates the index file per jar. Then you'll just have to merge them all together, which can be just one utility class delivered together with the processor.
How to get a list of all implemented classes in Strategy Pattern?
I want to design a system that allows the user to select from a list of file types to save the file as. I have a class named Word, and an interface named SaveFileType. Every filetype implements SaveFileType which has a saveFile() method. The idea is that when the 'programmer' wants to add a new filetype, none of the code in the application has to be changed. This is the UML diagram I have made: The problem that I am facing is the Word class doesn't have the list of all available file types, that I need to display to the user. Some sample code below: Word class: public class Word { SaveFileAs saveFileAs; Document currentDocument; public Word(Document currentDocument) { this.currentDocument = currentDocument; } public void saveFile() { // Print all available filetypes // No actual file-saving logic is needed. } } Word97 Class: public class Word97 implements SaveFileAs { #Override public void saveFile(Document currentDocument) { // Do some Java wizardry here. System.out.println("Document named '" + currentDocument.getTitle() + "' has been saved as filetype 'Word97' " ); } } Main class: public class Main { public static void main(String[] args) { Document notes = new Document("Notes", "This is a note."); Word wordProgram = new Word(notes); // saveFile should print out a list of all possible filetypes. wordProgram.saveFile(); } }
Strategy is for changing implementation at runtime, you cannot get all implementations. It would be the task of another class. Also you need somehow a method like setStrategy(Strategy) in your Word class, that's why you've chosen the pattern right? For get all implementations, you could make use of ServiceLoader. I would add an enum in the picture. So the example codes look like: method in Word class: void setSaveFileStrategy(AvailableStrategy strategy){ this.saveFileAs = strategy.strategy(); } The enum: enum AvailableStrategy{ Word97( Word97.class), //.... once new strategy was introduced, you need add an entry here. WordXml( WordXml.class); private Class<saveFileAs> strategyClass; AvailableStrategies(Class<saveFileAs> strategyClass) { this.strategyClass = strategyClass; } saveFileAs strategy() throws IllegalAccessException, InstantiationException { return strategyClass.newInstance() ; } } I think you know how to get all enum instances (available strategies). Note that codes were not compiled and tested, just for showing the idea. Exception handlings were ignored.
It would be bad if the Word class knew about all the types. It's the job of another class, even if word uses it. One solution would be to have a new class that maps a string extension to the strategy. And can enumerate those strategies: public final class DocumentTypeMap implements Iterable<SaveFileAs> { private final Map<String, SaveFileAs> docTypes = new HashMap<>; public void register(String extension, SaveFileAs saveFileAs) { docTypes.put(extension, saveFileAs); } public Iterator<SaveFileAs> iterator() { return docTypes.values().iterator(); } } Usage: DocumentTypeMap map = new DocumentTypeMap(); map.register(".doc", new Word97()); //etc. Word word = new Word(map); //inject the dependency of a pre-configured map into the word class. Then when the Word class needs the correct strategy during saving, it can use a method on DocumentTypeMap (not provided here) to get the correct one. I'm thinking that might be by extension.
If you want to be able to add a document type without changing any code, it means that the document type list has to be defined outside your code, in file like a property file and your code has to read the property file to know all available types. Then you need to add in this property file which class implements how to save a specific document type and you implement a factory which instantiate a class given its name, and a class which associate the right instance according to the chosen type. For the properties files, you can have entries like: ext_1=.doc ext_2=.xml ext_3=.rtf class_1=Word97 class_2=WordXML class_3=RTF ... A such file is easy to parse to know the types list and which class has to be used to save a document. To know how to instantiate a class from its name, see the class Class and the method newInstance. This is an "old way", maybe with injection is there a most up to date solution. In your UML model, I would add the class which reads the properties file, the class which instantiates a class from its name, and the class which associate the right instance to Word. To model the properties file, maybe an instance objet may be use since a properties file is an instance of ResourceBundle.
How do you find all subclasses of a given class in Java?
How does one go about and try to find all subclasses of a given class (or all implementors of a given interface) in Java? As of now, I have a method to do this, but I find it quite inefficient (to say the least). The method is: Get a list of all class names that exist on the class path Load each class and test to see if it is a subclass or implementor of the desired class or interface In Eclipse, there is a nice feature called the Type Hierarchy that manages to show this quite efficiently. How does one go about and do it programmatically?
Scanning for classes is not easy with pure Java. The spring framework offers a class called ClassPathScanningCandidateComponentProvider that can do what you need. The following example would find all subclasses of MyClass in the package org.example.package ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class)); // scan in org.example.package Set<BeanDefinition> components = provider.findCandidateComponents("org/example/package"); for (BeanDefinition component : components) { Class cls = Class.forName(component.getBeanClassName()); // use class cls found } This method has the additional benefit of using a bytecode analyzer to find the candidates which means it will not load all classes it scans.
There is no other way to do it other than what you described. Think about it - how can anyone know what classes extend ClassX without scanning each class on the classpath? Eclipse can only tell you about the super and subclasses in what seems to be an "efficient" amount of time because it already has all of the type data loaded at the point where you press the "Display in Type Hierarchy" button (since it is constantly compiling your classes, knows about everything on the classpath, etc).
This is not possible to do using only the built-in Java Reflections API. A project exists that does the necessary scanning and indexing of your classpath so you can get access this information... Reflections A Java runtime metadata analysis, in the spirit of Scannotations Reflections scans your classpath, indexes the metadata, allows you to query it on runtime and may save and collect that information for many modules within your project. Using Reflections you can query your metadata for: get all subtypes of some type get all types annotated with some annotation get all types annotated with some annotation, including annotation parameters matching get all methods annotated with some (disclaimer: I have not used it, but the project's description seems to be an exact fit for your needs.)
Try ClassGraph. (Disclaimer, I am the author). ClassGraph supports scanning for subclasses of a given class, either at runtime or at build time, but also much more. ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in selected packages, and you can query this class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.
Don't forget that the generated Javadoc for a class will include a list of known subclasses (and for interfaces, known implementing classes).
I know I'm a few years late to this party, but I came across this question trying to solve the same problem. You can use Eclipse's internal searching programatically, if you're writing an Eclipse Plugin (and thus take advantage of their caching, etc), to find classes which implement an interface. Here's my (very rough) first cut: protected void listImplementingClasses( String iface ) throws CoreException { final IJavaProject project = <get your project here>; try { final IType ifaceType = project.findType( iface ); final SearchPattern ifacePattern = SearchPattern.createPattern( ifaceType, IJavaSearchConstants.IMPLEMENTORS ); final IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); final SearchEngine searchEngine = new SearchEngine(); final LinkedList<SearchMatch> results = new LinkedList<SearchMatch>(); searchEngine.search( ifacePattern, new SearchParticipant[]{ SearchEngine.getDefaultSearchParticipant() }, scope, new SearchRequestor() { #Override public void acceptSearchMatch( SearchMatch match ) throws CoreException { results.add( match ); } }, new IProgressMonitor() { #Override public void beginTask( String name, int totalWork ) { } #Override public void done() { System.out.println( results ); } #Override public void internalWorked( double work ) { } #Override public boolean isCanceled() { return false; } #Override public void setCanceled( boolean value ) { } #Override public void setTaskName( String name ) { } #Override public void subTask( String name ) { } #Override public void worked( int work ) { } }); } catch( JavaModelException e ) { e.printStackTrace(); } } The first problem I see so far is that I'm only catching classes which directly implement the interface, not all their subclasses - but a little recursion never hurt anyone.
I did this several years ago. The most reliable way to do this (i.e. with official Java APIs and no external dependencies) is to write a custom doclet to produce a list that can be read at runtime. You can run it from the command line like this: javadoc -d build -doclet com.example.ObjectListDoclet -sourcepath java/src -subpackages com.example or run it from ant like this: <javadoc sourcepath="${src}" packagenames="*" > <doclet name="com.example.ObjectListDoclet" path="${build}"/> </javadoc> Here's the basic code: public final class ObjectListDoclet { public static final String TOP_CLASS_NAME = "com.example.MyClass"; /** Doclet entry point. */ public static boolean start(RootDoc root) throws Exception { try { ClassDoc topClassDoc = root.classNamed(TOP_CLASS_NAME); for (ClassDoc classDoc : root.classes()) { if (classDoc.subclassOf(topClassDoc)) { System.out.println(classDoc); } } return true; } catch (Exception ex) { ex.printStackTrace(); return false; } } } For simplicity, I've removed command line argument parsing and I'm writing to System.out rather than a file.
Keeping in mind the limitations mentioned in the other answers, you can also use openpojo's PojoClassFactory (available on Maven) in the following manner: for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(packageRoot, Superclass.class, null)) { System.out.println(pojoClass.getClazz()); } Where packageRoot is the root String of the packages you wish to search in (e.g. "com.mycompany" or even just "com"), and Superclass is your supertype (this works on interfaces as well).
Depending on your particular requirements, in some cases Java's service loader mechanism might achieve what you're after. In short, it allows developers to explicitly declare that a class subclasses some other class (or implements some interface) by listing it in a file in the JAR/WAR file's META-INF/services directory. It can then be discovered using the java.util.ServiceLoader class which, when given a Class object, will generate instances of all the declared subclasses of that class (or, if the Class represents an interface, all the classes implementing that interface). The main advantage of this approach is that there is no need to manually scan the entire classpath for subclasses - all the discovery logic is contained within the ServiceLoader class, and it only loads the classes explicitly declared in the META-INF/services directory (not every class on the classpath). There are, however, some disadvantages: It won't find all subclasses, only those that are explicitly declared. As such, if you need to truly find all subclasses, this approach may be insufficient. It requires the developer to explicitly declare the class under the META-INF/services directory. This is an additional burden on the developer, and can be error-prone. The ServiceLoader.iterator() generates subclass instances, not their Class objects. This causes two issues: You don't get any say on how the subclasses are constructed - the no-arg constructor is used to create the instances. As such, the subclasses must have a default constructor, or must explicity declare a no-arg constructor. Apparently Java 9 will be addressing some of these shortcomings (in particular, the ones regarding instantiation of subclasses). An Example Suppose you're interested in finding classes that implement an interface com.example.Example: package com.example; public interface Example { public String getStr(); } The class com.example.ExampleImpl implements that interface: package com.example; public class ExampleImpl implements Example { public String getStr() { return "ExampleImpl's string."; } } You would declare the class ExampleImpl is an implementation of Example by creating a file META-INF/services/com.example.Example containing the text com.example.ExampleImpl. Then, you could obtain an instance of each implementation of Example (including an instance of ExampleImpl) as follows: ServiceLoader<Example> loader = ServiceLoader.load(Example.class) for (Example example : loader) { System.out.println(example.getStr()); } // Prints "ExampleImpl's string.", plus whatever is returned // by other declared implementations of com.example.Example.
It should be noted as well that this will of course only find all those subclasses that exist on your current classpath. Presumably this is OK for what you are currently looking at, and chances are you did consider this, but if you have at any point released a non-final class into the wild (for varying levels of "wild") then it is entirely feasible that someone else has written their own subclass that you will not know about. Thus if you happened to be wanting to see all subclasses because you want to make a change and are going to see how it affects subclasses' behaviour - then bear in mind the subclasses that you can't see. Ideally all of your non-private methods, and the class itself should be well-documented; make changes according to this documentation without changing the semantics of methods/non-private fields and your changes should be backwards-compatible, for any subclass that followed your definition of the superclass at least.
The reason you see a difference between your implementation and Eclipse is because you scan each time, while Eclipse (and other tools) scan only once (during project load most of the times) and create an index. Next time you ask for the data it doesn't scan again, but look at the index.
I'm using a reflection lib, which scans your classpath for all subclasses: https://github.com/ronmamo/reflections This is how it would be done: Reflections reflections = new Reflections("my.project"); Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);
You can use org.reflections library and then, create an object of Reflections class. Using this object, you can get list of all subclasses of given class. https://www.javadoc.io/doc/org.reflections/reflections/0.9.10/org/reflections/Reflections.html Reflections reflections = new Reflections("my.project.prefix"); System.out.println(reflections.getSubTypesOf(A.class)));
Add them to a static map inside (this.getClass().getName()) the parent classes constructor (or create a default one) but this will get updated in runtime. If lazy initialization is an option you can try this approach.
I just write a simple demo to use the org.reflections.Reflections to get subclasses of abstract class: https://github.com/xmeng1/ReflectionsDemo
I needed to do this as a test case, to see if new classes had been added to the code. This is what I did final static File rootFolder = new File(SuperClass.class.getProtectionDomain().getCodeSource().getLocation().getPath()); private static ArrayList<String> files = new ArrayList<String>(); listFilesForFolder(rootFolder); #Test(timeout = 1000) public void testNumberOfSubclasses(){ ArrayList<String> listSubclasses = new ArrayList<>(files); listSubclasses.removeIf(s -> !s.contains("Superclass.class")); for(String subclass : listSubclasses){ System.out.println(subclass); } assertTrue("You did not create a new subclass!", listSubclasses.size() >1); } public static void listFilesForFolder(final File folder) { for (final File fileEntry : folder.listFiles()) { if (fileEntry.isDirectory()) { listFilesForFolder(fileEntry); } else { files.add(fileEntry.getName().toString()); } } }
If you intend to load all subclassess of given class which are in the same package, you can do so: public static List<Class> loadAllSubClasses(Class pClazz) throws IOException, ClassNotFoundException { ClassLoader classLoader = pClazz.getClassLoader(); assert classLoader != null; String packageName = pClazz.getPackage().getName(); String dirPath = packageName.replace(".", "/"); Enumeration<URL> srcList = classLoader.getResources(dirPath); List<Class> subClassList = new ArrayList<>(); while (srcList.hasMoreElements()) { File dirFile = new File(srcList.nextElement().getFile()); File[] files = dirFile.listFiles(); if (files != null) { for (File file : files) { String subClassName = packageName + '.' + file.getName().substring(0, file.getName().length() - 6); if (! subClassName.equals(pClazz.getName())) { subClassList.add(Class.forName(subClassName)); } } } } return subClassList; }
find all classes in classpath public static List<String> getClasses() { URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader(); List<String> classes = new ArrayList<>(); for (URL url : urlClassLoader.getURLs()) { try { if (url.toURI().getScheme().equals("file")) { File file = new File(url.toURI()); if (file.exists()) { try { if (file.isDirectory()) { for (File listFile : FileUtils.listFiles(file, new String[]{"class"}, true)) { String classFile = listFile.getAbsolutePath().replace(file.getAbsolutePath(), "").replace(".class", ""); if (classFile.startsWith(File.separator)) { classFile = classFile.substring(1); } classes.add(classFile.replace(File.separator, ".")); } } else { JarFile jarFile = new JarFile(file); if (url.getFile().endsWith(".jar")) { Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry jarEntry = entries.nextElement(); if (jarEntry.getName().endsWith(".class")) { classes.add(jarEntry.getName().replace(".class", "").replace("/", ".")); } } } } } catch (IOException e) { e.printStackTrace(); } } } } catch (URISyntaxException e) { e.printStackTrace(); } } return classes; }
enter link description hereService Manager in java will get all implementing classes for an interface in J