moagrius / TileView

TileView is a subclass of android.view.ViewGroup that asynchronously displays, pans and zooms tile-based images. Plugins are available for features like markers, hotspots, and path drawing.
MIT License
1.46k stars 337 forks source link

JUnit Tests Fail When Using JACK/Java 8 on Consuming Application #382

Closed MisterRager closed 7 years ago

MisterRager commented 7 years ago

I have a test failure related to how the library is compiled when using Java 8/JACK:

java.lang.VerifyError: Expecting a stackmap frame at branch target 43
Exception Details:
  Location:
    com/qozix/tileview/widgets/ZoomPanLayout.setScale(F)V @12: ifeq
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0x0000000: 2a23 b700 7144 2ab4 002b 2395 9900 1f2a
    0x0000010: b400 2b45 2a23 b500 2b2a b700 8d2a b700
    0x0000020: 6d2a 2324 b600 812a b600 80b1          

        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
        at java.lang.Class.getConstructor0(Class.java:3075)
        at java.lang.Class.getConstructor(Class.java:1825)
        at android.view.LayoutInflater.createView(LayoutInflater.java:580)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:743)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
        at com.myjob.android.fragments.LinkDetailFragment.onCreateView(LinkDetailFragment.java:117)
        at android.support.v4.app.Fragment.performCreateView(Fragment.java:2087)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1113)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1295)
        at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801)
        at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1682)
        at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:541)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at org.robolectric.shadows.ShadowMessageQueue.dispatchMessage(ShadowMessageQueue.java:144)
        at org.robolectric.shadows.ShadowMessageQueue.access$100(ShadowMessageQueue.java:30)
        at org.robolectric.shadows.ShadowMessageQueue$1.run(ShadowMessageQueue.java:105)
        at org.robolectric.util.Scheduler.runOrQueueRunnable(Scheduler.java:293)
        at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:143)
        at org.robolectric.shadows.ShadowMessageQueue.enqueueMessage(ShadowMessageQueue.java:126)
        at android.os.MessageQueue.enqueueMessage(MessageQueue.java)
        at android.os.Handler.enqueueMessage(Handler.java:631)
        at android.os.Handler.sendMessageAtTime(Handler.java:600)
        at android.os.Handler.sendMessageDelayed(Handler.java:570)
        at android.os.Handler.post(Handler.java:326)
        at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1568)
        at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:696)
        at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:662)
        at org.robolectric.shadows.support.v4.SupportFragmentTestUtil.startFragment(SupportFragmentTestUtil.java:17)
        at com.myjob.android.fragments.LinkDetailFragmentTest.setUp(LinkDetailFragmentTest.java:40)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:248)
        at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:174)
        at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:63)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:140)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
p-lr commented 7 years ago

I see that you are using Robolectric. Are you sure that this is not related to this (because robolectric provides an implementation of android.jar but it may not be suitable in that particular test).

MisterRager commented 7 years ago

This also shows up in the designer view - no Robolectric there. I think I have an idea on how to fix it. PR imminent...

MisterRager commented 7 years ago

I can't seem to test this. When I use debug builds of the library, I can't get the client app to crash, but I can't seem to even use the aar from release builds. @moagrius what is the setup you use for building the actual lib?

MisterRager commented 7 years ago

This is the fix I'm trying to find a way to test:

https://github.com/moagrius/TileView/compare/master...MisterRager:compile-with-1.8-support

MisterRager commented 7 years ago

Another oddity: when I run the test with the -noverify flag, this is the error: https://github.com/robolectric/robolectric-gradle-plugin/issues/145

moagrius commented 7 years ago

i've never tried with java 8. i don't do anything special to build in AS, but i do publish the artifacts using a gradle task, based off this: https://raw.githubusercontent.com/blundell/release-android-library/master/android-release-aar.gradle

does that help?

moagrius commented 7 years ago

i'm going to close this since Jack is being abandoned by google

MisterRager commented 7 years ago

Opened a pull request: https://github.com/moagrius/TileView/pull/407

Also, the library is incompatible with the preview desugar that Google is using for JDK 8 support going forward. My intuition says "yes" since the bytecode produced by proguard will be incompatible with the runtime doing the dexing.

Granted, this is Java 8 in the build toolchain, not Java 8 in the actual project.

MisterRager commented 7 years ago

I can't seem to compile, still, and javap -v com/qozix/tileview/widgets/ZoomPanLayout on the decompressed classes.jar I obtain form bintray shows no stackmap frames as well as bytecode version 0x51 (JDK 7).

MisterRager commented 7 years ago

@moagrius I think bintray might not update the artifacts w/o a version bump. Could you possibly throw me the .aar file for the release you sent out so I can see whether the settings took effect on your build?

MisterRager commented 7 years ago

Desugar bug: https://issuetracker.google.com/issues/37909288

moagrius commented 7 years ago

yeah i have to manually upload to bintray - i'll try to do it tonight

moagrius commented 7 years ago

i'm getting errors when building master (for the release):

:demo:transformClassesWithDexForDebug
Running dex in-process requires build tools 23.0.2.
For faster builds update this project to use the latest build tools.
Dex: Error converting bytecode to dex:
Cause: Dex cannot parse version 52 byte code.
This is caused by library dependencies that have been compiled using Java 8 or above.
If you are using the 'java' gradle plugin in a library submodule add 
targetCompatibility = '1.7'
sourceCompatibility = '1.7'
to that submodule's build.gradle file.
    UNEXPECTED TOP-LEVEL EXCEPTION:
    com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
        at com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)
        at com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
        at com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)
        at com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)
        at com.android.dx.command.dexer.Main.processClass(Main.java:704)
        at com.android.dx.command.dexer.Main.processFileBytes(Main.java:673)
        at com.android.dx.command.dexer.Main.access$300(Main.java:83)
        at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:602)
        at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
        at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
        at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
        at com.android.dx.command.dexer.Main.processOne(Main.java:632)
        at com.android.dx.command.dexer.Main.processAllFiles(Main.java:510)
        at com.android.dx.command.dexer.Main.runMonoDex(Main.java:280)
        at com.android.dx.command.dexer.Main.run(Main.java:246)
        at com.android.dx.command.dexer.Main.main(Main.java:215)
        at com.android.dx.command.Main.main(Main.java:106)

...while parsing com/qozix/tileview/BuildConfig.class
1 error; aborting
:demo:transformClassesWithDexForDebug FAILED

FAILURE: Build failed with an exception.

I remember we tried to move to Java 8 at work and finally rolled it back because A) it created a ton of hassle, and B) Jack has been abandoned by Google

Does this change require Java 8?

MisterRager commented 7 years ago

Let me try to get an environment with JDK 7 - I wasn't able to test on my dev laptop because Ubuntu dropped the package.

MisterRager commented 7 years ago

Here's a test project to demonstrate the errors with the new desugar tool: https://github.com/MisterRager/TestDesugarJdk7Libs

moagrius commented 7 years ago

so this change won't work with 7?

gavra0 commented 7 years ago

Hi, Android plugin for Gradle dev here. The issue with the StackMapTable is due to usage of -dontpreverify flag, which got added to the build.gradle of 2.2.6 tileview library: proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

The issue is that the default Proguard settings in the plugin contain this flag. We are tracking this issue https://issuetracker.google.com/issues/37137716.

To publish a version that contains a valid StackMapTable, you don't have to specify -target 8 in you Proguard rules (this would make it incompatible with projects which do not use Desugar). Just avoid including the default, proguard-android.txt, in the build until we resolve the issue.

Thanks!

moagrius commented 7 years ago

@gavra0 thanks for the info. @MisterRager have you got it from here?

MisterRager commented 7 years ago

@gavra0 thanks for chiming in. @moagrius PR opened - see that for more info #412