I am trying to run a build on Android. I'm in the process of building a React-Native bridge for a Java library. However, I am getting a Duplicate class error which looks like follows:
Duplicate class org.apache.commons.lang3.builder.CompareToBuilder
found in modules commons-lang3-3.9.jar (org.apache.commons:commons-lang3:3.9)
and creditCardNfcReader-1.0.3-runtime.jar (com.github.pro100svitlo:creditCardNfcReader:1.0.3)
There are an entire list of these errors being printed out. There is also a slightly different error which looks like this:
Duplicate class bolts.BoltsExecutors$ImmediateExecutor found in
modules bolts-tasks-1.4.0.jar (com.parse.bolts:bolts-tasks:1.4.0)
and jetified-bolts-android-1.1.2.jar (com.parse.bolts:bolts-android:1.1.2)
My dependencies currently look like this in my build.gradle file:
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.facebook.react:react-native:+"
implementation 'com.github.pro100svitlo:creditCardNfcReader:1.0.3'
addUnimodulesDependencies()
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
I have tried to exclude modules and groups from the dependencies with no luck yet. Here are a few approaches I have tried as recommended from several sources:
1.
implementation ("com.facebook.react:react-native:+") {
exclude group: 'com.parse.bolts', module: 'bolts-tasks'
}
2.
implementation ("com.facebook.react:react-native:+") { exclude module: 'bolts-tasks'}
3.
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.facebook.react:react-native:+"
implementation 'com.github.pro100svitlo:creditCardNfcReader:1.0.3'
addUnimodulesDependencies()
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
configurations { runtime.exclude group: '*' }
I would really appreciate any help with finding a solution to this problem. Thanks in advance.
The exclude method of the configuration closure for a dependency excludes transitive dependencies. So, if your module dependency depends on other modules, you can exclude them from your build. You can check out the transitive dependencies of the 'com.facebook.react:react-native:+' module on its maven repo.
https://mvnrepository.com/artifact/com.facebook.react/react-native/0.20.1
Try specify the version of dependency instead of use '+' to avoid conflict.
Here is some reference to check on resolving the plugins and dependency jar conflicts.
jarjar package reference
Related
I am trying to generate a JAR (salesforce-soap-connection.jar) file that I want to use as a dependency (library) in my project.
Currently, I generate this jar file using the command below and then push the generated jar file in my repo.
java -classpath ./sf/force-wsc-45.0.0.jar:./sf/js-1.7R2.jar:./sf/ST4-4.3.1.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/lib/tools.jar:./sf/antlr-4.7.2-complete.jar com.sforce.ws.tools.wsdlc ./sf/enterprise.wsdl ./sf/salesforce-soap-connection.jar
Basically, I want to do this using Gradle. (Instead of running the above command, do exactly what the command does using Gradle)
The jar files that are used in the above command should be downloaded from maven repository and only enterprise.wsdl will be present in project/src/main/resources folder.
The generated jar file should be kept in project/lib folder.
This is my build.gradle file. Please suggest what to do next…
plugins {
id 'scala'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.scala-lang:scala-library:2.11.8'
implementation 'joda-time:joda-time:2.1'
implementation 'org.joda:joda-convert:2.1.1'
implementation 'org.slf4j:slf4j-api:1.7.36'
implementation 'org.apache.logging.log4j:log4j-api:2.6.2'
implementation 'org.apache.logging.log4j:log4j-core:2.6.2'
implementation 'com.google.cloud:google-cloud-storage:1.52.0'
implementation 'com.google.cloud:google-cloud-bigquery:1.110.0'
implementation 'org.jooq:jooq:3.12.0'
implementation 'org.jooq:jooq-scala_2.11:3.10.5'
implementation 'com.google.apis:google-api-services-bigquery:v2-rev459-1.25.0'
implementation 'org.json:json:20180813'
implementation 'com.google.code.gson:gson:2.8.3'
implementation 'org.yaml:snakeyaml:1.25'
implementation 'com.github.tototoshi:scala-csv_2.11:1.3.6'
implementation 'org.json4s:json4s-native_2.11:3.6.10'
implementation 'org.apache.commons:commons-dbcp2:2.0.1'
implementation 'commons-io:commons-io:2.6'
implementation fileTree('lib')
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes "Main-Class": "com.org.loader.main"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
I was able to solve the issue with gradle JavaExec type task.
JavaExec Executes a Java application in a child process.
Similar to Exec, but starts a JVM with the given classpath and application class.
I have used toCopy as a configuration so that it is only salesForceJarGenerate task and not included in project external dependencies.
transitive = false is used to stop given dependency to not download or exclude its transitive dependencies.
In salesForceJarGenerate task:-
classpath option is to include dependencies/jars that are needed to be provided for the soap-connector.jar
main option is to provide the main class that will convert .ml files to java files.
args is the arguments.
agrs "{location of your enterprise.xml file}" , "output location of your jar file" , "location where the intermediate java files will be stored"
More on this can be found on official documentation here!
here is my final build.gradle
plugins {
id 'scala'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.scala-lang:scala-library:2.11.8'
implementation 'joda-time:joda-time:2.1'
implementation 'org.joda:joda-convert:2.1.1'
implementation 'org.slf4j:slf4j-api:1.7.36'
implementation 'org.slf4j:slf4j-simple:2.0.0'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.12.1'
implementation 'org.apache.logging.log4j:log4j-api:2.6.2'
implementation 'org.apache.logging.log4j:log4j-core:2.6.2'
implementation 'com.google.cloud:google-cloud-storage:1.52.0'
implementation 'com.google.cloud:google-cloud-bigquery:1.110.0'
implementation 'org.jooq:jooq:3.12.0'
implementation 'org.jooq:jooq-scala_2.11:3.10.5'
implementation 'com.google.apis:google-api-services-bigquery:v2-rev459-1.25.0'
implementation 'org.json:json:20180813'
implementation 'com.google.code.gson:gson:2.8.3'
implementation 'org.yaml:snakeyaml:1.25'
implementation 'com.github.tototoshi:scala-csv_2.11:1.3.6'
implementation 'org.json4s:json4s-native_2.11:3.6.10'
implementation 'org.apache.commons:commons-dbcp2:2.0.1'
implementation 'commons-io:commons-io:2.6'
implementation 'com.force.api:force-wsc:54.0.0'
implementation fileTree('lib')
}
configurations {
toCopy
}
dependencies {
toCopy('com.force.api:force-wsc:45.0.0') {
transitive = false
}
toCopy('rhino:js:1.7R2') {
transitive = false
}
toCopy('org.antlr:ST4:4.3.1') {
transitive = false
}
toCopy('org.antlr:antlr-complete:3.5.2') {
transitive = false
}
toCopy('jdk.tools:jdk.tools:1.8') {
transitive = false
}
}
//generates salesforce-soap-connection.jar with the given enterprise.xml file
task salesForceJarGenerate(type: JavaExec) {
classpath = configurations.toCopy
main = "com.sforce.ws.tools.wsdlc"
args "${projectDir}/src/main/resources/enterprise.xml", "${projectDir}/lib/salesforce-soap-connection.jar", "$buildDir/salesforce-gen/"
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes "Main-Class": "com.org.loader.main"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
compileScala.dependsOn salesForceJarGenerate
Now the generated jar file can be added as a dependency
by adding the below in dependencies block.
implementation fileTree("location(directory) of generated jar file")
Gradle v7.3.3
I'm trying to use the The Java Platform Plugin, and I have this so far in my platform build.gradle file
artifactId = "my-java-platform"
group = "com.mycompany.platform"
version = "1.0.0"
dependencies {
constraints {
...
api "org.slf4j:slf4j-log4j12:1.7.9"
api "org.projectlombok:lombok:1.16.18"
...
}
}
I did a ./gradlew publishToMavenLocal and see the resulting pom.xml file with those 2 dependencies.
Then in my application's build.gradle file I have
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation platform(group: "com.company.platform", name: "my-java-platform", version: "1.0.0")
annotationProcessor platform(group: "com.company.platform", name: "my-java-platform", version: "1.0.0")
compileOnly group: "org.slf4j", name: "slf4j-log4j12"
compileOnly group: "org.projectlombok", name: "lombok"
...
}
One of my applications source code has
package com.mycompany.common
import java.util.TimeZone;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
import lombok.extern.slf4j.Slf4j;
#Slf4j
public class ObjectMapperConfiguration {
private static ObjectMapper objectMapper;
/**
* Static only
*/
private ObjectMapperConfiguration() {}
/**
* Work with Spring to configure the ObjectMapper
*/
public static ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
objectMapper = builder.createXmlMapper(false).build();
configureObjectMapper(objectMapper);
log.info("The ObjectMapperConfiguration has run");
return objectMapper;
}
...
}
But I get
$ ./gradlew clean build
> Task :compileJava FAILED
/Users/.../src/main/java/com/company/common/ObjectMapperConfiguration.java:39: error: cannot find symbol
log.info("The ObjectMapperConfiguration has run");
^
symbol: variable log
location: class com.company.common.ObjectMapperConfiguration
I understand that the log variable is defined in the #Slf4j annotation? If so why am I getting the error? Thanks!
The Lombok magic is implemented via an annotation processor.
See here for the recommended Lombok Gradle config
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
testCompileOnly 'org.projectlombok:lombok:1.18.22'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
}
The application's build.gradle file, the one that uses the platform, should look like this
dependencies {
implementation platform(group: "com.mycompany.platform", name: "my-java-platform", version: "1.0.0")
annotationProcessor platform(group: "com.company.platform", name: "my-java-platform", version: "1.0.0")
annotationProcessor group: "org.projectlombok", name: "lombok"
...
}
In my project I have two dependencies with okio as a transitive dependency conflict. In theory, gradle should solve it by choosing the highest version, but that didn't work.
I have been trying everything, since exclude until force the version from okio lib, but nothing works. Looking on external libraries path, I realized that one of the dependencies contains the okio as a path of the dependency, and I believe that this is the problem. But how can I solve this?
This is a simple gradle example with my two dependencies. Commented lines are my failed attempts to solve the problem:
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.72'
}
repositories {
mavenCentral()
}
//configurations.all {
// resolutionStrategy.force('com.squareup.okio:okio:2.4.3')
//}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
// -> dependency one
implementation "com.squareup.retrofit2:retrofit:2.7.2"
// implementation ("com.squareup.retrofit2:retrofit:2.7.2"){
// exclude group: 'com.squareup.okio'
// }
// -> dependency two
implementation "com.eternitywall:java-opentimestamps:1.18"
// implementation ("com.eternitywall:java-opentimestamps:1.18") {
// exclude group: 'com.squareup.okio'
// }
// implementation "com.squareup.okio:okio:2.4.3"
// implementation "com.squareup.okio:okio"
// constraints {
// implementation("com.squareup.okio:okio:2.4.3") {
// because 'transitive version conflict'
// }
// }
}
To get the error, just have a Main.kt file with the code:
import okhttp3.OkHttpClient
fun main(args: Array<String>) {
OkHttpClient.Builder()
}
And the error obtained is:
Exception in thread "main" java.lang.NoSuchMethodError: 'boolean okio.ByteString.startsWith(okio.ByteString)'
at okio.Options.of(Options.java:64)
at okhttp3.internal.Util.<clinit>(Util.java:73)
at okhttp3.OkHttpClient.<clinit>(OkHttpClient.java:124)
at okhttp3.OkHttpClient$Builder.<init>(OkHttpClient.java:449)
at MainKt.main(Main.kt:4)
And finally, this is the library root that I mentioned from dependence with the included okio
I will be very grateful if you can help me.
Thanks in advance!!
Well, it seems that the only solution is to separate the app into modules, placing each dependency in a different module. Even though I was reluctant it was the only way I found.
I am trying to add few dependencies to my Android project but I'm still getting some weird errors.
I am trying to add recommended dependencies which I've found on CodeLabs but it steel does not allow me to sync my gradle files successfully.
The error that is keep showing up is the following: ERROR: Failed to resolve: androidx.lifecycle:lifecycle-extensions:2.2.0-rc2
Code: inside gradle module
// Room components
implementation "androidx.room:room-runtime:$rootProject.roomVersion"
annotationProcessor "androidx.room:room-compiler:$rootProject.roomVersion"
androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion"
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.archLifecycleVersion"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$rootProject.archLifecycleVersion"
// UI
implementation "com.google.android.material:material:$rootProject.materialVersion"
// Testing
androidTestImplementation "androidx.arch.core:core-testing:$rootProject.coreTestingVersion"
Text inside gradle project:
ext {
roomVersion = '2.2.1'
archLifecycleVersion = '2.2.0-rc2'
coreTestingVersion = '2.1.0'
materialVersion = '1.0.0'
}
This is also one error that I am getting sometimes, it appears randomly...
ERROR: Manifest merger failed : Attribute application#appComponentFactory value=(android.support.v4.app.CoreComponentFactory) from [com.android.support:support-compat:28.0.0] AndroidManifest.xml:22:18-91
is also present at [androidx.core:core:1.1.0] AndroidManifest.xml:24:18-86 value=(androidx.core.app.CoreComponentFactory).
Suggestion: add 'tools:replace="android:appComponentFactory"' to <application> element at AndroidManifest.xml:11:5-28:19 to override.
The error log literally says there is no androidx.lifecycle:lifecycle-extensions version 2.2.0-rc2.
Change archLifecycleVersion = '2.2.0-rc2' to archLifecycleVersion = '2.2.0-rc02' to fix that error.
The APIs in lifecycle-extensions have been deprecated. Instead, add dependencies for the specific Lifecycle artifacts you need.
dependencies {
def lifecycle_version = "2.2.0"
def arch_version = "2.1.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// Annotation processor
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
}
From this source
One of the dependencies declared in my project has a transitive dependency on 'com.google.guava:guava:15.0'. But my application deployed on WAS/Weblogic doesn't work due to a CDI issue which has been fixed in 'com.google.guava:guava:15.0:cdi1.0'. (same version, but with classifier) I need to tell gradle to use this jar during build and packaging. I am trying to figure out how we can override this transitive dependency with a jar specific version classifier.
Tried the following approaches:
Added the dependency explicitly: compile 'com.google.guava:guava:15.0:cdi1.0'. But both jars got included in the resultant WAR.
Added the dependency explicitly and defined a resolution strategy:
configurations.all {
resolutionStrategy {
force 'com.google.guava:guava:15.0:cdi1.0'
}
}
Even this didn't work.
Defined a resolution strategy to check and change the version.
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group + ":" + details.requested.name == 'com.google.guava:guava') {
details.useVersion "15.0:cdi1.0"
//details.useTarget "com.google.guava:guava:15.0:cdi1.0"
}
}
}
Even this didn't work.
Need your suggestions on how this issue can be tackled.
Currently classifiers are not yet taken into account when it comes to resolutionStrategies. A workaround for you might excluding the transitive Guava library when declaring your dependencies and adding the Guava cdi1.0 version explicitly:
dependencies {
compile ("org.acme:someDependency:1.0"){
exclude group: 'com.google.guava', module: 'guava'
}
compile "com.google.guava:guava:15.0:cdi1.0"
}
I came across a more elegant approach which is simply:
compile ("com.google.guava:guava:15.0:cdi1.0") {
force = true
}
Explanation
Setting force = true for a dependency tells gradle to use the specified version in case of a version conflict
implementation( group: 'commons-codec', name: 'commons-codec'){
version{
strictly "[1.15]"
}
}
This works for me with gradle 6.6.1
The documentation link for strictly can found here https://docs.gradle.org/current/userguide/rich_versions.html#rich-version-constraints
Gradle 4.5.1 has the function DependencySubstitutions. Here an example to replace a dependency:
configurations.each {
c -> c.resolutionStrategy.dependencySubstitution {
all { DependencySubstitution dependency ->
if (dependency.requested.group == 'org.json') {
dependency.useTarget 'com.vaadin.external.google:android-json:0.0.20131108.vaadin1'
}
}
}
}
This will not work if the same dependency is pointed by some other jar. Sureshot way to exclude the dependency
configurations {
all*.exclude group: 'com.google.guava', module:'guava-jdk5'
}
Since force = true is deprecated, relevant solution is to use strictly(...) version, e.g.:
dependencies {
// no need to exclude transitive spring-data-relational from this dependency
implementation("org.springframework.data", "spring-data-r2dbc", "1.1.0.RC1")
implementation("org.springframework.data", "spring-data-relational").version {
strictly("2.0.0.RC1")
}
}
P.S. tested on Gradle 6.3
Try this:
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
// https://docs.gradle.org/current/userguide/resolution_rules.html
if (details.requested.group == 'com.google.guava' && details.requested.name == 'guava') {
details.useVersion '15.0:cdi1.0'
}
}
}
try this its working perfectly in my case in App level in build.gradle file
android {
configurations {
all*.exclude module: 'conceal'
all*.exclude module: 'bcprov-jdk15on'
}
}