How to get all interfaces of an object?

Asked

Viewed 145 times

8

I need to list all interfaces that an object implements. From what I understand, I could do the following:

Object misterioso;

    ....

misterioso.getClass().getInterfaces();

but this would only take the implemented interfaces directly by the class. That is, if the class of this object of mine implements the interface I2 which, in turn, extends I1, this call would only return I2. That’s what I understood from Javadoc and the tests I’ve performed.

How do I get all interfaces implemented by an object, including recursive interfaces (and superclasses)?

I accept suggestions with dependencies, but take into account that, in the environment in which I am working, I can only have guaranteed JRE implementations up to 7 (but with the right to functional part, of Stream functional interfaces to the Optionals), I have no access to creating Proxy about the interfaces and that most of the available dependencies are incompatible with the tool in which the code will run.

  • 2

    Who gave the negative could explain to me how I can improve the question? To the point of being worthy of its positive if possible =3

  • 2

    I may be traveling, but I can’t go around the superclasses Object and taking the interfaces implemented by each one?

  • 2

    I think the reflection should be done recursively for each interface obtained directly. ps: pressed +1, the question is good.

  • 2

    @Augustovasques, thank you very much =D Taking advantage (cc Piovezan), I managed to arrive at something that I believe to be the answer, but I am doing more tests and with laziness of a formal demonstration based in that reply of mine. The answer has nothing to do with Java or reflection, but about recursion, according to your tip 2

2 answers

9


A recursive process needs to be implemented to search for the most internal implementations, as in the example below:

public static ArrayList<String> SetInterfaces(Class<?>[] interfaces,
                                              ArrayList<String> items)
{        
    for (Class<?> intf : interfaces) {
        items.add(intf.getName());
        SetInterfaces(intf.getInterfaces(), items);
    }
    return items;
}

and to use that code:

Car car = new Car();
Class<?>[] interfaces = car.getClass().getInterfaces();
ArrayList<String> items = new ArrayList<>();
SetInterfaces(interfaces, items)
        .forEach((item) -> {
             System.out.println(item);
         });

Online Example

In the example only the class name is shown, giving an example of the output of the most internal interfaces implemented


The user had not mentioned the use of inheritance but, questioned it if he had inheritances to reach all interfaces implemented, following practically the same logic:

public static Set<String> SetInterfaces(Class<?> aClass,
                                          Set<String> items)
{           
    for (Class<?> intf : aClass.getInterfaces()) {
        items.add(intf.getName()); 
        SetInterfaces(intf, items);            
    }
    if (aClass.isInterface() == false && aClass.getSuperclass() != null) {
        SetInterfaces(aClass.getSuperclass(), items);
    }        
    return items;
}

and

OnibusBiTrem oni = new OnibusBiTrem();
Class<?> classes = oni.getClass(); 
Set<String> items = new HashSet<>() ;        
SetInterfaces(classes, items)
            .forEach((item) -> {
                 System.out.println(item);
             });

Online Example

  • All we had to do was navigate the superclass. I know I didn’t specify, but it will navigate/list multiple times the same interface if by chance two interfaces implement the same superinterface. The double listing resolves itself using Set or its variations, already avoid double navigation could be simply asked the collection if it already has the element (contains).

  • More is how you yourself reported @Jeffersonquesado missing information and what I proposed to you is a simple example, no more information and browse the super class as well if the data comes from a super class? I really didn’t understand that remark

  • Imagine I have the class Bus, extending from Car and implements HasPassengers, and the class OnibusBiTrem, extending from Bus and implements the interface IMultiplosVagoes. If HasPassengers and IMultiolosVagoes do not extend any interface, I should get them and also to all interfaces Car when I went behind the interfaces of new OnibusBiTrem(). Anyway, it is trivial to change your code to do this navigation, so I have already marked as the appropriate response

  • I think that’s what you want, changed a little but, is the same idea @Jeffersonquesado

4

This reply began to be written before the reply from Virgilio Novic.

My approach has a different view, with a construction of knowledge that I consider valid to share, but the code obtained remains more or less that of Virgilio Norvig.

This is a recursive problem (as indicated by Piovezam and Augusto Vasques in the comments). I can reduce it to a search in a directed acyclic graph.

In this graph, I have three kinds of knots:

  • object node (input, does not matter for the final result)
  • class nodes (no matter for the final result)
  • interface nodes (interest for the final result)

The question then becomes how, from the object node, which interface nodes I can achieve. An interesting thing about the structure of this graph is the following:

  • the graph is finite, always
  • the input node has only one edge, which goes to a class node (identified by getClass())
  • the class node can point to another class node (identified by getSuperclass()), and can also point to several interface nodes (identified by getInterfaces())
  • the interface node can point to several interface nodes (identified by getInterfaces())

Since it is acyclic and finite, I can navigate it in depth without problems. An idea well above how I navigate this graph is as follows:

def percorre_grafo(nodo):
  se nodo é objeto:
    percorre_grafo(nodo.getClass())
  se nodo é de classe:
    para iface em nogo.getInterfaces():
      percorre_grafo(iface)
    se nodo.getSuperclass() != null:
      percorre_grafo(nodo.getSuperclass)
  se nodo é interface:
    # faz algo com o nodo em questão
    para iface em nogo.getInterfaces():
      percorre_grafo(iface)

However, I can leave code blocks with minor concerns. For example, a block to be the front, receiving the object in question, another to traverse the classes/superclasses of that object and finally a last block that recursively traverses the interfaces:

def percorre_grafo__front(nodo):
  # garanto aqui que nodo é do tipo "objeto"
  # só tem uma aresta que aponta para um nó do tipo "classe"
  percorre_grafo__classe(nodo.getClass())

def percorre_grafo__classe(nodo):
  # garanto aqui que nodo é do tipo "classe"
  # pode ter uma aresta que aponta para um nó do tipo "classe"
  # podem ter diversas arestas que apontam para nós do tipo "interface"

  se nodo.getSuperclass() != null:
    percorre_grafo__classe(nodo.getSuperclass())
  percorre_grafo__interface(iface) para iface em nodo.getInterfaces()

def percorre_grafo__interface(nodo):
  # garanto aqui que nodo é do tipo "interface"
  # podem ter diversas arestas que apontam para nós do tipo "interface"

  # faz algo com o nodo em questão
  percorre_grafo__interface(iface) para iface em nodo.getInterfaces()

I can still remove the recursion from the function percorre_grafo__classe, because it is a recursive function trivial. This is the iterative unfolding of it:

def percorre_grafo__classe(nodo):
  # garanto aqui que nodo é do tipo "classe"
  # pode ter uma aresta que aponta para um nó do tipo "classe"
  # podem ter diversas arestas que apontam para nós do tipo "interface"

  iter = nodo
  enquanto iter != null:
    percorre_grafo__interface(iface) para iface em iter.getInterfaces()
    iter = iter.getSuperclass()

In this strategy I pass through all the nodes reachable from the object in question, including repeating the same interface several times. If I admit that the recursion part is reach the knots, then I can pass to the recursive step the "answer" being built, a strategy similar to the one I used in this answer to discover the difference between the largest and smallest element of a list recursively. The do something with the node in question is add into the set. If the node was already previously in the set, it means that I had already passed through it, then no it is necessary to make the recursive call.

Assuming this as the strategy, and taking into account the function percorre_grafo__classe as the point of entry that prepares the function for recursive call, we then have the following algorithm:

def percorre_grafo__front(nodo):
  # garanto aqui que nodo é do tipo "objeto"
  # só tem uma aresta que aponta para um nó do tipo "classe"
  percorre_grafo__classe(nodo.getClass())

def percorre_grafo__classe(nodo):
  # garanto aqui que nodo é do tipo "classe"
  # pode ter uma aresta que aponta para um nó do tipo "classe"
  # podem ter diversas arestas que apontam para nós do tipo "interface"

  conjunto_interfaces = new Set()
  iter = nodo
  enquanto iter != null:
    percorre_grafo__interface(iface, conjunto_interfaces) para iface em iter.getInterfaces()
    iter = iter.getSuperclass()

def percorre_grafo__interface(nodo, conjunto_interfaces):
  # garanto aqui que nodo é do tipo "interface"
  # podem ter diversas arestas que apontam para nós do tipo "interface"

  se conjunto_interfaces não contém nodo:
    conjunto_interfaces.add(nodo)
    percorre_grafo__interface(iface) para iface em nodo.getInterfaces()

And in Java, what would that be like?

HashSet<Class<?>> percorre_grafo__front(Object nodo) {
  // garanto aqui que nodo é do tipo "objeto"
  // só tem uma aresta que aponta para um nó do tipo "classe"

  return percorre_grafo__classe(nodo.getClass());
}

HashSet<Class<?>> percorre_grafo__classe(Class<?> nodo) {
  // garanto aqui que nodo é do tipo "classe"
  // pode ter uma aresta que aponta para um nó do tipo "classe"
  // podem ter diversas arestas que apontam para nós do tipo "interface"

  HashSet<Class<?>> conjunto_interfaces = new HashSet<>();

  Class<?> iter = nodo;
  while (iter != null) {
    Stream.of(iter.getInterfaces()).forEach(iface -> percorre_grafo__interface(iface, conjunto_interfaces));
    iter = iter.getSuperclass();
  }
  return conjunto_interfaces;
}

void percorre_grafo__interface(Class<?> nodo, HashSet<Class<?>> conjunto_interfaces) {
  // garanto aqui que nodo é do tipo "interface"
  // podem ter diversas arestas que apontam para nós do tipo "interface"

  if (conjunto_interfaces.add(nodo)) {
    Stream.of(nodo.getInterfaces()).forEach(iface -> percorre_grafo__interface(iface, conjunto_interfaces));
  }
}

Using a standard name/code a little more Java:

public HashSet<Class<?>> percorreGrafo(Object obj) {
  // garanto aqui que nodo é do tipo "objeto"
  // só tem uma aresta que aponta para um nó do tipo "classe"

  return percorreGrafo__classe(obj.getClass());
}

private HashSet<Class<?>> percorreGrafo__classe(Class<?> clazz) {
  // garanto aqui que nodo é do tipo "classe"
  // pode ter uma aresta que aponta para um nó do tipo "classe"
  // podem ter diversas arestas que apontam para nós do tipo "interface"

  HashSet<Class<?>> interfaces = new HashSet<>();
  for (Class<?> iter = clazz; iter != null; iter = iter.getSuperclass()) {
    Stream.of(iter.getInterfaces()).forEach(iface -> percorreGrafo__interface(iface, interfaces));
  }
  return interfaces;
}

private void percorreGrafo__interface(Class<?> clazz, HashSet<Class<?>> interfaces) {
  // garanto aqui que nodo é do tipo "interface"
  // podem ter diversas arestas que apontam para nós do tipo "interface"

  if (interfaces.add(clazz)) {
    Stream.of(clazz.getInterfaces()).forEach(iface -> percorreGrafo__interface(iface, interfaces));
  }
}

Removing Stream:

public HashSet<Class<?>> percorreGrafo(Object obj) {
  // garanto aqui que nodo é do tipo "objeto"
  // só tem uma aresta que aponta para um nó do tipo "classe"

  return percorreGrafo__classe(obj.getClass());
}

private HashSet<Class<?>> percorreGrafo__classe(Class<?> clazz) {
  // garanto aqui que nodo é do tipo "classe"
  // pode ter uma aresta que aponta para um nó do tipo "classe"
  // podem ter diversas arestas que apontam para nós do tipo "interface"

  HashSet<Class<?>> interfaces = new HashSet<>();
  for (Class<?> iter = clazz; iter != null; iter = iter.getSuperclass()) {
    for (Class<?> iface: iter.getInterfaces()) {
      percorreGrafo__interface(iface, interfaces);
    }
  }
  return interfaces;
}

private void percorreGrafo__interface(Class<?> clazz, HashSet<Class<?>> interfaces) {
  // garanto aqui que nodo é do tipo "interface"
  // podem ter diversas arestas que apontam para nós do tipo "interface"

  if (interfaces.add(clazz)) {
    for (Class<?> iface: clazz.getInterfaces()) {
      percorreGrafo__interface(iface, interfaces);
    }
  }
}

Note that the method Set.add(E e) returns true if you don’t have the element yet e, and on top of the added set. Case e already exists, returns false. So, add a node in the set of visited interfaces is already doing at the same time the verification that the element is in the set. So, if interfaces.add(clazz) return true, that means that clazz was not yet in the set and that was added.


How can I be so sure of the construction of these graphs? Well, reading the documentation.

First of all, the language doesn’t make multiple inheritance (grammar described in JLS 8.1.4). Therefore, if I am inheriting from some class (ps: always is), I cannot inherit from any other. Therefore, only possessing at most one superclass.

It is documented in Java that every class inherits from Object, directly or indirectly (JLS 4.3.2). And it’s also documented that Object.class.getSuperclass() returns null (Javadoc).

It also has in the Java language specification that an interface cannot implement itself cyclically (JLS 12.2.1). Therefore, it is impossible to exit an interface and through getInterfaces(), get into it again. I at all times I will arrive at an interface that does not extend any other, an interface that is end of line.


Note that the Virgilio Novic code does the same thing as this answer, but in one method, and returns the appropriate set of interfaces (although it happens to pass through one of these interfaces more than once).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.