java - poo - Encuentre todas las clases e interfaces que una clase extiende o implementa recursivamente
public interface java (8)
De la pregunta ¿Cómo encuentras todas las subclases de una clase dada en Java? , this respuesta podría ser útil:
Usando la clase PojoClassImpl.java puede obtener la súper clase llamando al método getSuperClass()
. Creo que eso es suficiente para que escribas un método recursivo.
Me preguntaba si había una manera fácil de determinar la lista completa de Tipos que una clase de Java extiende o implementa recursivamente.
por ejemplo:
class Foo extends Bar implements I1, I2 {...}
class Bar implements I3 {...}
interface I1 extends I4, I5 {...}
interface I2 {...}
interface I3 {...}
interface I4 {...}
interface I5 {...}
class ClassUtil {
public static Set<Class<?>> getAllExtendedOrImplementedTypesRecursively(Class<?> clazz){
???
}
}
import static org.junit.Assert.*;
public class ClassUtilTest {
@Test
public void shouldEqualClasses(){
Set<Class<?>> types = ClassUtil.getAllExtendedOrImplementedTypesRecursively(Foo.class);
Set<Class<?>> checklist = new HashSet<>();
checklist.add(Foo.class);
checklist.add(Bar.class);
checklist.add(I1.class);
checklist.add(I2.class);
checklist.add(I3.class);
checklist.add(I4.class);
checklist.add(I5.class);
assertTrue(checklist.containsAll(types));
assertTrue(types.containsAll(checklist));
}
}
Creo que Arquillian ShrinkWrap creador ayuda.
ACTUALIZACIÓN: debido a que el objeto Clase no implementa Comparable> También necesito encontrar una forma de crear un Conjunto (o clase similar) sin implementar la interfaz Comparable (por ejemplo, depender únicamente del código hash del objeto de clase).
ACTUALIZACIÓN: cambió la prueba para usar hashset. derp
En java8
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ClassUtil {
public static Set<Class<?>> getAllExtendedOrImplementedTypesRecursively(final Class<?> clazz) {
return walk(clazz)
.filter(Predicate.isEqual(java.lang.Object.class).negate())
.collect(Collectors.toSet());
}
public static Stream<Class<?>> walk(final Class<?> c) {
return Stream.concat(Stream.of(c),
Stream.concat(
Optional.ofNullable(c.getSuperclass()).map(Stream::of).orElseGet(Stream::empty),
Arrays.stream(c.getInterfaces())
).flatMap(ClassUtil::walk));
}
}
Código de prueba:
import java.util.Set;
class Test {
public static void main(String[] args) {
final Set<Class<?>> set = ClassUtil.getAllExtendedOrImplementedTypesRecursively(Foo.class);
set.stream().map(Class::getName).forEach(System.out::println);
}
class Foo extends Bar implements I1, I2 {}
class Bar implements I3 {}
interface I1 extends I4, I5 {}
interface I2 {}
interface I3 {}
interface I4 {}
interface I5 {}
}
Salida:
Test$Foo Test$Bar Test$I2 Test$I5 Test$I1 Test$I3 Test$I4
Es muy fácil, en caso de que tu clase sea Foo, tu código será así.
public void getClassDetails() {
Class klass = Foo.class;
Class<?> superKlass = klass.getSuperClass();
Class[] interfaces = klass.getInterfaces();
}
Hay un ClassUtils en el lenguaje común de Apache que tiene los 2 métodos que desea. .getAllSuperClasses () y .getAllInterfaces ().
La clave que desea está en el método Class#getSuperclass()
:
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));
}
La siguiente implementación del método hace lo que requiere el OP, atraviesa la jerarquía de herencia para cada clase e interfaz:
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);
}
JFrame.class
con JFrame.class
y obtuve lo siguiente:
Set<Class<?>> classes = getAllExtendedOrImplementedTypesRecursively(JFrame.class);
for (Class<?> clazz : classes) {
System.out.println(clazz.getName());
}
Salida:
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
ACTUALIZACIÓN: Para el caso de prueba del OP se imprime:
test.I5
test.Bar
test.I2
test.I1
test.Foo
test.I3
test.I4
Si entendí bien tu pregunta, quieres encontrar todas las superclases (clase e interfaz) de una clase específica. Si es así puedes consultar la siguiente solución.
para encontrar las superclases
Class C = getClass();
while (C != null) {
System.out.println(C.getSimpleName());
C = C.getSuperclass();
}
para encontrar las interfaces
C = getClass();
for(Class adf: C.getInterfaces()){
System.out.println(adf.getSimpleName());
}
Una vez implementé un mecanismo similar usando asm
en alguna rama de ShrinkWrap https://github.com/mmatloka/shrinkwrap/commit/39d5c3aa63a9bb85e6d7b68782879ca10cca273b . El problema es que a veces la clase puede usar un objeto que es una implementación de interfaz que no se menciona en otro archivo, por lo que aún puede fallar durante la implementación.
Por lo que sé hace un tiempo, la posición oficial era más bien no incluir esa característica dentro de ShrinkWrap
, sino confiar en herramientas, por ejemplo, en JBoss Tools
, donde debería haber una característica que permita adiciones de clases recursivas.