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
some code is copied from another stack answer and from here : https://dzone.com/articles/get-all-classes-within-package.
Related Topics
After Spring Boot 2.0 Migration: Jdbcurl Is Required With Driverclassname
How to Store a Large (10 Digits) Integer
How to Get the Parent Element Name of a Child Element in Json
Crudrepository and Hibernate: Save(List<S>) VS Save(Entity) in Transaction
Remove Keys from Anywhere in a Json String Without Deserialization
How to Truncate a Double to Only Two Decimal Places in Java
Sonarqube: Missing Blame Information for the Following Files
How to Create a Java Code to Check Multiple Question
Passing Empty List as Parameter to JPA Query Throws Error
How to Apply Spring Boot Filter Based on Url Pattern
Status Expected:<200> But Was:<404> in Spring Test
How to Update a Jsf Component from a Jsf Backing Bean Method
How to Select One Object from the List of Objects
Simpledateformat Producing Wrong Date Time When Parsing "Yyyy-Mm-Dd Hh:Mm"
Spring Boot Error: Java.Lang.Noclassdeffounderror: Org/Springframework/Util/Assert
Password Validate 8 Digits, Contains Upper, Lowercase, and a Special Character
Android Tv Recyclerview Set Next Focus of Its Item
How to Wait for @Jmslistener Annotated Method to Complete in Junit