I was wondering if there was an easy way of determining the complete list of Types that a Java class extends or implements recursively?
for instance:
cla
If I got your question right, you want to find all the superclasses (class and interface) of a specific class. If so you can check the following solution
to find the superclasses
Class C = getClass();
while (C != null) {
System.out.println(C.getSimpleName());
C = C.getSuperclass();
}
to find the interfaces
C = getClass();
for(Class adf: C.getInterfaces()){
System.out.println(adf.getSimpleName());
}
I have once implemented similiar mechanism using asm
on some ShrinkWrap branch https://github.com/mmatloka/shrinkwrap/commit/39d5c3aa63a9bb85e6d7b68782879ca10cca273b . The issue is sometimes class might use object which is an interface implementation not mentioned in other file so it still can fail during deployment.
From what I know some time ago official position was rather not to include such feature inside of the ShrinkWrap
, but rather rely on tooling e.g. JBoss Tools
, where should be a feature allowing for recursive class additions.
There is a ClassUtils in the Apache Common Lang that have the 2 methods you want. .getAllSuperClasses() and .getAllInterfaces().
It's very easy, in case your class is Foo then your code will be like this,
public void getClassDetails() {
Class klass = Foo.class;
Class<?> superKlass = klass.getSuperClass();
Class[] interfaces = klass.getInterfaces();
}
The following implementation of the method does what the OP requires, it traverses the inheritance hierarchy for every class and interface:
public static Set<Class<?>> getAllExtendedOrImplementedTypesRecursively(Class<?> clazz) {
List<Class<?>> res = new ArrayList<>();
do {
res.add(clazz);
// First, add all the interfaces implemented by this class
Class<?>[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
res.addAll(Arrays.asList(interfaces));
for (Class<?> interfaze : interfaces) {
res.addAll(getAllExtendedOrImplementedTypesRecursively(interfaze));
}
}
// Add the super class
Class<?> superClass = clazz.getSuperclass();
// Interfaces does not have java,lang.Object as superclass, they have null, so break the cycle and return
if (superClass == null) {
break;
}
// Now inspect the superclass
clazz = superClass;
} while (!"java.lang.Object".equals(clazz.getCanonicalName()));
return new HashSet<Class<?>>(res);
}
I tested with JFrame.class
and I got the following:
Set<Class<?>> classes = getAllExtendedOrImplementedTypesRecursively(JFrame.class);
for (Class<?> clazz : classes) {
System.out.println(clazz.getName());
}
Output:
java.awt.Container
java.awt.Frame
javax.swing.JFrame
javax.swing.TransferHandler$HasGetTransferHandler
java.awt.Window
javax.accessibility.Accessible
javax.swing.RootPaneContainer
java.awt.Component
javax.swing.WindowConstants
java.io.Serializable
java.awt.MenuContainer
java.awt.image.ImageObserver
UPDATE: For the OP's test case it prints:
test.I5
test.Bar
test.I2
test.I1
test.Foo
test.I3
test.I4
The key you want is in the Class#getSuperclass()
method:
public static Set<Class<?>> stuff(Class<?> target) {
Set<Class<?>> classesInterfaces = new HashSet<>();
classesInterfaces.add(target);
classesInterfaces.addAll(Arrays.asList(target.getInterfaces());
Class<?> superClass = target.getSuperclass();
if(superClass != null)
classesInterfaces.addAll(stuff(superClass));
}