Automatic class instantiation [duplicate] - java

I want to do something like this:
List<Animal> animals = new ArrayList<Animal>();
for( Class c: list_of_all_classes_available_to_my_app() )
if (c is Animal)
animals.add( new c() );
So, I want to look at all of the classes in my application's universe, and when I find one that descends from Animal, I want to create a new object of that type and add it to the list. This allows me to add functionality without having to update a list of things. I can avoid the following:
List<Animal> animals = new ArrayList<Animal>();
animals.add( new Dog() );
animals.add( new Cat() );
animals.add( new Donkey() );
...
With the above approach, I can simply create a new class that extends Animal and it'll get picked up automatically.
UPDATE: 10/16/2008 9:00 a.m. Pacific Standard Time:
This question has generated a lot of great responses -- thank you. From the responses and my research, I've found that what I really want to do is just not possible under Java. There are approaches, such as ddimitrov's ServiceLoader mechanism that can work -- but they are very heavy for what I want, and I believe I simply move the problem from Java code to an external configuration file. Update 5/10/19 (11 years later!) There are now several libraries that can help with this according to #IvanNik's answer org.reflections looks good. Also ClassGraph from #Luke Hutchison's answer looks interesting. There are several more possibilities in the answers as well.
Another way to state what I want: a static function in my Animal class finds and instantiates all classes that inherit from Animal -- without any further configuration/coding. If I have to configure, I might as well just instantiate them in the Animal class anyway. I understand that because a Java program is just a loose federation of .class files that that's just the way it is.
Interestingly, it seems this is fairly trivial in C#.

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());
}
}
}

The Java way to do what you want is to use the ServiceLoader mechanism.
Also many people roll their own by having a file in a well known classpath location (i.e. /META-INF/services/myplugin.properties) and then using ClassLoader.getResources() to enumerate all files with this name from all jars. This allows each jar to export its own providers and you can instantiate them by reflection using Class.forName()

Think about this from an aspect-oriented point of view; what you want to do, really, is know all the classes at runtime that HAVE extended the Animal class. (I think that's a slightly more accurate description of your problem than your title; otherwise, I don't think you have a runtime question.)
So what I think you want is to create a constructor of your base class (Animal) which adds to your static array (I prefer ArrayLists, myself, but to each their own) the type of the current Class which is being instantiated.
So, roughly;
public abstract class Animal
{
private static ArrayList<Class> instantiatedDerivedTypes;
public Animal() {
Class derivedClass = this.getClass();
if (!instantiatedDerivedClass.contains(derivedClass)) {
instantiatedDerivedClass.Add(derivedClass);
}
}
Of course, you'll need a static constructor on Animal to initialize instantiatedDerivedClass... I think this'll do what you probably want. Note that this is execution-path dependent; if you have a Dog class that derives from Animal that never gets invoked, you won't have it in your Animal Class list.

Unfortunately this isn't entirely possible as the ClassLoader won't tell you what classes are available. You can, however, get fairly close doing something like this:
for (String classpathEntry : System.getProperty("java.class.path").split(System.getProperty("path.separator"))) {
if (classpathEntry.endsWith(".jar")) {
File jar = new File(classpathEntry);
JarInputStream is = new JarInputStream(new FileInputStream(jar));
JarEntry entry;
while( (entry = is.getNextJarEntry()) != null) {
if(entry.getName().endsWith(".class")) {
// Class.forName(entry.getName()) and check
// for implementation of the interface
}
}
}
}
Edit: johnstok is correct (in the comments) that this only works for standalone Java applications, and won't work under an application server.

The most robust mechanism for listing all subclasses of a given class is currently ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author.)
List<Class<Animal>> animals;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("com.zoo.animals")
.enableClassInfo().scan()) {
animals = scanResult
.getSubclasses(Animal.class.getName())
.loadClasses(Animal.class);
}

You could use ResolverUtil (raw source) from the Stripes Framework
if you need something simple and quick without refactoring any existing code.
Here's a simple example not having loaded any of the classes:
package test;
import java.util.Set;
import net.sourceforge.stripes.util.ResolverUtil;
public class BaseClassTest {
public static void main(String[] args) throws Exception {
ResolverUtil<Animal> resolver = new ResolverUtil<Animal>();
resolver.findImplementations(Animal.class, "test");
Set<Class<? extends Animal>> classes = resolver.getClasses();
for (Class<? extends Animal> clazz : classes) {
System.out.println(clazz);
}
}
}
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class Donkey extends Animal {}
This also works in an application server as well since that's where it was designed to work ;)
The code basically does the following:
iterate over all the resources in the package(s) you specify
keep only the resources ending in .class
Load those classes using ClassLoader#loadClass(String fullyQualifiedName)
Checks if Animal.class.isAssignableFrom(loadedClass);

Java dynamically loads classes, so your universe of classes would be only those that have already been loaded (and not yet unloaded). Perhaps you can do something with a custom class loader that could check the supertypes of each loaded class. I don't think there's an API to query the set of loaded classes.

use this
public static Set<Class> getExtendedClasses(Class superClass)
{
try
{
ResolverUtil resolver = new ResolverUtil();
resolver.findImplementations(superClass, superClass.getPackage().getName());
return resolver.getClasses();
}
catch(Exception e)
{Log.d("Log:", " Err: getExtendedClasses() ");}
return null;
}
getExtendedClasses(Animals.class);
Edit:
library for (ResolverUtil) : Stripes

Thanks all who answered this question.
It seems this is indeed a tough nut to crack. I ended up giving up and creating a static array and getter in my baseclass.
public abstract class Animal{
private static Animal[] animals= null;
public static Animal[] getAnimals(){
if (animals==null){
animals = new Animal[]{
new Dog(),
new Cat(),
new Lion()
};
}
return animals;
}
}
It seems that Java just isn't set up for self-discoverability the way C# is. I suppose the problem is that since a Java app is just a collection of .class files out in a directory / jar file somewhere, the runtime doesn't know about a class until it's referenced. At that time the loader loads it -- what I'm trying to do is discover it before I reference it which is not possible without going out to the file system and looking.
I always like code that can discover itself instead of me having to tell it about itself, but alas this works too.
Thanks again!

Using OpenPojo you can do the following:
String package = "com.mycompany";
List<Animal> animals = new ArrayList<Animal>();
for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(package, Animal.class, null) {
animals.add((Animal) InstanceFactory.getInstance(pojoClass));
}

This is a tough problem and you will need to find out this information using static analysis, its not available easily at runtime.
Basically get the classpath of your app and scan through the available classes and read the bytecode information of a class which class it inherits from. Note that a class Dog may not directly inherit from Animal but might inherit from Pet which is turn inherits from Animal,so you will need to keep track of that hierarchy.

One way is to make the classes use a static initializers... I don't think these are inherited (it won't work if they are):
public class Dog extends Animal{
static
{
Animal a = new Dog();
//add a to the List
}
It requires you to add this code to all of the classes involved. But it avoids having a big ugly loop somewhere, testing every class searching for children of Animal.

I solved this problem pretty elegantly using Package Level Annotations and then making that annotation have as an argument a list of classes.
Find Java classes implementing an interface
Implementations just have to create a package-info.java and put the magic annotation in with the list of classes they want to support.

Since directly using newInstance() is deprecated, you can do it this way using Reflections.
Reflections r = new Reflections("com.example.location.of.sub.classes")
Set<Class<? extends Animal>> classes = r.getSubTypesOf(Animal.class);
classes.forEach(c -> {
Animal a = c.getDeclaredConstructor().newInstance();
//a is your instance of Animal.
});

Related

java generics - "extends" keyword -> not supporting add elements

I am stuck with a strange problem due to java generics "extend" keyword. I have developed a generic method to get the elements from a method as generic as possible.
When I use <? extends X>, I am not able to add any elements to it.
In my case I am using the generic template to restrict the arguments provided by the user and providing the return type ac.
class Root{
}
class Sub_1 extends Root{
}
class Sub_2 extends Root{
}
public static <T extends Root> List<T> getSubElements(Class<T> targetClass){
List<T> ls=new ArrayList<>();
if(targetClass.getSimpleName().equals("Sub_1")){
Sub_1 sub_1 = new Sub_1();
ls.add(sub_1);
}else if(targetClass.getSimpleName().equals("Sub_2")){
Sub_2 sub_2=new Sub_2();
ls.add(sub_2);
}
return ls;
}
In the above case, I am getting compilation error when I add elements to the list.
ls.add(sub_1);
ls.add(sub_2);
It looks quite challenging now to solve this issue.. I will be happy if someone can provide some hints here.
Thanks!!
You can do this in a type-safe way, without using reflection, by having the caller pass in a Supplier of the desired type instead of the Class of that type. The getSubElement code then simply calls the supplier to get the right instance:
static <T extends Root> List<T> getSubElements(Supplier<T> s) {
List<T> ls = new ArrayList<>();
ls.add(s.get());
return ls;
}
The caller needs to provide a way to create an instance of its desired subclass. This might be using a constructor reference, or it could be a reference to a static factory method. If the class hierarchy is like so:
public class Root { }
public class Sub1 extends Root {
public Sub1() { ... }
}
public class Sub2 extends Root {
public static Sub2 instance() { ... }
}
Then callers could write code like the following:
List<Sub1> list1 = getSubElements(Sub1::new);
List<Sub2> list2 = getSubElements(Sub2::instance);
If you can accept any class derived from Root, and all have a default constructor...
public static <T extends Root> List<T> getSubElements(Class<T> targetClass) throws ReflectiveOperationException {
List<T> ls = new ArrayList<>();
T t = targetClass.getDeclaredConstructor().newInstance();
ls.add(t);
return ls;
}
... or try/catch exception locally.
To sum things up, here is a verified working implementation, checked using an online java compiler:
import java.util.*;
class Root{
}
class Sub_1 extends Root{
}
class Sub_2 extends Root{
}
public class Bla {
public static <T extends Root> T factoryMethod(Class<T> targetClass) throws Exception{
if (Sub_1.class ==(targetClass)) {
return (T) (new Sub_1());
}
else if (Sub_2.class == (targetClass)) {
return (T) (new Sub_2());
}
else {
throw new Exception("Unsupported class type");
}
}
public static List<Root> getSubElements() throws Exception{
List<Root> ls=new ArrayList<>();
ls.add(factoryMethod(Sub_1.class));
ls.add(factoryMethod(Sub_2.class));
return ls;
}
public static void main(String[] args) {
try {
List<Root> root = getSubElements();
System.out.println(root);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I would rather say the answer depends on boundary conditions. we can write code to get the necessary functionality but they may/may not adhere to various boundaries conditions like performance, security, integrity ,.. etc
e.g:
The following code
**T newInstance = targetClass.newInstance();**
**list.add(newInstance);**
can also achieve necessary functionality but may/may not adhere to performance boundary, coz any call to reflective methods checks for security access.
The solution with Supplier posted above also achieves a similar functionality , but it may not adhere to security boundary as a malicious supplier can supply values which can lead to buffer overflow or DOS attacks.
(if you really want to to try it out you can create a static supplier and initialize with self.. you will get an stack overflow. java generics book also provide a similar security related example which you can refer). The problem i see lies in the java open sub-typing in the current scenario .
There are other solutions also to achieve required functionality ( with slight modification to way of subtyping created) which may/may not adhere to these boundary conditions. The problem i see is due to open sub-typing system and makes it verbose and difficult for developers to write code adhering to all boundary conditions.
The solution also depends completely up on your model structure whether you have created a sub-typing coz of your data or or based on behavior , which might not reflect in this short example.
you can refer Java Generics Book by Philiph Wadler for more details on working with generics which i would recommend. it also gives an important aspect of writing code in a secure way. On an interesting note you can refer to project amber (java 11 or later) regarding Data Classes for java which tries to address some of these problems.

discover interface classes at runtime [duplicate]

I want to do something like this:
List<Animal> animals = new ArrayList<Animal>();
for( Class c: list_of_all_classes_available_to_my_app() )
if (c is Animal)
animals.add( new c() );
So, I want to look at all of the classes in my application's universe, and when I find one that descends from Animal, I want to create a new object of that type and add it to the list. This allows me to add functionality without having to update a list of things. I can avoid the following:
List<Animal> animals = new ArrayList<Animal>();
animals.add( new Dog() );
animals.add( new Cat() );
animals.add( new Donkey() );
...
With the above approach, I can simply create a new class that extends Animal and it'll get picked up automatically.
UPDATE: 10/16/2008 9:00 a.m. Pacific Standard Time:
This question has generated a lot of great responses -- thank you. From the responses and my research, I've found that what I really want to do is just not possible under Java. There are approaches, such as ddimitrov's ServiceLoader mechanism that can work -- but they are very heavy for what I want, and I believe I simply move the problem from Java code to an external configuration file. Update 5/10/19 (11 years later!) There are now several libraries that can help with this according to #IvanNik's answer org.reflections looks good. Also ClassGraph from #Luke Hutchison's answer looks interesting. There are several more possibilities in the answers as well.
Another way to state what I want: a static function in my Animal class finds and instantiates all classes that inherit from Animal -- without any further configuration/coding. If I have to configure, I might as well just instantiate them in the Animal class anyway. I understand that because a Java program is just a loose federation of .class files that that's just the way it is.
Interestingly, it seems this is fairly trivial in C#.
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());
}
}
}
The Java way to do what you want is to use the ServiceLoader mechanism.
Also many people roll their own by having a file in a well known classpath location (i.e. /META-INF/services/myplugin.properties) and then using ClassLoader.getResources() to enumerate all files with this name from all jars. This allows each jar to export its own providers and you can instantiate them by reflection using Class.forName()
Think about this from an aspect-oriented point of view; what you want to do, really, is know all the classes at runtime that HAVE extended the Animal class. (I think that's a slightly more accurate description of your problem than your title; otherwise, I don't think you have a runtime question.)
So what I think you want is to create a constructor of your base class (Animal) which adds to your static array (I prefer ArrayLists, myself, but to each their own) the type of the current Class which is being instantiated.
So, roughly;
public abstract class Animal
{
private static ArrayList<Class> instantiatedDerivedTypes;
public Animal() {
Class derivedClass = this.getClass();
if (!instantiatedDerivedClass.contains(derivedClass)) {
instantiatedDerivedClass.Add(derivedClass);
}
}
Of course, you'll need a static constructor on Animal to initialize instantiatedDerivedClass... I think this'll do what you probably want. Note that this is execution-path dependent; if you have a Dog class that derives from Animal that never gets invoked, you won't have it in your Animal Class list.
Unfortunately this isn't entirely possible as the ClassLoader won't tell you what classes are available. You can, however, get fairly close doing something like this:
for (String classpathEntry : System.getProperty("java.class.path").split(System.getProperty("path.separator"))) {
if (classpathEntry.endsWith(".jar")) {
File jar = new File(classpathEntry);
JarInputStream is = new JarInputStream(new FileInputStream(jar));
JarEntry entry;
while( (entry = is.getNextJarEntry()) != null) {
if(entry.getName().endsWith(".class")) {
// Class.forName(entry.getName()) and check
// for implementation of the interface
}
}
}
}
Edit: johnstok is correct (in the comments) that this only works for standalone Java applications, and won't work under an application server.
The most robust mechanism for listing all subclasses of a given class is currently ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author.)
List<Class<Animal>> animals;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("com.zoo.animals")
.enableClassInfo().scan()) {
animals = scanResult
.getSubclasses(Animal.class.getName())
.loadClasses(Animal.class);
}
You could use ResolverUtil (raw source) from the Stripes Framework
if you need something simple and quick without refactoring any existing code.
Here's a simple example not having loaded any of the classes:
package test;
import java.util.Set;
import net.sourceforge.stripes.util.ResolverUtil;
public class BaseClassTest {
public static void main(String[] args) throws Exception {
ResolverUtil<Animal> resolver = new ResolverUtil<Animal>();
resolver.findImplementations(Animal.class, "test");
Set<Class<? extends Animal>> classes = resolver.getClasses();
for (Class<? extends Animal> clazz : classes) {
System.out.println(clazz);
}
}
}
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class Donkey extends Animal {}
This also works in an application server as well since that's where it was designed to work ;)
The code basically does the following:
iterate over all the resources in the package(s) you specify
keep only the resources ending in .class
Load those classes using ClassLoader#loadClass(String fullyQualifiedName)
Checks if Animal.class.isAssignableFrom(loadedClass);
Java dynamically loads classes, so your universe of classes would be only those that have already been loaded (and not yet unloaded). Perhaps you can do something with a custom class loader that could check the supertypes of each loaded class. I don't think there's an API to query the set of loaded classes.
use this
public static Set<Class> getExtendedClasses(Class superClass)
{
try
{
ResolverUtil resolver = new ResolverUtil();
resolver.findImplementations(superClass, superClass.getPackage().getName());
return resolver.getClasses();
}
catch(Exception e)
{Log.d("Log:", " Err: getExtendedClasses() ");}
return null;
}
getExtendedClasses(Animals.class);
Edit:
library for (ResolverUtil) : Stripes
Thanks all who answered this question.
It seems this is indeed a tough nut to crack. I ended up giving up and creating a static array and getter in my baseclass.
public abstract class Animal{
private static Animal[] animals= null;
public static Animal[] getAnimals(){
if (animals==null){
animals = new Animal[]{
new Dog(),
new Cat(),
new Lion()
};
}
return animals;
}
}
It seems that Java just isn't set up for self-discoverability the way C# is. I suppose the problem is that since a Java app is just a collection of .class files out in a directory / jar file somewhere, the runtime doesn't know about a class until it's referenced. At that time the loader loads it -- what I'm trying to do is discover it before I reference it which is not possible without going out to the file system and looking.
I always like code that can discover itself instead of me having to tell it about itself, but alas this works too.
Thanks again!
Using OpenPojo you can do the following:
String package = "com.mycompany";
List<Animal> animals = new ArrayList<Animal>();
for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(package, Animal.class, null) {
animals.add((Animal) InstanceFactory.getInstance(pojoClass));
}
This is a tough problem and you will need to find out this information using static analysis, its not available easily at runtime.
Basically get the classpath of your app and scan through the available classes and read the bytecode information of a class which class it inherits from. Note that a class Dog may not directly inherit from Animal but might inherit from Pet which is turn inherits from Animal,so you will need to keep track of that hierarchy.
One way is to make the classes use a static initializers... I don't think these are inherited (it won't work if they are):
public class Dog extends Animal{
static
{
Animal a = new Dog();
//add a to the List
}
It requires you to add this code to all of the classes involved. But it avoids having a big ugly loop somewhere, testing every class searching for children of Animal.
I solved this problem pretty elegantly using Package Level Annotations and then making that annotation have as an argument a list of classes.
Find Java classes implementing an interface
Implementations just have to create a package-info.java and put the magic annotation in with the list of classes they want to support.
Since directly using newInstance() is deprecated, you can do it this way using Reflections.
Reflections r = new Reflections("com.example.location.of.sub.classes")
Set<Class<? extends Animal>> classes = r.getSubTypesOf(Animal.class);
classes.forEach(c -> {
Animal a = c.getDeclaredConstructor().newInstance();
//a is your instance of Animal.
});

Create new instances of a class from an array of classes with Java

I'm trying to create an array of classes in Java. Not objects, but classes. Currently I have a class MyBaseClass and I extend three classes MyClass1, MyClass2, and MyClass3 from it. I store these classes to a static array like this:
private static MyBaseClass[] classes = {
new MyClass1(),
new MyClass2(),
new MyClass3()
};
public static MyBaseClass getInstanceOfClass(int index) {
return classes[index];
}
and then I use those methods like this:
try {
MyBaseClass obj = getInstanceOfClass(index).getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
Now I'm wondering if I could do this in an easier way. If I could create an array of classes I might be able to escape the getInstanceOfClass() method and some possible exceptions. I tried doing this:
private static Class<MyBaseClass>[] classes = {
MyClass1.class,
MyClass2.class,
MyClass3.class
};
But this gives me an error "Incompatible types" as MyClass1 is not equal to MyBaseClass. Interestingly enough, this seemingly works:
private static Class<?>[] classes = {
new MyClass1().getClass(),
new MyClass2().getClass(),
new MyClass3().getClass()
};
But the idea of that is horrible and it's even marked by my debugger. So, any better ways of doing this?
Edit:
This works:
private static Class<?>[] classes = {
MyClass1.class,
MyClass2.class,
MyClass3.class
};
But then the result of getInstanceOfClass(index).newInstance(); is an Object so I have to do typecasting. I'm not really sure if that's safe in this case...
You have to indicated that you are looking for possibly subclasses of MyBaseClass. For this you can add ? extends to the generic type description. Note that this will also accept MyBaseClass itself.
Added to this, you can use .class to get the Class object of a class, instead of making an isntance and calling getClass().
Unfortunately this doesn't work with arrays because they don't allow generic types. So you have to add them to a list (which is almost always a good thing):
private static ArrayList<Class<? extends MyBaseClass>> classes = new ArrayList<Class<? extends MyBaseClass>>();
...
classes.add(MyClass1.class),
classes.add(MyClass2.class),
classes.add(MyClass3.class),

Jackson: programmatically determine subtypes

Given an arbitrary Class object, what is the best way to determine the subtypes of that class registered with Jackson?
For example, here's a simple case where classes Lion and Penguin are subtypes of Animal:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
#JsonSubTypes({
#JsonSubTypes.Type(Lion.class),
#JsonSubTypes.Type(Penguin.class)})
public static abstract class Animal {}
#JsonTypeName("Lion")
public static class Lion extends Animal {}
#JsonTypeName("Penguin")
public static class Penguin extends Animal {}
My dream function would look like:
List<Class> getSubTypeClasses(Class c) {...}
where getSubTypeClasses(Animal.class) would return Lion and Penguin.
If the Jackson API doesn't provide a convenient way to get this information I will read the annotations manually, but it would be nice to know of a technique compatible with any AnnotationIntrospector implementation.
Instead of ai.findSubTypes(ac) you may use mapper.getSubtypeResolver().collectAndResolveSubtypes(ac, config, ai).
I've not tested it with registered subtypes but looking at the code it should work.
There is currently no mechanism for doing that. But you could file a request for adding something like this: given a base class, return a set of known sub-types along with type ids used for them, and the default implementation use. This seems like a reasonable thing to provide access for.
In the meantime (new feature could be available for 2.3, so it'd take some time), have a look at AnnotationIntrospector and see what methdods are available there, and how jackson-databind uses it to build mapping information. You should not have to write all of that manually, even without accessor.
Thanks to StaxMan for nudging me in the right direction. Here's a solution for Jaxen 2.2.3:
public static List<Class> getSubtypeClasses(ObjectMapper mapper, Class c) {
return getSubtypeClasses(mapper.getDeserializationConfig(), c);
}
public static List<Class> getSubtypeClasses(MapperConfig config, Class c) {
AnnotationIntrospector ai = config.getAnnotationIntrospector();
AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(c, ai, config);
List<NamedType> subtypes = ai.findSubtypes(ac);
List<Class> result = new ArrayList<>();
if (subtypes != null) {
for (NamedType subtype : subtypes) {
result.add(subtype.getType());
}
}
return result;
}
To access the SubTypes annotations of a super class you can use the JacksonAnnotationIntrospector:
AnnotationIntrospector annotationInspector = new JacksonAnnotationIntrospector();
JavaType superClassType = TypeFactory.defaultInstance().uncheckedSimpleType(Animal.class);
AnnotatedClass annotatedClass = AnnotatedClass.construct(superClassType,new ObjectMapper().getSerializationConfig());
List<NamedType> subtypes = annotationInspector.findSubtypes(annotatedClass);

Generic class method returns its own type as a template parameter

I'm designing a set of generic classes that hold Document objects within Folder objects:
// Folder, which holds zero or more documents
public interface Folder<DocType extends Document>
{
// Locate matching documents within the folder
public ArrayList<DocType> findDocuments(...);
...
}
// Document, contained within a folder
public interface Document
{
// Retrieve the parent folder
public Folder getFolder(); // Not correct
...
}
These classes are then extended for the actual implementation of the folder and document types. The trouble is that the Document.getFolder() method needs to return an object of type Folder<DocType>, where DocType is the actual implementation type of Document. Which means that the method needs to know what its own concrete class type is.
So my question is, should the Document class be declared instead like this:
// Document, contained within a Folder
public interface Document<DocType extends Document>
{
// Retrieve the parent folder
public Folder<DocType> getFolder();
...
}
Or is there a simpler way to do this? The code above requires concrete implementations to look like this:
public class MyFolder
implements Folder<MyDocument>
{ ... }
public class MyDocument
implements Document<MyDocument>
{ ... }
It's the Document<MyDocument> part that seems a bit strange to me; is it really necessary?
(Apologies if this is a duplicate; I couldn't find the exact answer I was looking for in the archives.)
ADDENDUM
The original code above used ArrayList<DocType>, but like several posters have pointed out, I'd be better off returning a List, e.g.:
public List<DocType> findDocuments(...);
(That method was not crucial to my problem, and my actual API returns an Iterator, so I just used the first thing that came to mind in order to simplify the question.)
The way you have it seems to be Ok for me, with the exception of a missing type parameters in the Document and Folder interfaces and the use of ArrayList (an implementation) instead of List (an interface).
interface Folder<T extends Document<T>>
{
public List<T> findDocuments();
}
interface Document<T extends Document<T>>
{
public Folder<T> getFolder();
}
Using the API is the best way to know, let's say we have an implementation of Document called SpreadSheet:
class SpreadSheet implements Document<SpreadSheet> {
#Override
public Folder<SpreadSheet> getFolder() {
return new SpreadSheetFolder();
}
}
And then you have a Folder implementation called SpreadSheetFolder:
class SpreadSheetFolder implements Folder<SpreadSheet>{
#Override
public List<SpreadSheet> findDocuments() {
return asList(new SpreadSheet(), new SpreadSheet());
}
}
Then when you use your API, you would do:
Document<SpreadSheet> d = new SpreadSheet();
Folder<SpreadSheet> folder = d.getFolder();
It works just fine.
That seems an aedequate way to adress your requirements, and no, there is no simpler way to express the same (in particular, Java has no syntax to constrain a type parameter to the type of this).
However, since you extend both Document and Folder, perhaps your actually need a mutually recursive type bound. By which I mean that in your solution, the expression
new MyFolder().findDocuments().get(0).getFolder()
is of type Folder<MyDocument>, not MyFolder. If it needs to be MyFolder, the generics get ugly:
//Folder, which holds zero or more documents
interface Folder<D extends Document<D, F>, F extends Folder<D, F>> {
ArrayList<D> findDocuments();
}
// Document, contained within a folder
interface Document<D extends Document<D, F>, F extends Folder<D, F>> {
F getFolder();
}
You can then implement:
class MyFolder implements Folder<MyDocument, MyFolder> {
#Override
public ArrayList<MyDocument> findDocuments() {
return new ArrayList<>(Collections.singletonList(new MyDocument()));
}
}
class MyDocument implements Document<MyDocument, MyFolder> {
#Override
public MyFolder getFolder() {
return new MyFolder();
}
}
and now,
MyFolder folder = new MyFolder().findDocuments().get(0).getFolder();
compiles, too.
BTW, using ArrayList in an interface is quite restrictive, as the kludge when I wanted to use Collections.singletonList illustrates. You also (inadvertently?) deny yourself the services of Collections.unmodifiableList and friends. Usually, one therefore leaves the List implementation to the discretion of the implementor by declaring
List<D> findDocuments();
instead.

Categories