mercredi 14 décembre 2016

Java Reflection Edge Case with Nested Classes [duplicate]

This question already has an answer here:

Motivation: A friend of mine holds a tutorial at university for the new students and I visited him today. He got an exercise for the class and I did it, the most complicated and worst way possible. However, I stumbled across an unexpected exception on Reflection, when I tried to instance a nested class.

I broke down the classes to get a more simple example (Ignore the fact, that nobody ever would do that):

public class DeepJavaNested {

    /**
     * A method, that holds an inner class
     */
    public void outerClassFoo() {

        /**
         * Class enclosed by method
         */
        class InnerClass {

            /**
             * Default constructor of InnerClass
             */
            public InnerClass() {
                System.out.println("Constructed instance of " + getClass().getName());
            }

            /**
             * Just to test the created object
             */
            public void foo() {
                System.out.println("Successfully invoked a pointless method!");
            }
        }
    }
}

Additionally I have a main method which tries two things. At first, it gets the Reflection class object of the nested class:

    Class<?> innerClass = null;

    try {
        innerClass = Class.forName("deep.nested.DeepJavaNested$1InnerClass");
    } catch (ClassNotFoundException e) {
        assert false;
    }

Then, it tries to invoke the constructor by the two ways, Reflection offers:

    try {
        // get the (obviously declared) default constructor for the inner class
        Constructor<?> innerClassConstructor = innerClass.getConstructor();
        // set it accessible, just in case, I am missing something, that would hide it
        innerClassConstructor.setAccessible(true);

        // invoke the constructor and get an instance of InnerClass
        Object instanceOfInnerClass = innerClassConstructor.newInstance();
        // invoke test method
        innerClass.getMethod("foo").invoke(instanceOfInnerClass);
    } catch (NoSuchMethodException e) {
        System.err.println("Reflection failed to find constructor: " + e.getMessage());
    } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
        e.printStackTrace();
    }

And, because I know, that this does not work; the second way:

    try {
        // invoke the default constructor using the evil way
        Object innerClassObj = innerClass.newInstance();
        // invoke test method
        innerClass.getMethod("foo").invoke(innerClassObj);
    } catch (InstantiationException e) {
        System.err.println("Reflection failed to instance class: " + e.getMessage());
    } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
        e.printStackTrace();
    }

The resulting output of the application:

Reflection failed to find constructor: deep.nested.DeepJavaNested$1InnerClass.<init>()
Reflection failed to instance class: deep.nested.DeepJavaNested$1InnerClass

So obviously, Java cannot find the public constructor and is also unable to create an instance of the class with the messy way, that also expects a default constructor to be available.

My question now: Did I miss something, or is Java Reflection not able to instance classes, that are not enclosed by a class, but by a method?

The whole code example is also available as a Gist: http://ift.tt/2hOs6f3





Aucun commentaire:

Enregistrer un commentaire