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

[Suggestion] A plugin that only removes the final modifier #1223

Closed
tmurakami opened this issue Oct 26, 2017 · 4 comments
Closed

[Suggestion] A plugin that only removes the final modifier #1223

tmurakami opened this issue Oct 26, 2017 · 4 comments

Comments

@tmurakami
Copy link
Contributor

With the inline mock making feature, Android app developers may face VerifyError when testing an Android project that relies on proguarded Android libraries, such as Google Play Services.
This is probably because those library developers (not the ProGuard team) explicitly use -dontpreverify option in order to reduce build time.
The option destroys stack map tables, but Android VM does not need any stack map table.

BTW, if the proguarded class is non-final, it is possible to create its mock object with the default MockMaker and stub the methods.
Since the default MockMaker creates mocks by subclassing, VerifyError does not occur even if the stack map table of the mock type is corrupted.
(Although of course Answers#CALLS_REAL_METHODS will not work for these mocks...)

Therefore, providing a plugin that only removes the final modifier might solve the problem without specifying -noverify.

Please point out if there is any misunderstanding.

@TimvdLippe
Copy link
Contributor

My 2 cents: I am not sure this is something we as Mockito developers have to pursue. Feel free to write the plugin yourself and maybe we can add a mention of it in our documentation as a potential solution.

@mockitoguy
Copy link
Member

Thank you for reporting @tmurakami!

It is not clear to me how such plugin would work.

Can you hack on Mockito codebase and submit a PR? This would help us understand what you mean by the plugin. Do you need new public API from Mockito or you can rely on existing MockMaker API (or one of our other extensions).

@tmurakami
Copy link
Contributor Author

What I was considering was a Java Agent which removes final modifier when loading class.
However, I might have come up with a better way to solve this problem.

Problems such as #1000 and #1005 occur because stack map frames are incorrect.
Then, I came up with an idea to compute the frames of those methods before InlineBytecodeGenerater redefines them.

As a workaround, when I introduced the following MockMaker instead of mock-maker-inline, #1000 and #1005 errors did not occur.

public class MyMockMaker extends InlineByteBuddyMockMaker {

    static {
        ByteBuddyAgent.install().addTransformer(new Transformer(), true);
    }

    private static class Transformer implements ClassFileTransformer {
        @Override
        public byte[] transform(ClassLoader loader,
                                String className,
                                Class<?> classBeingRedefined,
                                ProtectionDomain protectionDomain,
                                byte[] classfileBuffer) throws IllegalClassFormatException {
            if (classBeingRedefined == null) {
                return null;
            } else {
                ClassReader cr = new ClassReader(classfileBuffer);
                ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
                cr.accept(cw, SKIP_FRAMES);
                return cw.toByteArray();
            }
        }
    }

}

I'm not sure because I am not an expert of Java bytecode.
But are there any downsides to computing frames before redefining the method on InlineBytecodeGenerater?

@tmurakami
Copy link
Contributor Author

I close this issue because I have lost interest in 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

3 participants