Spring for Android Build Failing when Including spring-social-twitter
Asked Answered
C

2

0

On Android Studio 0.8.2, I am trying to create an app that integrates with Twitter using Spring. Had innumerable build problems until I created a blank activity that I'm just using the test my Gradle build.

Every time I try to connect to spring-social-twitter, the build fails. If I comment out the Twitter dependency, the app compiles. I'm pretty sure this has nothing to do with the app itself, because I'm testing it on a blank app.

What am I doing wrong?

My build.gradle file:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 20
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "com.example.testapplication"
        minSdkVersion 8
        targetSdkVersion 20
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    packagingOptions {
        exclude 'META-INF/ASL2.0'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/notice.txt'
    }
}

configurations.compile {
    exclude module: 'spring-core'
    exclude module: 'spring-web'
    exclude module: 'commons-logging'
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:20.+'
    compile 'org.springframework.android:spring-android-rest-template:1.+'
    compile 'org.springframework.android:spring-android-auth:1.+'
    compile 'org.springframework.android:spring-android-core:1.+'
    compile 'org.springframework.security:spring-security-crypto:3.+'
    compile 'org.springframework.social:spring-social-core:1.+'
    compile 'org.springframework.social:spring-social-twitter:1.+' // <- The offending line
    compile 'com.fasterxml.jackson.core:jackson-databind:2.3.2'
}

The error:

Error:Execution failed for task ':app:dexDebug'.
    > com.android.ide.common.internal.LoggedErrorException: Failed to run command:
    C:\Android\android-studio\sdk\build-tools\android-4.4W\dx.bat --dex --num-threads=4 --output C:\Workspace\TestApplication\app\build\intermediates\dex\debug C:\Workspace\TestApplication\app\build\intermediates\classes\debug C:\Workspace\TestApplication\app\build\intermediates\dependency-cache\debug C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\aopalliance-1.0-b64c80122d373c2ee241b55db78eac4c4c550a82.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\classes-528f16ed29eae5d85d8c6f1ee7d32d83803e6e6d.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\classes-fa1cd323aa3b243f3f4157cb5e43b3768ee49e9b.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\internal_impl-20.0.0-d4c263ffd0c244f7b9af8079e5d62faa86242454.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\jackson-annotations-2.3.0-c8c500c4e2e271888f48319f1d0f4ee141245e21.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\jackson-core-2.3.2-5a10979c76ddf0300365195ed3dcdf3bbf65dba0.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\jackson-databind-2.3.2-a027503e6b72a7b1487e8e935334766d26725e1b.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\javax.inject-1-e86c6ad046940b581fcf8f69e7965f8f5d1cfaf6.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-android-auth-1.0.1.RELEASE-d09921850d19080abfdeefe1fde904485c1b37c8.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-android-core-1.0.1.RELEASE-d006eb074ec6bcaf01f1fcb65dcc840f72c538d1.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-android-rest-template-1.0.1.RELEASE-f254c94632ca185a2fee85575fea1e4e9e68766f.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-aop-4.0.2.RELEASE-87af05a1d636417a8a1c074a0d93dbc6c5902550.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-beans-4.0.2.RELEASE-5afb5560550de06352f4871e0c5351c296555245.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-context-4.0.2.RELEASE-ae3ec0e430000b49e6dabc34fb702e4db3ab96ad.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-expression-4.0.2.RELEASE-1cfe445710559e2affa6317c573db04b9638c918.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-security-crypto-3.2.4.RELEASE-e5c641be2ba64d1b5bda6b6e9778a6043726fc96.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-social-config-1.1.0.RC1-0646da07e81cc32f0ff7a641a47b589c6ee71ed6.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-social-core-1.1.0.RC1-f762fce97f3b62664de8e04d427fea101bc74da1.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-social-twitter-1.1.0.RC1-66dcadc997a346a9caac49e5e66d0d6d60d6e684.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-social-web-1.1.0.RC1-753970492ed13f57671662ceb587dd9aa4f2c882.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\spring-webmvc-4.0.2.RELEASE-a6c8053426ad57c5e0b1eb2de9405ef3c0e118b1.jar C:\Workspace\TestApplication\app\build\intermediates\pre-dexed\debug\support-annotations-20.0.0-bab26a85db10fdf51a5bd499a182514bd4080ed4.jar
Error Code:
2
Output:
UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dex.DexException: Multiple dex files define Lorg/springframework/beans/BeansException;
at com.android.dx.merge.DexMerger.readSortableTypes(DexMerger.java:594)
at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:552)
at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:533)
at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:170)
at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)
at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
at com.android.dx.command.dexer.Main.run(Main.java:230)
at com.android.dx.command.dexer.Main.main(Main.java:199)
at com.android.dx.command.Main.main(Main.java:103)
Chorography answered 16/7, 2014 at 1:55 Comment(1)
Some of your dependencies has same class BeansExceptionStanch
C
3

I can get you farther along, but you may get stuck at the next problem.

If I load up your build file (and reproduce your build error), when I go into the IDE and ask it to take me to the BeansException class, I get this:

Screen shot of "Open class" dialog, showing multiple BeansException classes

You can see that BeansException is defined in two different places, which isn't allowed in Android builds, thus the error you're seeing. You need to set up your build such that each class is defined in one place.

Doing a little more sleuthing, you can use this command to see your dependency tree. From your application's module directory, run this command:

../gradlew dependencies

The relevant part of the output is here:

_debugApk - ## Internal use, do not manually configure ##
+--- com.android.support:appcompat-v7:20.+ -> 20.0.0
|    \--- com.android.support:support-v4:20.0.0
|         \--- com.android.support:support-annotations:20.0.0
+--- org.springframework.android:spring-android-rest-template:1.+ -> 1.0.1.RELEASE
|    \--- org.springframework.android:spring-android-core:1.0.1.RELEASE
+--- org.springframework.android:spring-android-auth:1.+ -> 1.0.1.RELEASE
|    +--- org.springframework.android:spring-android-core:1.0.1.RELEASE
|    +--- org.springframework.android:spring-android-rest-template:1.0.1.RELEASE (*)
|    +--- org.springframework.security:spring-security-crypto:3.1.3.RELEASE -> 3.2.4.RELEASE
|    \--- org.springframework.social:spring-social-core:1.0.2.RELEASE -> 1.1.0.RC1
+--- org.springframework.android:spring-android-core:1.+ -> 1.0.1.RELEASE
+--- org.springframework.security:spring-security-crypto:3.+ -> 3.2.4.RELEASE
+--- org.springframework.social:spring-social-core:1.+ -> 1.1.0.RC1
+--- org.springframework.social:spring-social-twitter:1.+ -> 1.1.0.RC1
|    +--- com.fasterxml.jackson.core:jackson-databind:2.3.0 -> 2.3.2
|    |    +--- com.fasterxml.jackson.core:jackson-annotations:2.3.0
|    |    \--- com.fasterxml.jackson.core:jackson-core:2.3.2
|    +--- org.springframework.security:spring-security-crypto:3.2.0.RELEASE -> 3.2.4.RELEASE
|    +--- org.springframework.social:spring-social-core:1.1.0.RC1
|    +--- org.springframework.social:spring-social-config:1.1.0.RC1
|    |    +--- org.springframework.social:spring-social-web:1.1.0.RC1
|    |    |    +--- javax.inject:javax.inject:1
|    |    |    +--- org.springframework:spring-webmvc:4.0.2.RELEASE
|    |    |    |    +--- org.springframework:spring-beans:4.0.2.RELEASE
|    |    |    |    +--- org.springframework:spring-context:4.0.2.RELEASE
|    |    |    |    |    +--- org.springframework:spring-aop:4.0.2.RELEASE
|    |    |    |    |    |    +--- aopalliance:aopalliance:1.0
|    |    |    |    |    |    \--- org.springframework:spring-beans:4.0.2.RELEASE
|    |    |    |    |    +--- org.springframework:spring-beans:4.0.2.RELEASE
|    |    |    |    |    \--- org.springframework:spring-expression:4.0.2.RELEASE
|    |    |    |    \--- org.springframework:spring-expression:4.0.2.RELEASE
|    |    |    \--- org.springframework.social:spring-social-core:1.1.0.RC1
|    |    \--- org.springframework.social:spring-social-core:1.1.0.RC1
|    +--- com.fasterxml.jackson.core:jackson-core:2.3.0 -> 2.3.2
|    \--- com.fasterxml.jackson.core:jackson-annotations:2.3.0
\--- com.fasterxml.jackson.core:jackson-databind:2.3.2 (*)

From this we can see that org.springframework.social:spring-social-twitter:1.+ eventually includes org.springframework:spring-beans:4.0.2.RELEASE through its transitive dependencies (which you found out because you isolated this as the line causing your build problem), but that means if it's already being bundled into the spring-android-core jar, it's redundant. I don't see another dependency on spring-beans from spring-android-core; perhaps that class is just packaged into the jar and isn't even a dependency.

At any rate, you can use this syntax in your dependencies to tell Gradle to not pick up a transitive dependency:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:20.+'
    compile 'org.springframework.android:spring-android-rest-template:1.+'
    compile 'org.springframework.android:spring-android-auth:1.+'
    compile 'org.springframework.android:spring-android-core:1.+'
    compile 'org.springframework.security:spring-security-crypto:3.+'
    compile 'org.springframework.social:spring-social-core:1.+'
    compile('org.springframework.social:spring-social-twitter:1.+') {
        exclude module: 'spring-beans'
    }
    compile 'com.fasterxml.jackson.core:jackson-databind:2.3.2'
}

If I do this, then no more dex multiple-files-define-a-class error. However, I now get this similar but different duplicate-files error, which I can muse about a bit but I'm not sure if I could fix it without writing a test app that instantiates Spring, which is beyond the scope of what I'll do in a SO answer ;)

:app:packageDebug
Error: duplicate files during packaging of APK /Users/sbarta/AndroidStudioProjects/MyApplication/app/build/outputs/apk/app-debug-unaligned.apk
    Path in archive: META-INF/spring.schemas
    Origin 1: /Users/sbarta/.gradle/caches/modules-2/files-2.1/org.springframework.social/spring-social-config/1.1.0.RC1/7afae4a4f83c64c4fd382c77708866e82900e799/spring-social-config-1.1.0.RC1.jar
    Origin 2: /Users/sbarta/.gradle/caches/modules-2/files-2.1/org.springframework/spring-context/4.0.2.RELEASE/6d6a781d99215990da8b398e1cdf09594a683209/spring-context-4.0.2.RELEASE.jar
You can ignore those files in your build.gradle:
    android {
      packagingOptions {
        exclude 'META-INF/spring.schemas'
      }
    }
:app:packageDebug FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:packageDebug'.
> Duplicate files copied in APK META-INF/spring.schemas
    File 1: /Users/sbarta/.gradle/caches/modules-2/files-2.1/org.springframework.social/spring-social-config/1.1.0.RC1/7afae4a4f83c64c4fd382c77708866e82900e799/spring-social-config-1.1.0.RC1.jar
    File 2: /Users/sbarta/.gradle/caches/modules-2/files-2.1/org.springframework.social/spring-social-config/1.1.0.RC1/7afae4a4f83c64c4fd382c77708866e82900e799/spring-social-config-1.1.0.RC1.jar

What this means is that there are two META-INF/spring.schemas files being included from two different places, which is also not permitted. However, you don't have the flexibility here of telling dex to ignore just one of them; you can tell it to ignore all of them via:

android {
  packagingOptions {
    exclude 'META-INF/spring.schemas'
  }
}

in your build file. I have a feeling that Spring needs that schemas file (which one, though???), so if you do this, your app may still not work. Experiment and thrash around with it, and if you're still having problems, though, you can post another question and maybe get more specialized help.

I'm not sure what the root of this problem is. Is it a packaging error in the Spring libraries that there are multiple schema files? Or are you expected to resolve this? Or do other build systems just Do The Right Thing? I'm not sure.

Carabin answered 16/7, 2014 at 18:19 Comment(3)
Just a couple of questions. First, how did you get that tree structure to show up on your "gradlew dependencies"? My system is not doing that. Second, what version of gradle are you using? Mine does not allow the "{ exclude module: 'spring-beans' }". Am I missing a configuration somewhere.Chorography
The dependency tree works for me if I run it from the module's directory, not the top-level project directory. As for the Gradle/plugin version, it's 0.12 of the plugin and maybe 1.12 of Gradle. That exclude should be working with what you've got.Carabin
Okay, I've got the dependency tree working. Not sure what's going on with the exclude statement. It keeps telling me "Build script error, unsupported Gradle DSL method found" It's not worthy worrying about, since I pretty much have it working, but it's still strange.Chorography
C
0

Okay, this is far from what one would call a satisfactory solution, but the thing compiles, so I'm "pleased".

Whatever the root of the problem is, it seems to be specific to spring-social-twitter version 1.1.0. I changed the build.gradle line to read:

compile 'org.springframework.social:spring-social-twitter:1.0.5.RELEASE'

rather than the ...spring-social-twitter:1.+' I had before and it now compiles fine. Haven't tested the working aspects yet, but that will be a set of altogether different questions.

The method for finding this was, I assure you, no less ridiculous than the actual "solution".

Chorography answered 18/7, 2014 at 1:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.