0

I'm using reflection discover a method satisfying some conditions and to invoke the found method.

Check following code. Using Groovy..

class TestClass<T>{
    T hello(){
        return null
    }
}

class TestSubClass extends TestClass<List<String>>{

    List<String> hello(){
        return null
    }
}

TestSubClass.methods.each{
    if(it.name.contains("hello")){
        println it.toGenericString()
    }
}

which prints out

public java.util.List<java.lang.String> TestSubClass.hello() // <-- most relevant method for a user of this class
public java.lang.Object TestSubClass.hello()
public java.lang.Object TestSubClass.super$2$hello()

Java reflection is returning multiple declarations of same method based on inheritance/generics, which is understandable.

In my case, I'd like to discover the method with most appropriate signature, including exact type of returnTypes. For example, in the above example, the 1st method in the output has full signature and that's the one we'd usually invoke (without reflection).

Note: above is a simplified example. The real logic is not about finding methods based on naming.

phanin
  • 5,327
  • 5
  • 32
  • 50
  • Why would that be "the most appropriate"? You also haven't really asked a question. I assume you're having problems with the pruning, if so, what problems? – Jorn Vernee Feb 24 '17 at 23:13
  • Thanks @JornVernee . I've updated the question. I think that's the most appropriate 'Method' because it holds the full signature including generic types, whereas others just say `Object` – phanin Feb 24 '17 at 23:22

3 Answers3

1

The Java specifications require a method to marked synthetic if it is not explicitly in the source code.

A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).

JAVA specifications

You can try:

TestSubClass.methods.each{
    if(it.name.contains("hello") && !m.isSynthetic()){
        println it
    }
}

You can also check against if the method is bridged. Which is a similar concept: https://stackoverflow.com/a/5007394/1754020

Community
  • 1
  • 1
Eddie Martinez
  • 13,582
  • 13
  • 81
  • 106
1

The compiler generates the other 2 methods. Luckily, there is a property that you can check to see this: synthetic:

TestSubClass.declaredMethods.each{
    if(it.name.contains("hello") && !it.synthetic) {
        println it.toGenericString()
    }
}

Which now prints just:

public java.util.List<java.lang.String> test.TestSubClass.hello()
Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
0

In my case, I'd like to discover the method with most appropriate signature, including exact type of return Types.

If it's the Java API that you're wondering about, then you'll want to look at class Class. It contains a large number of reflective methods that allow you to interrogate types.

For example, the following code fragment searches all the methods declared on a supplied type for one method which: takes no arguments, is public and static, and has a return type of DateSerial.Config...

public static <D extends DateSerial<?>> DateSerial.Config<D> obtainMetadata(Class<D> cls) {

    Method exe = Stream.of(cls.getDeclaredMethods())
            .filter(m -> m.getParameterCount() == 0  && 
                         m.getReturnType() == DateSerial.Config.class)
            .filter(m -> { 
                    int mod = m.getModifiers();
                    return Modifier.isStatic(mod) && Modifier.isPublic(mod); 
                }) 
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException(
                    "No metadata accessor for " + cls.getName()));

            :
            :
}

You can get as precise with your interrogations as you need. For example, you can filter methods based on those with a certain number of arguments, the last of which is a String[] array, etc. etc. Caveat emptor: Java reflective code is verbose, ugly, and can be hard to read.

scottb
  • 9,908
  • 3
  • 40
  • 56