What Is the Purpose of Mavens Dependency Declarations Classifier Property

What is the purpose of Mavens dependency declarations classifier property?

The classifier distinguishes artifacts that were built from the same
POM but differ in content. It is some optional and arbitrary string
that - if present - is appended to the artifact name just after the
version number.

Source

Differences between dependencyManagement and dependencies in Maven

Dependency Management allows to consolidate and centralize the management of dependency versions without adding dependencies which are inherited by all children. This is especially useful when you have a set of projects (i.e. more than one) that inherits a common parent.

Another extremely important use case of dependencyManagement is the control of versions of artifacts used in transitive dependencies. This is hard to explain without an example. Luckily, this is illustrated in the documentation.

How to change behavior according to maven/gradle scope?

yes and no - sort of.

The general guideline is to create one artifact per pom.xml - most tools work quite nice with this concept. As soon as you go beyond sometimes funky stuff happens. Changing the jar only by scope isn't possible afaik. It would also confuse people a lot. And probably will make troubleshooting very difficult.

But there is a workaround. As you mentioned tests: the jar plugin allows you to export the classes in src/test/java as test-jar and use that as dependency specifying a type.

See How to create a test-jar.

I assume the same mechanism with the type can be used for other things as well.

There is also the concept of classifiers (this is usually used for sources, javadoc and things like that). See this question.

While these things tend to work with maven on the command line, IDEs sometimes start to behave a bit weird if you push type and classifier usage too far.

Maven: how do I reference a *-bin.zip?

The -bin is called a "classifier". Classifiers allow for multiple artifacts with the "same" name.

You want to add <classifier>bin</classifier> to your dependency or artifactItem in order to reference it, instead of putting it in the version.

See the "classifier" part of the Dependencies section in the Maven POM Reference.

dependencyManagement for dependency with classifier and without it

Have you defined ${guava.version}? Look for <properties> in pom.xml:

<properties>
<guava.version>15.0</guava.version>
<!-- another project properties here -->
</properties>

Also, current version of Guava (16.0.1 as of writing this answer) is CDI agnostic, and thus you should use simple dependency declaration without need for distinct profiles for Tomcat / JBoss or use of cdi1.0 classifier:

<properties>
<guava.version>16.0.1</guava.version>
<!-- another project properties here -->
</properties>

<!-- <dependencies> -->

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>

P.S. <classifier>cdi1.0</classifier> is available only in Guava 15.0 (as a bug workaround), so if you're stuck on 15.0 for some reason you should probably not be using ${guava.version} but rather hardcode <version>15.0</version>...

Including dependencies in a jar with Maven

You can do this using the maven-assembly plugin with the "jar-with-dependencies" descriptor. Here's the relevant chunk from one of our pom.xml's that does this:

  <build>
<plugins>
<!-- any other plugins -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>

Referencing a shared dependency version - what is the best practice

Common convention is to have a root pom, defining the version, and then leaving the version information out in your project poms so they will pick up the one from root pom.

Often, Spring is a kind of special case as it has multiple modules that you'd want to have the same version, so something like

  <properties>
<spring.version>3.0.0</spring.version>
</properties>

and

  <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>${spring.version}</version>
</dependency>

in the root pom is what we use. In the project pom it would be then like this:

  <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</dependency>

However, if Spring is regarded just as a regular module, it would be just

  <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>3.0.0</version>
</dependency>

in the dependencies section in the root pom, and

  <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</dependency>

on project pom.

maven-assembly-plugin: How to use appendAssemblyId

That is because you are mis-interpreting the warnings.


Let's recap. A Maven project that is not of type pom will always produce, by default, what is called a main artifact. For a JAR, this artifact is the result of packaging the compiled sources into a JAR; for a WAR, it is the result of building the web-application.

What is important to remember is that this artifact is attached to the project: this terminology is useful when the project is installed (with mvn install), deployed (with mvn deploy) or released (with the maven-release-plugin). Attached means that this artifact will be installed / deployed / released when the project is. Not all files generated during a Maven build (basically, everything under the target folder) are; only the files that were attached. As such, you can very well create a lot of files under target but have a single installed artifact.

Alongside this main artifact, you may want your build to produce other artifacts to install or deploy. That's the concept of additional or secondary attached artifacts. The main examples are the Javadoc or the sources: typically when a project is released, its Javadoc and its sources also are. And that is where the notion classifier kicks in.

In a Maven repository, each and every file has to follow the same naming convention: artifactId-version(-classifier).type. Every secondary artifact will have the same GAV (group id, artifact id, version) as the main artifact so if you want to put inside a Maven repo 1 main artifact and 1 attached artifact (like it would be the case for a main JAR along with its JAR Javadoc and JAR sources), you need some way to distinguish them. Which is what the classifier is for: distinguish secondary artifacts from the main artifact.


Let's go back to your example now. Your Maven project, which is of jar packaging, will produce by default a main JAR artifact called my.module-5.0.0-SNAPSHOT.jar; still by default, this main JAR is attached to the project (and ready to be installed / deployed). Now you're configuring the maven-assembly-plugin to create a new JAR artifact (called helper-5.0.0-SNAPSHOT.jar but it really doesn't matter). The Assembly Plugin, by default, attaches to the project the artifact it produces. So you end up with 2 attached artifacts

  1. having the same artifact id of my.module; the fact that the file on disk inside the target folder is named helper for one is irrelevant, only the GAV coordinates matter
  2. having the same version of 5.0.0-SNAPSHOT
  3. having the same packaging of JAR

and no classifier to distinguish them. This is what raises the warning: you end up attaching to the project a secondary artifact that effectively replaces the main one, simply because it has the same coordinates. So the result is:

  1. Both files having different names on disk inside target, but that is irrelevant because
  2. Both share the same coordinates so only 1 will survive.

It is the one produced by the Assembly Plugin that will win the conflict, and replace the attached main artifact.

If you want to convince yourself of all that, run mvn clean install on the project and check your local repo. You will notice that only the jar-with-dependencies artifact will be installed. The other one (the main artifact) went poof.

You can also configure a <distributionManagement>:

<distributionManagement>
<repository>
<id>local-repo-test</id>
<url>file://...</url>
</repository>
</distributionManagement>

and invoke mvn clean deploy. You can then check that the only deployed artifact will be the jar-with-dependencies.


Final note: Yes, the classifier parameter of the Assembly Plugin is deprecated, because you should just use the assembly id as classifier.

Maven include JavaFX dependencies for operation system i am currently running on even when i classify other

When you use JavaFX via Maven artifacts from Maven Central, you typically add to your pom:

    <dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
</dependency>
</dependencies>

and it just works on your platform, no need for classifiers.

Now if you check the dependencies, and you are on Linux for instance, you will find:

$ mvn dependency:tree

[INFO] org.openjfx:javafx-controls:jar:16:compile
[INFO] +- org.openjfx:javafx-controls:jar:linux:16:compile
[INFO] \- org.openjfx:javafx-graphics:jar:16:compile
[INFO] +- org.openjfx:javafx-graphics:jar:linux:16:compile
[INFO] \- org.openjfx:javafx-base:jar:16:compile
[INFO] \- org.openjfx:javafx-base:jar:linux:16:compile

Same if you are on Windows or Mac OS.

You can guess how javafx-controls gets the traverse dependencies: via its pom. But how does it get the classifier?

Let's check the pom:

<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
<parent>
<groupId>org.openjfx</groupId>
<artifactId>javafx</artifactId>
<version>16</version>
</parent>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
<classifier>${javafx.platform}</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>16</version>
</dependency>
</dependencies>
</project>

As you can see, there is already a classifier applied, based on a ${javafx.platform} maven property.

That property is resolved via a the parent pom:

    <parent>
<groupId>org.openjfx</groupId>
<artifactId>javafx</artifactId>
<version>16</version>
</parent>

If you check its content:

<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>org.openjfx</groupId>
<artifactId>javafx</artifactId>
<version>16</version>
<packaging>pom</packaging>
<name>openjfx</name>
<description>OpenJFX JavaFX</description>
<url>https://openjdk.java.net/projects/openjfx/</url>
<properties>
<javafx.version>16</javafx.version>
</properties>
<dependencyManagement></dependencyManagement>
<profiles>
<profile>
<id>linux</id>
<activation>
<os>
<name>linux</name>
</os>
</activation>
<properties>
<javafx.platform>linux</javafx.platform>
</properties>
</profile>
// windows profile
// mac profile
...

So that means that there is a profile that gets activated based on your current platform, and that sets automatically the property ${javafx.platform}, which in turn set your dependencies classifier.

So what happens if you add a different classifier to your JavaFX dependency (and you are on Linux for instance):

    <dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
<classifier>win</classifier>
</dependency>
</dependencies>

you will get:

$ mvn dependency:tree

[INFO] \- org.openjfx:javafx-controls:jar:win:16:compile
[INFO] +- org.openjfx:javafx-controls:jar:linux:16:compile
[INFO] \- org.openjfx:javafx-graphics:jar:16:compile
[INFO] +- org.openjfx:javafx-graphics:jar:linux:16:compile
[INFO] \- org.openjfx:javafx-base:jar:16:compile
[INFO] \- org.openjfx:javafx-base:jar:linux:16:compile

The dependency is correct, you get the win version first, but then its own pom has a dependency on javafx-controls:${javafx.platform}, which is resolved based on your platform (i.e. Linux), and that explains why you get the platform artifact as well.

I don't see how this can be avoided, as you can't disable the profile activation inside the dependency's pom.

EDIT

If you keep reading the javafx parent pom, there is this profile:

<profile>
<id>javafx.platform.custom</id>
<activation>
<property>
<name>javafx.platform</name>
</property>
</activation>
<properties>
<javafx.platform>${javafx.platform}</javafx.platform>
</properties>
</profile>

which is a profile that gets activated if javafx.platform is set, and it overrides previous values of the ${javafx.platform} value.

So I've just tried on Linux (without adding any classifier to the dependency):

$ mvn -Djavafx.platform=win dependency:tree

[INFO] com.gluonhq.samples:hellopi:jar:1.0.0-SNAPSHOT
[INFO] \- org.openjfx:javafx-controls:jar:16:compile
[INFO] +- org.openjfx:javafx-controls:jar:win:16:compile
[INFO] \- org.openjfx:javafx-graphics:jar:16:compile
[INFO] +- org.openjfx:javafx-graphics:jar:win:16:compile
[INFO] \- org.openjfx:javafx-base:jar:16:compile
[INFO] \- org.openjfx:javafx-base:jar:win:16:compile

and that works, no more platform classifiers.

Still, your IDE might show platform dependencies, but as long as you run with that property (like mvn -Djavafx.platform=win javafx:run) that should work.



Related Topics



Leave a reply



Submit