My gradle project contains 3 sub-projects with one source file each:
root-project\
sub-project-abstract\
...AbstractFoo.java
sub-project-commons\
...ConcreteFoo.java (extends AbstractFoo)
sub-project-main\
...Main.java (instantiates ConcreteFoo)
build.gradle of sub-project-commons:
dependencies {
implementation(project(:sub-project-abstract))
}
build.gradle of sub-project-main:
dependencies {
implementation(project(:sub-project-commons))
}
The Main-class in sub-project-main is aware of ConcreteFoo, however, compilation fails with cannot access AbstractFoo.
For some reason, I expected sub-project-commons to "export" ConcreteFoo and AbstractFoo, since it's a implementation-dependency. Or in other words, form the perspective of sub-project-main, AbstractFoo is a transitive dependency.
However, this doesn't seem to be the case.
I know that I could probably make it work by explicitly adding sub-project-abstract as a direct dependency to sub-project-main. However, that's something I want to avoid due to the nature of the commons project (my actual project contains up to 10 subprojects, and it should be possible to reuse the commons-project without declaring a dependency to sub-project-abstract every single time the commons-project is referenced.
Is there a way to make the Main-class aware of AbstractFoo without directly declaring sub-project-abstract as a dependency (but indirectly via sub-project-commons)?
This is expected behavior for the implementation configuration. You should apply the Java Library Plugin and use the api configuration.
The key difference between the standard Java plugin and the Java Library plugin is that the latter introduces the concept of an API exposed to consumers. A library is a Java component meant to be consumed by other components. It’s a very common use case in multi-project builds [emphasis added], but also as soon as you have external dependencies.
The plugin exposes two configurations that can be used to declare dependencies: api and implementation. The api configuration should be used to declare dependencies which are exported by the library API, whereas the implementation configuration should be used to declare dependencies which are internal to the component.
[...]
Dependencies appearing in the api configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers. Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath. [...]
In sub-project-commons (Kotlin DSL):
plugins {
...
`java-library`
}
...
dependencies {
api(project(":sub-project-abstract"))
}
...
Related
My app has a module (lets call it myModule) which uses a 3rd party library(lets call it 3rdParty). This 3rdParty library is an aar file that uses a video compression library(lets call it videoCompressor). And myModule is also using the same compression library with the same version.
p.s. A module can't use aar file directly, so I had to put it in the app and use it in myModule as mentioned in this post.
So here is the dependency hierarchy
app
dependencies {
implementation(':myModule')
implementation(':3rdParty')
implementation 'videoCompressor:1.2.3'
}
myModule
dependencies {
api project(':3rdParty')
implementation 'videoCompressor:1.2.3'
}
3rdParty is an aar file and it also uses videoCompressor:1.2.3 internally.
While trying to build the project I get this error
Type com.abedelazizshe.lightcompressorlibrary.data.AtomsKt is defined multiple times: /Users/xx/Documents/xx/temp/xx/app/build/intermediates/mixed_scope_dex_archive/devDebug/out/d557fe27570a7fdcab8e1782ef61e44224719c80849bd367030f40a11145859c_1.jar:classes.dex, /Users/xx/Documents/xx/temp/xx/app/build/intermediates/mixed_scope_dex_archive/devDebug/out/23b9eb6594f48cb29b67fd834a2ea73b6ec11312577ac3867a8befdc5815129a_1.jar:classes.dex
This seems to be because there are duplicate classes from the videoCompressor library. How can this be fixed?
I tried removing videoCompressor from the app and myModule, build gets created but there is runtime crash about NoClassDefFoundError.
So I have this generic backend server that loads shaded jars in memory and then loads it through a custom Classloader.
E.g.
MyClass class = c.newInstance();
It works fine until the shaded Jar dependencies conflicts with the server classes.
E.g.
Server contains (with Custom Classloader):
com.fasterxml.jackson.jackson-databind:2.6.0
While the shaded jar contains
com.fasterxml.jackson.jackson-databind:2.9.9
When the method in the class that requires the said library e.g. class.doSomeThing(); it throws an error Caused by java.lang.NoSuchFieldError: because the loaded jackson-databind is 2.6.0 instead of 2.9.9
The question here is when the class is loaded from the shaded jar is there a way to make sure that the shaded dependencies are the ones used?
The question here is when the class is loaded from the shaded jar is there a way to make sure that the shaded dependencies are the ones used?
If you are using the default Class loader then the order of resolution will work as the order of the classpath. Within your code you can use
System.out.println(System.getProperty("system.class.path").replaceAll(":", "\n"));
And inspect the classpath. Usually such runtime environment (for example apache spark) has such features to allow you to prepend the classpath. You can check with your runtime server environment for such feature.
How can a task be associated to a specific dependency configuration?
If I look the 23.5. Dependency management (gradle java plugin official doc) section part, it states that, for example, compileTestJava task use testCompile configuration.
I just wanted to know how I could achieve that.
gradle is creating these configurations automatically;
if you define a sourceSet, a bunch of things gets created (by convention):
sourceSets {
thing
}
will define configurations: thingCompile, thingRuntime
tasks: compileThingJava, processThingResources, thingClasses
you might want to look at: gradle tasks --all and gradle dependencies
if you want to add dependencies to these configurations
the most preferable to use the generated ones
you may of course create your own configuration and extend from that: configurations { thingCompile.extendsFrom(myConfig) }
I am am migrating project to dagger 1.2.2. I'd like to override some dependencies for functional tests. For that I included the dagger-compiler as a dependency of the androidTest-build(?) as well:
apt "com.squareup.dagger:dagger-compiler:$daggerVersion"
compile "com.squareup.dagger:dagger:$daggerVersion"
androidTestApt "com.squareup.dagger:dagger-compiler:$daggerVersion
Now the compiler complains that he cannot find a class (I guess because both builds now contain the transitive dependencies of dagger-compiler):
Error:Execution failed for task ':app:compileDebugAndroidTestJava'.
> java.lang.NoClassDefFoundError: javax/inject/Scope
Looking around github it seems the approach should work without manually excluding stuff.
Nevermind. Actually reading the whole buildfile helps alot.
Because of previous dependency-foo I had a directive that excluded the missing dependency explicitly:
configurations {
androidTestCompile.exclude(group:'javax.inject')
}
Removing that fixed it.
My project depends on the Pax Exam framework. I declare, among others, these dependencies on Pax (PAX_EXAM_VERSION = 3.4.0):
compile group: 'org.ops4j.pax.exam', name: 'pax-exam-junit4', version: PAX_EXAM_VERSION
compile group: 'org.ops4j.pax.exam', name: 'pax-exam-container-native', version: PAX_EXAM_VERSION
Both of these depend on org.ops4j.pax.exam:pax-exam-spi, which is the module causing my issue.
So, when I try to build my project, the error reported is this one:
Could not resolve org.ops4j.pax.exam:pax-exam-spi:3.4.0
...
Could not parse POM http://repo.maven.apache.org/maven2/org/ops4j/pax/exam/pax-exam-spi/3.4.0/pax-exam-spi-3.4.0.pom
Unable to resolve version for dependency 'com.google.guava:guava:jar'
I have tried:
excluding pax-exam-spi from the transitive dependencies of the modules I depend on (but notice I still need the classes in it to be able to compile), adding Guava to my first-level dependencies, then trying to make pax-exam-spi a first-level dependency with transitive = false (won't work, same problem as above).
same as above, but instead of doing transitive = false, trying to use artifact-only notation, like this:
compile "org.ops4j.pax.exam:pax-exam-spi:${PAX_EXAM_VERSION}#jar"
I know the root of the problem is that the guava version is not declared in the pax-exam-spi pom, but in its parent exam, which only declares the Guava version(s) to use in 2 different profiles' dependencyManagement sessions (this works in Maven because one of the profiles is activated if the property glassfish.release is NOT set, and the other if that property IS set). However, knowing this has not been useful so far :(
Please let me know if there's any not-so-hacky way to make sure Gradle does include the pax-exam-spi's jar in my classpath, but does not even try to parse its POM (in particular, referring to a hard-coded path to the jar is out of question!).