Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call a private method that exists inside a private inner class

I want to test a private method that existe inside a private inner class

 public class MyBigClass {
    private class MyInnerClass {
       private void wantedMethod() {
       }
    }
 }

I want to call the wantedMethod() to test it

Here is my code

Class[] classes = MyBigClass.class.getDeclaredClasses();
    for (int i = 0; i < classes.length; i++) {
        // this code print "MyInnerClass"
        System.out.println(">> inner classes >> " + classes[i].getSimpleName());
        if (classes[i].getSimpleName().equals("MyInnerClass")) {
            Class clazz = classes[i];
            // Constructor c=clazz.getConstructor();
            Method[] methods = clazz.getDeclaredMethods();
            // this code print "wantedMethod"
            for (int j = 0; j < methods.length; j++) {
                System.out.println("inner class methods >>  " + methods[i].getName());
            }

        }

    }    

Problem : I cannot call wantedMethod()

like image 972
josephino Avatar asked May 16 '12 11:05

josephino


2 Answers

If you want to invoke a non-static method you need to tell on which object you want to invoke it. In your case you want inner class object, but since you don't have one yet you need to create it. Since Java can't let inner class object be created without outer class object you will need to create that outer object too.

So these are steps you need to take:

  • create outer class object (if you don't have one),
  • using outer class object create inner class object,
  • invoke method on inner class object.

You can do it like this:
(you just need to remember that default constructors have same visibility as visibility of its class, so private class will have private constructor which we will need to make accessible before we will be able to use it)

try {
    //creating parent object
    Object outer = new MyBigClass();

    //creating inner class object
    Class<?> innerClass = Class.forName("MyBigClass$MyInnerClass");
    Constructor<?> constructor = innerClass.getDeclaredConstructor(MyBigClass.class);//inner object must know type of outer class
    constructor.setAccessible(true);//private inner class has private default constructor
    Object child = constructor.newInstance(outer);//inner object must know about its outer object

    //invoking method on inner class object
    Method method = innerClass.getDeclaredMethod("wantedMethod",new Class<?>[]{});
    method.setAccessible(true);//in case of unaccessible method
    method.invoke(child,new Object[]{});

} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

You can find more info about creating inner class object via reflection in this question

like image 51
Pshemo Avatar answered Nov 14 '22 22:11

Pshemo


This is because your class isn't named CodeCircuit. Remove that if condition and it will work.

Also remove the line Constructor c=clazz.getConstructor(); as it throws an exception.

After making these changes, your own code prints

>> inner classes >> MyInnerClass
inner class methods >>  wantedMethod

EDIT

Use this code to execute the method.

    Class<?>[] classes = MyBigClass.class.getDeclaredClasses();

    for (Class<?> clazz : classes) {
        if(clazz.getSimpleName().equals("MyInnerClass")) {
            Method method = clazz.getDeclaredMethod("wantedMethod", new Class[] {});
            method.setAccessible(true);
            method.invoke(clazz.getDeclaredConstructor(MyBigClass.class).newInstance(new MyBigClass()), new Object[] {});
        }
    }

The syntax is a bit strange, making you to use the outer class for getting hold of the inner class constructor. It behaves as if you have a constructor with the below signature defined in your inner class:

public MyInnerClass(MyBigClass bigClass) {
}

But, I assume that's how Java handles inner (nested) classes using reflection.

Note that you'll have to provide a public constructor for your inner class.

public class MyBigClass {
    private class MyInnerClass {
        public MyInnerClass() {
            System.out.println("hello");
        }
        private void wantedMethod() {
            System.out.println("world");
        }
    }
}

You'll also have to setAccessible(true) on the private method in order to be able to invoke it.

EDIT 2

Upon further investigation, when I decompiled the generated MyBigClass$MyInnerClass.class class, I found that my hunch was right:

public class MyBigClass$MyInnerClass {
    public MyBigClass$MyInnerClass(MyBigClass paramMyBigClass) {
        System.out.println("hello");
    }
    private void wantedMethod() {
        System.out.println("world");
    }
}

Would be really glad if someone can throw some light into this behaviour

like image 21
adarshr Avatar answered Nov 14 '22 22:11

adarshr