javareflectioninvokenosuchmethod

Java Reflection NoSuchMethodException when referencing a method in same class


I am experiencing a NoSuchMethodException when trying to call getMethod on a method in the same class with no arguments from a string name pulled from a hashmap. Any advice, or another way to call a method in the same class given only a String name of the method? The call to get the method is here:

if (testChoices.containsKey(K)) {
        String method = testChoices.get(K);
        System.out.println(method);

        try {
            java.lang.reflect.Method m = TST.getClass().getMethod(method);
            m.invoke(testChoices.getClass());
        } catch (NoSuchMethodException e1) {
            // TODO Auto-generated catch block
            System.out.println("No method found");
            e1.printStackTrace();
        } catch (SecurityException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();


        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();

One of the methods I am trying to call is here:

private static void testgetDomainLic() throws IOException {

And the map entry being called is here:

testChoices.put(1, "testgetDomainLic");

Solution

  • I think in your case you can just change getMethod to getDeclaredMethod. getMethod only returns public methods.

    The hiccup here is that they actually have different semantics other than whether or not they return non-public methods. getDeclaredMethod only includes methods which are declared and not inherited.

    So for example:

    class Foo { protected void m() {} }
    class Bar extends Foo {}
    Foo actuallyBar = new Bar();
    // This will throw NoSuchMethodException
    // because m() is declared by Foo, not Bar:
    actuallyBar.getClass().getDeclaredMethod("m");
    

    In the worst case like this, you have to loop through all declared methods, like this:

    Class<?> c = obj.getClass();
    do {
        for (Method m : c.getDeclaredMethods())
            if (isAMatch(m))
                return m;
    } while ((c = c.getSuperclass()) != null);
    

    Or accounting for interfaces (mostly because they can declare static methods now):

    List<Class<?>> classes = new ArrayList<>();
    for (Class<?> c = obj.getClass(); c != null; c = c.getSuperclass())
        classes.add(c);
    Collections.addAll(classes, obj.getClass().getInterfaces());
    Method m = classes.stream()
                      .map(Class::getDeclaredMethods)
                      .flatMap(Arrays::stream)
                      .filter(this::isAMatch)
                      .findFirst()
                      .orElse(null);
    

    And as a side note, you probably don't need to call m.setAccessible(true), because you're invoking it from within the class that declares it. This is necessary, though, in other contexts.