Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructor of innerclass is not executed #268

Closed
axelsegers opened this issue Sep 7, 2017 · 5 comments
Closed

Constructor of innerclass is not executed #268

axelsegers opened this issue Sep 7, 2017 · 5 comments

Comments

@axelsegers
Copy link

I just noticed that constructors of inner-classes are not executed.
My parent class has the following code

private List list;

....and the inner class

public class ABC{
public ABC(){
//some code here which is not executed
}
}

Using random-beans the list property is populated as well as the properties of the innerclass ABC. However the constructor of ABC is never executed which blocks me because some important initialisation is there....

@fmbenhassine
Copy link
Member

fmbenhassine commented Sep 8, 2017

I'm not sure I fully understand what you are expecting.

If the list is populated and the properties of ABC are also populated, then random beans has done its work right? Are you expecting RB to call the constructor of ABC?

it would be great If you can provide a test with what is expected. Many thanks upfront

@axelsegers
Copy link
Author

Yes i'm expecting that RB calls the constructor of ABC, which is not happening.

@fmbenhassine
Copy link
Member

fmbenhassine commented Jan 26, 2019

I do confirm, the constructor of the inner class is not called. However, if you declare ABC as static, then the constructor should be called.

This is because Class.getDeclaredConstructor() throws a NoSuchMethodException when the inner class is not static and RB falls back to objenesis in this case which by-passes the constructor.

Can you try making the inner class ABC as static and let me know if it works for you?

@fmbenhassine
Copy link
Member

fmbenhassine commented Feb 9, 2019

Can you try making the inner class ABC as static and let me know if it works for you?

@axelsegers Have you got a chance to test this?

I'm re-reading this thread and based on the previous comments, I believe RB can't do anything in this case. If making the class static works for you, then this is the way to work around the issue. If it is not possible to change the class (may be legacy type you can't change), then I will close the issue and add a note about it in the known limitations section.

Looking forward for your feedback. Thank you upfront.

@fmbenhassine
Copy link
Member

Summing up on this. For inner classes, Class.getDeclaredConstructor() throws an exception. For static nested classes, it does not throw this exception. Here is an example:

import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class TestInnerClass {

    public class ABC {
        public ABC() {
            System.out.println("ABC.ABC");
        }
    }

    public static class DEF {
        public DEF() {
            System.out.println("DEF.DEF");
        }
    }

    public static void main(String[] args) {
        try {
            Constructor<ABC> constructor = ABC.class.getDeclaredConstructor();
            constructor.newInstance();
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
            System.err.println("falling back to objenesis for ABC");
            Objenesis objenesis = new ObjenesisStd();
            objenesis.newInstance(ABC.class);
        }

        System.out.println("#####");

        try {
            Constructor<DEF> constructor = DEF.class.getDeclaredConstructor();
            constructor.newInstance();
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
            System.err.println("falling back to objenesis for DEF");
            Objenesis objenesis = new ObjenesisStd();
            objenesis.newInstance(DEF.class);
        }
    }
}

Which prints:

java.lang.NoSuchMethodException: io.github.benas.randombeans.beans.TestInnerClass$ABC.<init>()
	at java.base/java.lang.Class.getConstructor0(Class.java:3350)
	at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2554)
	at io.github.benas.randombeans.beans.TestInnerClass.main(TestInnerClass.java:48)
falling back to objenesis for ABC
#####
DEF.DEF

Yes i'm expecting that RB calls the constructor of ABC, which is not happening.

For inner classes, Random Beans will fall back to using Objenesis (mostly as shown in the previous example) which will create the instance without calling the constructor (See Javadoc of Objenesis#newInstance(Class). And that's why the constructor of the inner class is not called.

As said previously, I'm not sure RB can do something to overcome this, So I added a section about this limitation in the known limitations page.

@axelsegers Thank you anyway for opening this issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants