Android Studio + Gradle: java.lang.IllegalArgumentException
Asked Answered
A

2

1

I have my project with Gradle and declare my dependencies on build.gradle:

dependencies {
compile 'com.android.support:support-v4:18.0.0'
compile 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE'
compile 'org.springframework.android:spring-android-auth:1.0.1.RELEASE'
compile 'org.springframework.android:spring-android-core:1.0.1.RELEASE'
compile 'org.roboguice:roboguice:2.0'

}

Build with Gradle work fine, but when a run my project a following error is throw on compilation phase:

Gradle: UNEXPECTED TOP-LEVEL EXCEPTION:
Gradle: java.lang.IllegalArgumentException: already added: Lorg/springframework/util/FileCopyUtils;
Gradle: at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:122)
Gradle: at com.android.dx.dex.file.DexFile.add(DexFile.java:161)

I use Gradle 1.8.

Alcahest answered 7/3, 2014 at 0:9 Comment(0)
S
5

It looks like multiple libraries are including the core library files; I get a slightly different exception when I make a sample case, but it's the same cause. If I open up the External Libraries tab to look at what jars it's using, I see spring-android-core and spring-core, and if I open those up to see what classes are in them, I see that both contain org.springframework.core.ErrorCoded (which is the duplicate class in my test case).

Project view showing added Spring libraries

You're not including spring-core directly; it's coming in as a transitive dependency from the spring-android-auth library (if I include just those two libraries and omit spring-android-rest-template I still get the error). I tried digging through the pom file definitions in Maven Central to try to prove why it's happening, but I'm not sure I could give you an explanation that didn't have a lot of holes in it, so I'll stay quiet on that front ;-) But I won't lack of understanding get in the way of trying to fix the problem. If you tell the spring-android-auth dependency to exclude spring-core, it does the trick:

dependencies {
    ...
    compile 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE'
    compile('org.springframework.android:spring-android-auth:1.0.1.RELEASE') {
        exclude module: 'spring-core'
    }
    compile 'org.springframework.android:spring-android-core:1.0.1.RELEASE'
}

I also came across this error:

Execution failed for task ':app:packageDebug'.
> Duplicate files copied in APK META-INF/notice.txt
File 1: /Users/sbarta/.gradle/caches/modules-2/files-2.1/org.springframework.android/spring-android-auth/1.0.1.RELEASE/f43faebbf90aef324979a81a4f5eee1e3b95191f/spring-android-auth-1.0.1.RELEASE.jar
File 2: /Users/sbarta/.gradle/caches/modules-2/files-2.1/org.springframework.android/spring-android-auth/1.0.1.RELEASE/f43faebbf90aef324979a81a4f5eee1e3b95191f/spring-android-auth-1.0.1.RELEASE.jar

so I had to follow the instructions at Android Gradle plugin 0.7.0: "duplicate files during packaging of APK" to exclude some META-INF/ files from packaging, and I added:

android {
    ...
    packagingOptions {
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
    }
}
Syphilis answered 7/3, 2014 at 16:59 Comment(2)
spring-android-core is a forked subset of spring-core, which has been built and tested against Android. In contrast, the Spring Framework modules themselves have not been developed or tested with Android in mind. For Rest Template usage alone, everything works smoothly. However, when using Spring Social (and transitively Spring Security Crypto), we need to make sure to exclude any Spring Framework dependencies in favor of spring-android-core and spring-android-rest-template.Sustentacular
The Spring for Android GitHub README now includes an example build configuration. Hopefully this will help others that see this thread.Sustentacular
S
0

Scott Barta's answer is exactly correct. Here is another way to globally exclude certain Spring modules in your build.gradle. As with any solution that has global effects, it should be used with caution.

configurations.compile {
    exclude module: 'spring-core'
    exclude module: 'spring-web'
    exclude module: 'commons-logging'
}
Sustentacular answered 14/8, 2014 at 10:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.