linkedin / dexmaker

A utility for doing compile or runtime code generation targeting Android's Dalvik VM
Apache License 2.0
1.88k stars 249 forks source link

Multidex incompatible class change error #67

Open andrewemery opened 7 years ago

andrewemery commented 7 years ago

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

alvminvm commented 7 years ago

I met the same problem as above.

ProxyBuilder
.forClass(clazz)
.dexCache(context.getApplicationContext().getDir("dx", 0))
.handler(this.mHandler)
.build();
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 'java.lang.reflect.ArtMethod' appears in /system/framework/core-libart.jar)
                                                       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.stock.ProxyBuilder.build(ProxyBuilder.java:213)
                                                       at me.alzz.mvp.PresenterFactory.newPresenter(PresenterFactory.java:85)
                                                       at me.alzz.mvp.Presenter.bind(Presenter.java:62)
TimvdLippe commented 5 years ago

We are facing the same issues. We have consistent failures in 2 tests, while all other tests are just fine. Both tests that exhibit this behavior are using multidex.

ed-abe commented 5 years ago

Has there been any update on this issue?