0

I'm in the situation like a class contains the same method name, and we are trying to use reflection to call, but it's seemed to have an issue when one of the argument contains null

For example :


package test;

public class Invoker {
    public void test(String a, Integer b) {
        System.out.println("String, Integer");
    }

    public void test(Integer a, Integer b) {
        System.out.println("Integer, Integer");
    }

    public void invoke(String methodName, Object ...args) {
        try {
           Class<?>[] clazz = new Class[args.length];
            int i=0;
           for(Object a:args) {
               clazz[i++] = a != null ? a.getClass() : null;
           }

           Method m = this.getClass().getMethod(methodName, clazz);

           // ... Continue for invocation

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String ...args) {
        Invoker invoker = new Invoker();

        // happened to be null sometimes
        String a = null;
        Integer b = 123;

        System.out.println("Trigger Normally");
        invoker.test(a, b);

        System.out.println("Trigger via Reflection");
        invoker.invoke("test", a, b);
    }
}

Result

Trigger Normally
String, Integer
Trigger via Reflection
java.lang.NoSuchMethodException: test.Invoker.test(null, java.lang.Integer)
    at java.lang.Class.getMethod(Class.java:1678)
    at test.Invoker.invoke(Invoker.java:21)
    at test.Invoker.main(Invoker.java:42)

The Argument sometimes happened to be null, but if it is null, It will trigger NoSuchMethodException

Our method name not intended to be unique, it has to be overload structure.

Data Feed
  • 11
  • 1

1 Answers1

1

Due to early binding the overloaded method being called is determined at compile time (or if it can't be determined, you'll get a compile-time error). Since you have String a = null, the compiler can determine that you want to call test(String, Integer).

Your reflection call is happening at runtime and missing type information from your null parameter (the method doesn't know it originated from a String a, the compiler knew that at compile time, but this is runtime), so you need to provide information whether it's a null String or Integer.

If you want to have your reflection method work with null values (and overloaded methods), you would need to add a separate type parameter to use in case of nulls. For example

invoker.invoke("test", a, String.class, b, Integer.class);

You can't get it to work for nulls without additional type information, since it would be like invoking test(null, 1). The compiler needs your help in this case too, e.g. test((Integer)null, 1) or test((String)null, 1), try it out.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • hm... I can't enforce my team member to specify every single class and arguments when they trying to call, this is why I was thinking is there any elegant way to fulfil this. – Data Feed Nov 09 '20 at 12:33
  • 1
    @DataFeed reflection shouldn't really be used as a general tool. Why did you even decide to use reflection here? What are you *actually* trying to do? – Kayaman Nov 09 '20 at 13:41