Using maven property in build.gradle - 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.

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)

Resolve Library Conflicts With 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.

IntelliJ How to force downgrade dependency version?

I have a persistent problem with maven dependencies version changes in IntelliJ. Whenever I try to use a previous version of a library and change the dependency version in my pom.xml nothing happens. Maven continues to use the newer version of the library.
For example I want to use:
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
But Maven repo has version 2.0.2 saved :
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
So for my projects version 2.0.2.RELEASE is used.
I tried reimporting the project first. Then I tried "reimpor all maven projects". Then I checked Settings > Maven > Always update snapshots. I also tried opening the project settings and deleting the dependency from there, but on reimport the 2.0.2 version will be imported in the project. For now the only thing that works is deleting manually the folder from the ".m2" folder.
Shouldn't library versions be strictly followed and shouldn't version 2.0.1 v be used for my project?
The moment you change the version of the artifacts, maven will use the same version. It will never use neither new version nor the older version. Since you are using intellij, you can check which are the jar files along with their version used. See below the screenshot.
You can expand the External libraries as shown below and you can check the dependencies used in pom.xml.
Besides, you can also check in command prompt. Go to command prompt and point to the project directory and type the following command.
mvn install dependency:copy-dependencies
You can see all the required dependencies along with version information in target folder.
I suggest you not to delete the .m2 directory as you may have to download all the dependencies once again.
If you want to enforce the use of a particular dependency version you can use:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
What this will do is exclude the dependency unless it actually gets used, and then if it does gets used it only uses the version you have specified.
Not clear what is the issue.
Repo can contain everything, no matter if dependency is present locally.
Also, Idea does not resolve dependency itself, we use maven api to resolve them.
By default, maven takes dependency which is nearest to root (see https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)
Specifiying explicit dependency in root pom should force using this version.
Could you please provide mvn dependency:tree output and corresponding IDEA maven dependency diagram (if you have IU)?
If Idea resolve another dependency version than maven, please fill an issue at https://youtrack.jetbrains.com/issues

A conflicting jar is being added to Maven dependencies - how to track down?

I have a dependency that I have added to my project:
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-server</artifactId>
<version>7.0.5</version>
</dependency>
When I compile and run I get an error indicating a mismatch of signatures. Looking at my Maven Dependencies in my Java Build Path (Eclipse) I see a jar being added by Maven for Vaadin version 6.8.8. I have scoured my pom.xml and do not see that I have added that. I assume that this dependency is being added by another dependency.
I definitely want to use Vaadin version 7.0.5. As long as version 6.8.8 keeps getting included it will be an issue. How can I resolve this?
mvn dependency:tree
Once you have its output you can add a suitable exclusion.

Maven: Include POM with used dependencies in assembly

We deliver our package with many external dependencies to customers. Now customers can use you libraries to develop stuff on top. For those who are also using Maven we would like to include a pom.xml file in the assembly which contains all dependencies, so they can simply use it in their Maven build:
It should contain all dependencies used by us as follows:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math</artifactId>
<version>2.1</version>
<scope>compile</scope>
</dependency>
Is there a way to achieve that in Maven?
The pom.xml for your jar/war is by default placed inside your jar/war in the location META-INF\maven\<groupId>\<artifacdId>
You have two choices:
The first one which is the most common and preferred way is relying on Maven's transitive dependency resolution.
Have a POM (assume called foo-api:1.0) in your project that declares the dependency (e.g. A:1.0:jar, B:1.0:jar).
Developer's own project (bar:2.0) should then simply depends on foo-api:1.0. Maven will simply include A:1.0:jar and B:1.0:jar as dependency of bar:2.0, through the transitive dependency resolution.
Another way is similar to the above approach, but use foo-api:1.0 as parent POM of bar:2.0.
Either way should work but which one is suitable depends on your design.

Resources