Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find "default" method from an interface using java reflection?

I want to find if a method is a "default method" through java reflection.I have tried printing the methods of java.lang.Iterable.


Code Snippet :

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectionTest {

public static void main(String[] args) {
    Class c = Iterable.class;

    for(Method m : c.getDeclaredMethods())
    {
        System.out.print(Modifier.toString(m.getModifiers()));
        System.out.println("  "+m.getName());
    }
  }
}


Result :

public abstract  iterator
public  spliterator
public  forEach

here , spliterator() and forEach() should have printed default.
Please correct me if my interpretation is wrong.

like image 880
Suresh Anbarasan Avatar asked Aug 24 '14 21:08

Suresh Anbarasan


2 Answers

In recent versions of java8 updates , we have isDefault() in java.lang.reflect.Method class , which does the trick.
Modifying my previous code a bit yields the result.

Code:

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectionTest {

  public static void main(String[] args) {
    Class c = Iterable.class;

    for(Method m : c.getDeclaredMethods())
    {
        System.out.print(Modifier.toString(m.getModifiers()));
        System.out.println("  "+(m.isDefault()?"default ":"")+m.getName());
    }
  }
}


Output:

public abstract  iterator
public  default spliterator
public  default forEach


Note: I have tested this in jdk8 update 20

like image 74
Suresh Anbarasan Avatar answered Oct 10 '22 09:10

Suresh Anbarasan


Don’t rely on Modifier.toString in that way. In the past, the modifiers for classes, fields, and methods were given unique distinct values so you could interpret them without looking at the type of the entity owning the modifier like that method suggests.

But while Java evolved, more modifier bits were added and it wasn’t possible to hold that property. In particular, when passing the modifier bits of a method to Modifier.toString unmodified, you will get the following surprising behavior:

  • a bridge method will be printed as volatile
  • a varargs method will be printed as transient

Therefore you should filter the bits. Java 7 introduced a method providing the right mask so that you could use Modifier.toString(m.getModifiers()&Modifier.methodModifiers()).

But this only works because the old Java keywords map to unique modifier bits and the newer modifier bits are not associated with keywords. With newer Java versions even this might be insufficient.

For the default keyword, it is even simpler: there is no modifier bit associated with the keyword. If a public, non-abstract, non-static method appears in an interface, it must be a default method. That’s how Method.isDefault() determines whether a method is a default method. Modifier.toString(…) has no chance of knowing whether the declaring class is an interface and therefore will never print default.

like image 29
Holger Avatar answered Oct 10 '22 07:10

Holger