At Runtime, Find All Classes in a Java Application That Extend a Base Class

At runtime, find all classes in a Java application that extend a base class

I use org.reflections:

Reflections reflections = new Reflections("com.mycompany");    
Set<Class<? extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class);

Another example:

public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Reflections reflections = new Reflections("java.util");
Set<Class<? extends List>> classes = reflections.getSubTypesOf(java.util.List.class);
for (Class<? extends List> aClass : classes) {
System.out.println(aClass.getName());
if(aClass == ArrayList.class) {
List list = aClass.newInstance();
list.add("test");
System.out.println(list.getClass().getName() + ": " + list.size());
}
}
}

Automatically add a subclass to a list when it extends a superclass

You can use Reflections.

Reflections reflections = new Reflections("cz.milanhlinak.animal");
Set<Class<? extends Animal>> animals = reflections.getSubTypesOf(Animal.class);

See my example repository https://github.com/milanhlinak/62481200 where I use Reflections + Google Guice for dependency injection.

Using Reflections you can get all sub types of your Animal class and add them to Google Guice Multibinder. After that, you can inject them somewhere...

// cz.milanhlinak.Module.java
public class Module extends AbstractModule {

@Override
protected void configure() {

Reflections reflections = new Reflections("cz.milanhlinak.animal");
Set<Class<? extends Animal>> animals = reflections.getSubTypesOf(Animal.class);

Multibinder<Animal> animalBinder = Multibinder.newSetBinder(binder(), Animal.class);
animals.forEach(animal -> animalBinder.addBinding().to(animal));

bind(AnimalProvider.class).to(AnimalProviderImpl.class).in(Singleton.class);
}
}

// cz.milanhlinak.animal.Animal.java
public abstract class Animal {

private final String sound;

public Animal(String sound) {
this.sound = sound;
}

void makeSound() {
System.out.println(this.sound);
}
}

// cz.milanhlinak.animal.Dog.java
public class Dog extends Animal {

public Dog() {
super("Bark");
}
}

// cz.milanhlinak.animal.Cat.java
public class Cat extends Animal {

public Cat() {
super("Meow");
}
}

// cz.milanhlinak.animal.AnimalProvider.java
public interface AnimalProvider {

Set<Animal> getAnimals();
}

// cz.milanhlinak.animal.AnimalProviderImpl.java
public class AnimalProviderImpl implements AnimalProvider {

private final Set<Animal> animals;

@Inject
public AnimalProviderImpl(Set<Animal> animals) {
this.animals = animals;
}

@Override
public Set<Animal> getAnimals() {
return this.animals;
}
}

You can also check Google Guice - how to automatically add binding where I was looking for something similar, but based on custom annotations.

How can I know the classes that extend my base class at runtime?

Use reflection to get the loaded assemblies and then enumerate through all types that are a subclass of your base class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var types = new List<Type>();

foreach (var assembly in assemblies)
types.AddRange(assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(Animal))));

foreach (var item in types)
Console.WriteLine(item.Name);
}
}

class Animal { }

enum AllAnimals { Cat, Dog, Pig };
class Cat : Animal { }
class Dog : Animal { }
class Pig : Animal { }
}

Get all classnames that extend a specific class

You could use Reflections:

Set<Class<? extends BaseClass>> subclasses = reflections.getSubTypesOf(BaseClass.class);

How do you find all subclasses of a given class in Java?

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).

How to get all extended classes without libraries

This is a solution,it works but you can add some enhancement (make it work with indirect superClasses ..), the idea is : find all the classes in the project directory , iterate those classes and look for all classes that extends a given class (by name). After that instanciate all these classes :

package x;

import java.util.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.*;
import java.net.URL;

public class MyClass {

/**
* 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 ClassNotFoundException
* @throws IOException
*/
private static Class[] getClasses(String packageName) throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
List<File> dirs = new ArrayList<File>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList<Class> classes = new ArrayList<Class>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes.toArray(new Class[classes.size()]);
}

/**
* 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> findClasses(File directory, String packageName) throws ClassNotFoundException {
List<Class> classes = new ArrayList<Class>();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(findClasses(file, packageName + "." + file.getName()));
} else if (file.getName().endsWith(".class")) {

// System.out.println(packageName + '.' + file.getName().substring(0, file.getName().length() - 6));

classes.add(
Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
}
}
return classes;
}

public static void main(String[] args) throws ClassNotFoundException {
List<City> cities = new ArrayList<City>();
List<Class> classes = findClasses(new File("C:\\Users\\za.oussama\\Desktop\\Dossiers\\ws\\xx\\bin\\x"), "x");
// print all class names within the project directory
classes.forEach(System.out::println);
// instanciate the classes who extends the class City :
// you can make it dynamic adding the class name to the method parameter
classes.stream().filter(clas -> clas.getSuperclass().getSimpleName().equals("City")).forEach(cl -> {
try {
City city = (City) cl.getDeclaredConstructor().newInstance();
cities.add(city);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
System.out.println();
cities.forEach(c -> System.out.println(" Instance created from class : " + c.getName()));

}
}

Output

class x.City
class x.London
class x.MyClass
class x.Paris

Instance created from class : London
Instance created from class : Paris

Image to clarify the path of files and the content of java classes
Sample Image

some code is copied from another stack answer and from here : https://dzone.com/articles/get-all-classes-within-package.



Related Topics



Leave a reply



Submit