I started migration from build.gradle (Groovy) to build.gradle.kts (Kotlin DSL). The thing is that com.google.common.util.concurrent.ListenableFuture (from com.google.guava) exists in several dependecies. Because of that build fails with java.lang.RuntimeException: Duplicate class ... error.
Previously (when I had build.gradle in Groovy) this problem was solved with this snippet:
configurations {
all*.exclude group: 'com.google.guava', module: 'listenablefuture'
}
But I can't find anything similar using Kotlin DSL.
Could you please provide Kotlin alternative for the snippet above or suggest any other solution on how to deal with this?
This works with the Gradle Kotlin DSL:
configurations {
all {
exclude(group = "com.google.guava", module = "listenablefuture")
}
}
This might work (though I haven't tried it):
configurations.forEach { it.exclude("com.google.guava", "listenablefuture") }
For two group you can use like this:
configurations.forEach {
it.exclude("com.google.guava", "listenablefuture")
it.exclude(group = "org.jetbrains", module = "annotations")
}
Related
Recently I started to develop and Android Kotlin project and I need to use the BigQuery library (from Google). According to the documentation, it not exists any client library developed in Kotlin but I reviewed the Java library so I decided to impor it...
When I put the gradle statement in app-module of my project:
implementation platform('com.google.cloud:libraries-bom:26.1.5')
implementation 'com.google.cloud:google-cloud-bigquery'
I got this ouput error:
Duplicate class org.jetbrains.annotations.NotNull found in modules annotations-13.0 (org.jetbrains:annotations:13.0) and auto-value-1.10 (com.google.auto.value:auto-value:1.10)
Duplicate class org.jetbrains.annotations.Nullable found in modules annotations-13.0 (org.jetbrains:annotations:13.0) and auto-value-1.10 (com.google.auto.value:auto-value:1.10)
Go to the documentation to learn how to Fix dependency resolution errors.
Could you help someone, please?
In order to solve it, I tried the following:
In build.gradle [app-module]:
configurations {
cleanedAnnotations
implementation.exclude group: 'org.jetbrains' , module:'annotations'
}
and
configurations {
cleanedAnnotations
implementation.exclude group:'com.google.auto.value' , module:'auto-value:1.10'
}
but still not working.
In build.gradle [app-module] in "android{}" section:
configurations.all {
resolutionStrategy {
exclude group: "org.jetbrains", module: "annotations-13.0"
}
}
but I didn't get any success....
I have create kotlin multiplatform project for handling API.
I integrated this in my main project but I am getting following exception.
java.lang.NoClassDefFoundError: Failed resolution of: Lio/ktor/client/HttpClientJvmKt;
I tried to add following dependencies in my main project still issue persists.
dependencies {
implementation "io.ktor:ktor-client-core:1.3.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.3.7"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.20.0"
}
packagingOptions {
exclude 'META-INF/kotlinx-io.kotlin_module'
exclude 'META-INF/atomicfu.kotlin_module'
exclude 'META-INF/kotlinx-coroutines-io.kotlin_module'
exclude 'META-INF/kotlinx-coroutines-core.kotlin_module'
}
Still I am getting this issue.
Any help would be appreciated.
In MPP you need to declare dependencies for each target.
For example:
commonMain needs to have the dependency you used above:
implementation "io.ktor:ktor-client-core:1.3.2"
androidMain needs to have it's own dependency:
implementation "io.ktor:ktor-client-okhttp:1.3.2"
iosMain also needs it's own dependency:
implementation "io.ktor:ktor-client-ios:1.3.2"
Note the suffix of ktor-client-xxxx.
So my guess is, you only need to replace the dependency in your main project to io.ktor:ktor-client-okhttp (or whichever client you prefer)
I'm trying to add logging for Ktor http requests in Android application. According to docs I have to add gradle dependency
implementation "io.ktor:ktor-client-logging:$ktor_version"
and just use this snippet
val client = HttpClient() {
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.HEADERS
}
}
Problem is that compiler "ignores" package 'io.ktor.client.features.logging' added as a dependency. What's strange is that JsonFeature (added as similar dependency) works just fine.
install(JsonFeature) { // perfectly works
...
}
install(Logging) { // unresolved reference
...
}
I already checked .jar file that gradle added to the project, it contains all expected classes, I can open them and see the source code, but magically just can't use in my app. After hours of research I guess it may be somehow related to gradle metadata or that logging feature is multiplatform and some additional gradle configuration is required, but unfortunately I'm not a gradle expert.
I tried adding enableFeaturePreview("GRADLE_METADATA") to settings.gradle, but no effect. Even tried to add "-jvm" to dependency.
implementation "io.ktor:ktor-client-logging-jvm:$ktor_version"
With this dependency Android Studio finding package successfully, but fails to compile with following error
More than one file was found with OS independent path 'META-INF/ktor-http.kotlin_module'
Can anyone please clarify how to properly configure dependency for Ktor logger?
For the ktor-client-logging you have to have the dependency set for each platform:
commonMain {
dependencies {
implementation "ch.qos.logback:logback-classic:1.2.3"
implementation "io.ktor:ktor-client-logging:$ktor_version"
}
}
androidMain {
dependencies {
implementation "io.ktor:ktor-client-logging-jvm:$ktor_version"
}
}
iosMain {
dependencies {
implementation "io.ktor:ktor-client-logging-native:$ktor_version"
}
}
as for the meta META-INF/ktor-http.kotlin_module add to the app/build.gradle inside the android {} block:
android {
packagingOptions {
exclude 'META-INF/common.kotlin_module'
exclude 'META-INF/*.kotlin_module'
}
}
We were recently asked to implement "Firebase Performance Monitoring" on an Android app, but it's been causing us lots of different problems. The app used to work just fine, but upon adding "firebase-perf", it compiles, but then on runtime we found out the Let plugin stopped working, every permission defined with the #AskPermission annotation is simply ignored.
Looking through the gradle build output, I stumbled upon this stack-trace:
java.lang.IllegalStateException: Expecting .,<, or ;, but found firebaseperf while unpacking <K:Ljava/lang/Object;>Lcom/google/android/gms/internal/firebase-perf/zzw<TK;>;
at org.aspectj.util.GenericSignatureParser.parseClassTypeSignature(GenericSignatureParser.java:204)
at org.aspectj.util.GenericSignatureParser.parseAsClassSignature(GenericSignatureParser.java:56)
at org.aspectj.weaver.UnresolvedType.forGenericTypeSignature(UnresolvedType.java:274)
at org.aspectj.weaver.bcel.BcelWorld.addSourceObjectType(BcelWorld.java:482)
at org.aspectj.weaver.bcel.BcelWorld.addSourceObjectType(BcelWorld.java:456)
at org.aspectj.weaver.bcel.BcelWeaver.addAspectsFromJarFile(BcelWeaver.java:263)
at org.aspectj.weaver.bcel.BcelWeaver.addLibraryJarFile(BcelWeaver.java:236)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.initBcelWorld(AjBuildManager.java:874)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.performBuild(AjBuildManager.java:249)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.batchBuild(AjBuildManager.java:185)
at org.aspectj.ajdt.ajc.AjdtCommand.doCommand(AjdtCommand.java:112)
at org.aspectj.ajdt.ajc.AjdtCommand.runCommand(AjdtCommand.java:60)
at org.aspectj.tools.ajc.Main.run(Main.java:371)
at org.aspectj.tools.ajc.Main$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at com.canelmas.let.LetPlugin$_apply_closure2_closure3.doCall(LetPlugin.groovy:66)
...
I've seen some similar cases here and there but couldn't find a solution yet. The way I see it, it looks like a conflict between differing versions of aspectjs, defined in different classpaths.
This is the relevant part of out project-level gradle file:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath group: 'org.tmatesoft.svnkit', name: 'svnkit', version: '1.7.11'
classpath('com.canelmas.let:let-plugin:0.1.11')
classpath 'com.google.gms:google-services:4.2.0'
classpath 'com.google.firebase:firebase-plugins:1.1.5'
}
}
And these are the firebase dependencies we have defined in the app-level gradle:
dependencies {
compile 'com.google.firebase:firebase-core:16.0.7'
compile 'com.google.firebase:firebase-perf:16.2.3'
}
Does anyone have an idea of a possible fix?
EDIT: There was someone in another thread, who claimed to have solved the problem with the code below, but I have no idea how to actually use it. Could anyone more Gradle-savvy be able to explain where is this declaration supposed to go and what I'm supposed to do with it?
I tried placing it many different places of my gradle file but I'm getting this error: "No such property: classpath for class: org.gradle.api.tasks.compile.JavaCompile"
def filtered_class_filetree = javaCompile.classpath.asFileTree.filter {
!it.canonicalPath.contains("firebase-perf")
}
If multiple libraries are compiling different versions of aspectj (or any other dependency), you can always force (or ignore) the ones you want like below:
implementation('com.google.firebase:firebase-core:16.0.7', { // this will remove aspectj dependencies from firebase
exclude group: 'org.aspectj', module: 'aspectjrt'
exclude group: 'com.android.support', module: 'aspectjtools'
})
You can also force aspect's version like below (beside your dependencies, in the module):
configurations.all {
resolutionStrategy.force 'org.aspectj:aspectjrt:x.x.x'
}
To answer your last question:
I tried placing it many different places of my gradle file but I'm
getting this error: "No such property: classpath for class:
org.gradle.api.tasks.compile.JavaCompile"
You can access java compiler (and classpath) using applicationVariants in android block inside your module:
// inside your android module
android {
//...
applicationVariants.all {
variant ->
variant.javaCompiler.classpath = variant.javaCompiler.classpath.filter {
!it.canonicalPath.contains("firebase-perf")
}
}
}
I have a multi-module gradle project that looks like this:
Parent
|--server
|--application (android module)
+--common
The server tests have a dependency on the common module tests. For this, I added
testCompile files(project(':common').sourceSets.test.output.classesDi
compileTestJava.dependsOn tasks.getByPath(':common:testClasses')
and it worked great. Unfortunately, when I tried to do the same thing for the application module that also has a dependency on the common module tests, it wouldn't work. It fails with:
Build file 'application\build.gradle' line: 103
A problem occurred evaluating project ':application'.
Could not find property 'sourceSets' on project ':common'
After googling a bit I also tried
project.evaluationDependsOn(':common')
testCompile files(project(':common').sourceSets.test.output.classesDir)
But fails with another exception:
Project application: Only Jar-type local dependencies are supported. Cannot handle: common\build\classes\test
Any ideas on how to fix this?
There's a couple of approaches solving the problem of importing test classes in this article. https://softnoise.wordpress.com/2014/09/07/gradle-sub-project-test-dependencies-in-multi-project-builds/ The one I used is:
code in shared module:
task jarTest (type: Jar) {
from sourceSets.test.output
classifier = 'test'
}
configurations {
testOutput
}
artifacts {
testOutput jarTest
}
code in module depending on the shared module:
dependencies{
testCompile project(path: ':common', configuration: 'testOutput')
}
And there seems to be a plugin for it as well! https://plugins.gradle.org/plugin/com.github.hauner.jarTest/1.0
Following the approach from sakis, this should be the configuration you need to get the tests available from another project in the Android platform (done for debug variant).
Shared module:
task jarTests(type: Jar, dependsOn: "assembleDebugUnitTest") {
classifier = 'tests'
from "$buildDir/intermediates/classes/test/debug"
}
configurations {
unitTestArtifact
}
artifacts {
unitTestArtifact jarTests
}
Your module:
dependencies {
testCompile project(path: ":libName", configuration: "unitTestArtifact")
}
The solution mentioned by droidpl for Android + Kotlin looks like this:
task jarTests(type: Jar, dependsOn: "assembleDebugUnitTest") {
getArchiveClassifier().set('tests')
from "$buildDir/tmp/kotlin-classes/debugUnitTest"
}
configurations {
unitTestArtifact
}
artifacts {
unitTestArtifact jarTests
}
Gradle for project that is going to use dependencies:
testImplementation project(path: ':shared', configuration: 'unitTestArtifact')
I know it's kinda an old question but the solution mentioned in the following blog solves the problem very nicely and is not a sort of hack or a temporary workaround:
Shared test sources in Gradle multi-module project
It works something like this:
// in your module's build.gradle file that needs tests from another module
dependencies {
testCompile project(path: ':path.to.project', configuration: 'test')
}
Also you should note that in the very last paragraph he mentioned that you need to enable Create separate module per source set in IntelliJ settings. But it works fine without using that option too. Probably due to changes in the recent IntelliJ versions.
EDIT: IntelliJ recognizes this fine as of 2020.x versions.
I think you could use gradles java test fixtures. This will automatically create a testFixtures source set, in which you can write your test that you want to reuse.
Test fixtures are configured so that:
they can see the main source set classes
test sources can see the test fixtures classes
For example, if you have some class in common module:
public class CommonDto {
private final Long id;
private final String name;
// getters/setters and other methods ...
}
Then in the common module, you could write into src/testFixtures/java following utils:
public class Utils {
private static final CommonDto A = new CommonDto(1, "A");
private static final CommonDto B = new CommonDto(2, "B");
public static CommonDto a() { return A; }
public static CommonDto b() { return B; }
}
Then in you other modules you could add this to reuse Utils class
dependencies {
// other dependencies ...
testImplementation(testFixtures(project(":common")))
}
All of this is better explained in the documentation that I provided initially. There are some nuances that you need to take into account until you create this not to leak test classes into production.