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.