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
Wrong super constructor is called #582
Comments
Ok... So, the call to The super constructor that gets called is not chosen at random, but it simply is the first one to be found in the classfile. The JVM spec doesn't require the order of methods/constructors to be preserved in the classfile (when a ".java" file is compiled to its ".class" file), but normally the order is preserved (and since That said, it should not matter which super constructor is called (and with which arguments), since all the classes (with all methods and constructors), starting from the one in the Ideally, yes, the same constructor that gets called from the unmocked constructor body should be the one to be called. Or at least, the accessible super constructor with the fewer parameters. So, an enhancement could be made to avoid situations like this. It would help to a have a reproducible test case, though. |
You can find a (hopefully) reproducible test case at https://github.com/andi5/jmockit-wrong-super |
I don't think there is a problem when the constructor is actually mocked. But when instantiating the non-mocked subclass I guess what might work is, to search in the original constructor the original super constructor call and copy it as first instruction, including the arguements given and then continue. |
And btw. I just now also tested with different Java version, with Java 10.0.2 it does not happen, with 11.0.1 it is happening. |
While of course even when the exception does not happen, potentially the wrong constructor is used generally. If I e. g. the |
Unfortunately the fix you did is not enough. But as you can see in With your fix-commit for this, it should also consistently fail with and without debug and on all Java versions as now the selected constructor does not depend on the order of constructors anymore. |
Those cases will be handled when #492 gets resolved. |
I see, thanks for the info. |
We had very strange behavior:
@Mocked javax.faces.context.PartialResponseWriter writer;
responseWriter = new TestResponseWriter();
javax.faces.context.ResponseWriter
which both classes extend from (one directly, one indirectly) has no explicit constructor, just the default implied no-arg constuctorjava.io.Writer
on the other hand has two protected constructors, one no-arg and one with anObject
parameter that must not benull
ResponseWriter
that calls the one-arg constructor ofWriter
.So after a couple of hours of adding stdout-debugging to JMockit and digging my way through subtle differences in the output, I got to the root cause.
In
mockit.internal.expectations.mocking.MockedClassModifier#visitMethod
you callgenerateCallToSuperConstructor()
.I'm not sure why this is done, I guess so that you are able to then add the call to the
MockingBridge
, as the super-constructor always has to be called first.The problem is, that your code calls a random super constructor with default values according to types. I'm not sure this is the best decision, as different constructors can ensure different invariants and so calling a random one might not be the best solution. Maybe it would better to look into the actual implementation of the constructor and calling the super-constructor the real method also is calling? But even then using default values for the arguments might not be the best solution.
In my case here, after adding
to
mockit.internal.SuperConstructorCollector#findConstructor
I have seen that without debug I getwhereas with debug I get
and the code just takes the first one it finds.
In my case without debug this was the one-arg constructor that was given
null
as parameter and thus produced that NPE.So one problem is, that it sometimes uses one constructor, sometimes the other, another problem probably is that actually it uses some random constructor that might have requirements or produces certain invariants.
The text was updated successfully, but these errors were encountered: