linkedin / linkedin/dexmaker

Multidex incompatible class change error

Open
#67 3 comments 1 reaction 0 assignees View on GitHub
Dominant language
Java
Stars
2k
Forks
262
PR merge metrics
No merged PRs in 30d

Description

Hi,

I'm working on an application that uses dexmaker-mockito:2.2.0 in its instrumentation tests. I recently crossed the dex limit so I integrated multidex to continue development. After multidex was integrated I began seeing the error below when calling Mockito.spy:

> java.lang.IncompatibleClassChangeError: Class 'com.android.dx.util.ByteArrayAnnotatedOutput' does not implement interface 'com.android.dex.util.ByteOutput'
in call to 'void com.android.dex.util.ByteOutput.writeByte(int)'
(declaration of 'com.android.dex.Leb128' appears in /data/app/com.example.test-2/base.apk:classes12.dex)
at com.android.dex.Leb128.writeUnsignedLeb128(Leb128.java:140)
at com.android.dx.util.ByteArrayAnnotatedOutput.writeUleb128(ByteArrayAnnotatedOutput.java:244)
at com.android.dx.dex.file.ClassDataItem.encodeSize(ClassDataItem.java:378)
at com.android.dx.dex.file.ClassDataItem.encodeOutput(ClassDataItem.java:347)
at com.android.dx.dex.file.ClassDataItem.place0(ClassDataItem.java:328)
at com.android.dx.dex.file.OffsettedItem.place(OffsettedItem.java:242)
at com.android.dx.dex.file.MixedItemSection.placeItems(MixedItemSection.java:311)
at com.android.dx.dex.file.DexFile.toDex0(DexFile.java:541)
at com.android.dx.dex.file.DexFile.toDex(DexFile.java:214)
at com.android.dx.DexMaker.generate(DexMaker.java:324)
at com.android.dx.DexMaker.generateAndLoad(DexMaker.java:422)
at com.android.dx.stock.ProxyBuilder.buildProxyClass(ProxyBuilder.java:266)
at com.android.dx.mockito.DexmakerMockMaker.createMock(DexmakerMockMaker.java:60)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:63)
at org.mockito.Mockito.mock(Mockito.java:1637)
at com.example.application.test.utils.MockHelper.mock(MockHelper.java:23)
at com.example.application.arch.testmodules.TestUtilsModule.providesPhoneNumberResolver(TestUtilsModule.java:72)
at com.example.application.arch.testmodules.TestUtilsModule_ProvidesPhoneNumberResolverFactory.get(TestUtilsModule_ProvidesPhoneNumberResolverFactory.java:38)
at com.example.application.arch.testmodules.TestUtilsModule_ProvidesPhoneNumberResolverFactory.get(TestUtilsModule_ProvidesPhoneNumberResolverFactory.java:11)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.example.application.test.exampleRootModule_MembersInjector.injectMembers(exampleRootModule_MembersInjector.java:289)
at com.example.application.test.exampleRootModule_MembersInjector.injectMembers(exampleRootModule_MembersInjector.java:38)
at com.example.application.arch.DaggerTestComponent.inject(DaggerTestComponent.java:2680)
at com.example.application.test.exampleRootModule.onInitialize(exampleRootModule.java:392)
at com.example.runner.Core.start(Core.java:213)
at com.example.runner.Runner.onStart(Runner.java:53)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879)

The errors appears to be caused by a mismatch between com.android.dex.Leb128 and com.android.dx.util.ByteArrayAnnotatedOutput. ByteArrayAnnotatedOutput isn't included from any other library and the Mockito version is the one specified by dexmaker.

Interestingly, only some instances of Mockito.mock have the above issue. The code diverges at DexMaker:190:
> File result1 = new File(dexCache, this.generateFileName());

For instances where the mock is correctly loaded, result1 exists. For instances where the mock encounters the above error, result1 does not exist.

I thought the problem might have been due to the class not being packaged in the main dex file, but adding the class to the multidex keep file didn't fix the issue.

Unfortunately, I can't provide you with a minimal working example because the exact cause of the problem is hard to nail down. However, I'm interested to get some insight into how an IncompatibleClassChangeError might occur in this scenario.

Thanks,

Andrew

Contributor guide

Open the contributing guide

Research direction

Start with the reported stack trace through DexMaker.generate, DexMaker.generateAndLoad, ByteArrayAnnotatedOutput, and Leb128, then compare the successful and failing Mockito.mock cases at DexMaker.java:190. Reproduce the multidex instrumentation-test failure and determine why the incompatible classes are loaded together; done means a minimal reproduction or a documented root cause and verification.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, java
Domain
mobile, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.