Resolve Library Conflicts With Maven - maven

Starting with kotlin 1.4.30, the kotlin-compiler-embeddable dependency has included the files for the 'fastutil' library inside their main jar package. The problem it this conflicts with my local specified version of fastutil in my pom.xml file.
Is there any way I can include the 1.4.30 kotlin-compiler-embeddable dependency and ignore the /it/unimi/dsi/fastutil folder that way it will only use my version I specified?
Screenshot of kotlin-compiler-embeddable layout:
Project is here: https://gofile.io/d/9m5LiV
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap // Default imports from the kotlin-compiler-embeddable lib
fun main(args: Array<String>) {
// http://fastutil.di.unimi.it/docs/it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap.html#%3Cinit%3E(int)
// ^ this is possible when you dont have a kotlin-compiler-embeddable conflict
// Because its importing this class from the kotlin-compiler-embeddable library
// instead of the fastutil library itself
val map = Int2ObjectOpenHashMap<String>(10)
println("Hello World!")
}

Maven 2.0.9 introduced deterministic ordering of dependencies on the classpath back in 2008.
If you have 2 dependencies containing the same class, first one mentioned in the pom wins.
You can use mvn dependency:build-classpath to inspect the class path.
In your case, place fastutil before kotlin compiler.
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.2.1</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-compiler-embeddable</artifactId>
<version>1.4.30</version>
</dependency>
Notes:
The wording of your question is puzzling. kotlin-compiler-embeddable is a regular dependency in your project, not a plugin.
I checked that kotlin-compiler also has fastlib pulled in, so using it instead of kotlin-compiler-embeddable won't help
The missing constructor problem comes from the fact that kotlin is not pulling in fastutil itself, but a repackaged version intellij-deps-fastutil-8.3.1-1. See commit: Add fastutil dependency for 202 and higher platforms
If you intend to distribute your app as an uber-jar, make sure to check your packager oprions. Maven shade plugin has powerful filtering tools.
Although relying on classpath order is fast to implement and works, it can get surprising. Consider repackaging your kotlin compiler dependency without fastlib.

Related

Spring Boot autoconfigure and its dependencies

I checked the source code of module spring-boot-autoconfigure
It has configurations classes for plenty of technologies : data, redis, cassandra, JPA, LDAP etc...
How can this module can compile properly without including all theses technologies dependencies jar in its POM ?
If I take the example of HibernateJpaAutoConfiguration class :
It uses beans/classes from other Spring modules like spring-orm :
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
However spring-boot-autoconfigure has no dependency to spring-orm in its POM. So how is compilation possible ?
This is possible because they apply Maven's concept of optional dependencies:
Optional dependencies are used when it's not possible (for whatever reason) to split a project into sub-modules. The idea is that some of the dependencies are only used for certain features in the project and will not be needed if that feature isn't used. (...) However, since the project cannot be split up (again, for whatever reason), these dependencies are declared optional. If a user wants to use functionality related to an optional dependency, they have to redeclare that optional dependency in their own project.
In Maven, it would usually look like this:
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<optional>true</optional>
</dependency>
In this example, the project is compiled with Project-A. However, Project-A is not shared as transitive dependency.
The developers of Spring Boot use Gradle instead of Maven. They wrote their own Gradle plugin to replicate this behavior. The result looks something like this:
dependencies {
...
optional("org.springframework:spring-orm")
(see spring-boot-autoconfigure/build.gradle)

Using maven property in build.gradle

I have a build.grade that references a pom/bom file.
I am using gradle 4.6, so I specified enableFeaturePreview("IMPROVED_POM_SUPPORT") in my settings.gradle.
The bom file contains the dependencyManagement tag and that all works fine. I can add gradle dependencies for a library mentioned in the dependencyManagement tag without specifying the version and gradle will get it from the bom.
Now, I want to use a library that is not in the bom's dependencyManagement tag but is in the same family as one that is. Specifically, sl4fj-api is defined in the bom:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${version.lib.slf4j}</version>
</dependency>
and I want to use the slf4j-ext library with the same version:
compile "org.slf4j:slf4j-ext"
Is the above somehow possible?
I suspect not, but this seems like it should be doable:
compile "org.slf4j:slf4j-ext:${version.lib.slf4j}"
But alas, the bom properties are not accessible using project::getProperty: Could not get unknown property 'version.lib.slf4j'
Or, given the slf4j-api dependency, can I get its version number after it has been evaluated and add another dependency using that version number or is that an ordering dilemma?
Any suggestions?
I found the following related question:
Gradle Maven Bom Properties
But I really do not want to do a full blown parse of the bom inside every sub-project.
I also found the following 'partial answer':
How to get properties of parent Maven to Gradle
but here it seems like the dependency information, including the version, is being duplicated from the bom/pom instead of referenced.

How to import classes from `com.android.build.api.transform` package in Maven

I am trying to transfer a gradle-based build plugin for android to a maven build system.
Up to now I was successful except with the android part.
It seems that I am missing classes from the package com.android.build.api.transform. Although I used this code
<dependency>
<groupId>com.android.tools.build</groupId>
<artifactId>gradle</artifactId>
<version>2.2.0</version>
<type>jar</type>
</dependency>
which is supposed to provide (rather indirectly) the required classes/packages, it seems that this is not working.
I also added
<repositories>
<repository>
<id>android</id>
<name>android</name>
<url>https://plugins.gradle.org/m2/</url>
</repository>
</repositories>
just in case, with no luck. Still the project is not able to compile due to missing classes.
Any idea what I am missing? I am very new to the gradle/maven scene, and I still feel out of my waters with these tools.
For reference here is a link to the javadoc of this artifact.
Thanks for your help
The 'gradle' artifact does not contain the missing package. As you mention, it depends transitively on at least one artifact that contains that package, but only in scope 'runtime'. Hence, it will not be available to your project on the compile classpath.
Anyway, adding the dependency explicitly in your pom.xml is the right thing to do. A search for the missing package on search.maven.org shows that you have the choice between com.android.tools.build:transform-api and com.android.tools.build:gradle-api. Locking at the transform-api artifact reveals that it's deprecated and encourages to use gradle-api instead. (The latest version is '2.0.0-deprecated-use-gradle-api'). I downloaded the gradle-api jar file, which indeed has the missing package. So please try adding that artifact to your pom.xml instead:
<dependency>
<groupId>com.android.tools.build</groupId>
<artifactId>gradle-api</artifactId>
<version>2.3.0</version>
</dependency>
I didn't check version 2.2.0, but if you for some reason want to use the older version, it will probably work too.
the transform API was a Google's Android Gradle plugin technology. but it was absorbed into and expanded by Gradle. so newer Android plugins migrated to the Gradle API and they no longer include the transform engine, which now is part of Gradle. if you use the deprecated transform API from Google that was bundled with older plugins, you will get the engine. but what you plan to do about all the other dependencies on Gradle, i have no idea.

How to define a module being required, but not a dependency in Apache Maven

I have a Maven multi-module project, with one (or many) modules called "plugin-xx", in the main "runtime" module, I'm dynamically loading a class from a plugin module.
To avoid classloading conflicts, I'm creating a new classloader, pointing to the jar in the target directory of "plugin-xx".
So for the "runtime" module, I would like to tell Maven, that "plugin-xx" needs to produce a jar, but I don't want this jar to be in the classpath of "runtime".
Adding "plugin-xx" as a dependency would include it into the classpath.
Include plugin-xx as a dependency but use a dependency scope other than compile. I think you want this one:
<scope>provided</scope>
From the docs:
provided
This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.
I'm not totally clear on your requirements so it's possible that you want this instead:
<scope>runtime</scope>
From the docs:
runtime
This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
You can use runtime scope for your dependency. Definition looks like this:
<dependency>
<groupId>plugin-xx</groupId>
<artifactId>plugin-xx</artifactId>
<version>1.0</version>
<scope>runtime</scope>
</dependency>
You won't see the plugin on classpath in your main module during compilation time but it will be placed on classpath on runtime so you can dynamically load it with your ClassLoader.

Maven 3 and JUnit 4 compilation problem: package org.junit does not exist

I am trying to build a simple Java project with Maven. In my pom-file I declare JUnit 4.8.2 as the only dependency. Still Maven insists on using JUnit version 3.8.1. How do I fix it?
The problem manifests itself in a compilation failure: "package org.junit does not exist". This is because of the import statement in my source code. The correct package name in JUnit 4.* is org.junit.* while in version 3.* it is junit.framework.*
I think I have found documentation on the root of the problem on http://maven.apache.org/plugins/maven-surefire-plugin/examples/junit.html but the advice there seems to be meant for Maven experts. I did not understand what to do.
Just to have an answer with the complete solution to help the visitors:
All you need to do is add the junit dependency to pom.xml. Don't forget the <scope>test</scope>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
#Dennis Roberts: You were absolutely right: My test class was located in src/main/java. Also the value of the "scope" element in the POM for JUnit was "test", although that is how it is supposed to be. The problem was that I had been sloppy when creating the test class in Eclipse, resulting in it being created in src/main/java insted of src/test/java. This became easier to see in Eclipse's Project Explorer view after running "mvn eclipse:eclipse", but your comment was what made me see it first. Thanks.
my problem was a line inside my pom.xml i had the line <sourceDirectory>${basedir}/src</sourceDirectory> removing this line made maven use regular structure folders which solves my issue
removing the scope tag in pom.xml for junit worked..
I had the same problem. All i did was - From the pom.xml file i deleted the dependency for junit 3.8 and added a new dependency for junit 4.8. Then i did maven clean and maven install. It did the trick. To verify , after maven install i went project->properties-build path->maven dependencies and saw that now the junit 3.8 jar is gone !, instead junit 4.8 jar is listed. cool!!. Now my test runs like a charm.. Hope this helps somehow..
Add this dependency to your pom.xml file:
http://mvnrepository.com/artifact/junit/junit-dep/4.8.2
<!-- https://mvnrepository.com/artifact/junit/junit-dep -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>4.8.2</version>
</dependency>
I had my files at the correct places, and just removing <scope>test</scope> from the JUnit dependency entry solved the problem (I am using JUnit 4.12). I believe that with the test scope the dependency was just being ignored during the compilation phase. Now everything is working even when I call mvn test.
My case was a simple oversight.
I put the JUnit dependency declaration inside <dependencies> under the <dependencyManagement/> node instead of <project/> in the POM file. Correct way is:
<project>
<!-- Other elements -->
<dependencies>
<!-- Other dependencies-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
<project>
I had a quite similar problem in a "test-utils" project (adding features, rules and assertions to JUnit) child of a parent project injecting dependencies.
The class depending on the org.junit.rules package was in src/main/java.
So I added a dependency on junit without test scope and it solved the problem :
pom.xml of the test-util project :
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
pom.xml of the parent project :
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
How did you declare the version?
<version>4.8.2</version>
Be aware of the meaning from this declaration explained here (see NOTES):
When declaring a "normal" version such as 3.8.2 for Junit, internally this is represented as "allow anything, but prefer 3.8.2." This means that when a conflict is detected, Maven is allowed to use the conflict algorithms to choose the best version. If you specify [3.8.2], it means that only 3.8.2 will be used and nothing else.
To force using the version 4.8.2 try
<version>[4.8.2]</version>
As you do not have any other dependencies in your project there shouldn't be any conflicts that cause your problem. The first declaration should work for you if you are able to get this version from a repository. Do you inherit dependencies from a parent pom?
Me too had the same problem as shown below.
To resolve the issue, below lines are added to dependencies section in the app level build.gradle.
compile 'junit:junit:4.12'
androidTestCompile 'com.android.support.test:runner:0.5'
Gradle build then reported following warning.
Warning:Conflict with dependency 'com.android.support:support-annotations'.
Resolved versions for app (25.1.0) and test app (23.1.1) differ.
See http://g.co/androidstudio/app-test-app-conflict for details.
To solve this warning, following section is added to the app level build.gradle.
configurations.all {
resolutionStrategy {
force 'com.android.support:support-annotations:23.1.1'
}
}
I had a similar problem of Eclipse compiling my code just fine but Maven failed when compiling the tests every time despite the fact JUnit was in my list of dependencies and the tests were in /src/test/java/.
In my case, I had the wrong version of JUnit in my list of dependencies. I wrote JUnit4 tests (with annotations) but had JUnit 3.8.x as my dependency. Between version 3.8.x and 4 of JUnit they changed the package name from junit.framework to org.junit which is why Maven still breaks compiling using a JUnit jar.
I'm still not entirely sure why Eclipse successfully compiled. It must have its own copy of JUnit4 somewhere in the classpath. Hope this alternative solution is useful to people. I reached this solution after following Arthur's link above.
I also ran into this issue - I was trying to pull in an object from a source and it was working in the test code but not the src code. To further test, I copied a block of code from the test and dropped it into the src code, then immediately removed the JUnit lines so I just had how the test was pulling in the object. Then suddenly my code wouldn't compile.
The issue was that when I dropped the code in, Eclipse helpfully resolved all the classes so I had JUnit calls coming from my src code, which was not proper. I should have noticed the warnings at the top about unused imports, but I neglected to see them.
Once I removed the unused JUnit imports in my src file, it all worked beautifully.
Find the one solution for this error if you have code in src/main/java Utils
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.9.1</version>
</dependency>
Changing the junit version fixed this for me. Seems like version 3.8.1 didn't work in my case. Issue fixed upon changing it to 4.12
I met this problem, this is how I soloved it:
Context:
SpringBoot application
Use maven to manage multiple modules
Add junit's maven dependency in root POM's dependencyManagement(rather than dependencies, their differences can be found here)
Intend to test class or folder inside one of the root module's child module
PS: If your situation does not match the context above, this solution may not solve your problem.
Steps
right click at the class or folder you want to test:
Choose More Run/Debug -> Modify Run Configuration
Change the module option to the one you want to test from root module
By default , maven looks at these folders for java and test classes respectively -
src/main/java and src/test/java
When the src is specified with the test classes under source and the scope for junit dependency in pom.xml is mentioned as test - org.unit will not be found by maven.

Resources