Two Maven Dependencies with different scope - maven

If I have the following two dependencies in the same pom.xml file:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
And I'd like to remove the redundancy. So should I delete the one with scope as runtime because it's included in the other dependency?
Also I'd be happy to understand why one would specify a dependency with scope of runtime.

From Introduction to the Dependency Mechanism - Dependency Scope:
compile
This is the default scope, used if none is specified. Compile dependencies are available in all classpaths of a project. Furthermore, those dependencies are propagated to dependent projects.
(...)
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.
So if you have a compile dependency, runtime is already included and therefore superfluous.
As an example for when to use runtime, take the SLF4J logging API: you compile your sources against slf4j-api.jar (compile dependency), but not the actual implementation, which is distributed separately (and there are several to choose from). However, when packaging your application or running unit tests, Maven should still include an implementation jar, e.g. slf4j-simple.jar (runtime dependency), because otherwise nothing will be logged.

Related

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.

List only used jars

I have Maven projects which I can build with these dependencies:
<dependency>
<groupId>org.wildfly.arquillian</groupId>
<artifactId>wildfly-arquillian-container-embedded</artifactId>
<version>1.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-embedded</artifactId>
<version>9.0.2.Final</version>
</dependency>
There are a lot of jars into these dependencies and I would like to use on the necessary. How I can list which jars are only needed for the build?
The simple answer to you question is that there is no easy way to do what you are asking. In maven you declare for your package all the dependencies that the code inside your package will ever need in all scenarios. In this case if your using only a specific part of the wildfly-embedded package, and that part that you are using only depends on a subset of the package's declared dependencies then Maven has no way of knowing this.
One approach you could take is to simply look at the declared dependencies of those artifacts, exclude one of them, and then run your test suite. Assuming you have a comprehensive test suite if the tests past then you can reasonably assume that the dependency you excluded was not required by any of the parts of the library you utilized. You can do this for each of the declared dependencies.

Why order of Maven dependencies matter?

I thought that the order of Maven dependencies doesn't matter before and regard this as a pro of it. And this is my old pom.xml's dependencies:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.19</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.19</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.19</version>
</dependency>
</dependencies>
It works well, and today I wanna move spring dependency to the bottom so that those jersey related can be together. However then I can no longer make it working, my Jetty complains:
[ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.3.0.M1:run (default-cli) on project mtest: Execution default-cli of goal org.eclipse.jetty:jetty-maven-plugin:9.3.0.M1:run failed: A required class was missing while executing org.eclipse.jetty:jetty-maven-plugin:9.3.0.M1:run: org/apache/commons/logging/LogFactory
That is really confusing, so do I have to concern about dependencies order? How do I know the correct order?
The order of dependencies does matter because of how Maven resolves transitive dependencies, starting with version 2.0.9. Excerpt from the documentation:
(...) this determines what version of a dependency will be used when multiple versions of an artifact are encountered. (...) You can always guarantee a version by declaring it explicitly in your project's POM. (...) since Maven 2.0.9 it's the order in the declaration that counts: the first declaration wins.
To expand upon the other answer (which states that the declaration order affects Maven's dependency mediation for transitive dependencies), there are a few tools you can use:
mvn dependency:tree [-Dscope=[runtime|test]] will show you what dependencies will be available for the selected scope. See here for details
mvn dependency:build-classpath gives you order in which dependencies are available on your classpath (if two or more classpath entries have the same class, the earlier one wins). See here for details
I don't know much about your situation, but it's often the case that you wind up with the wrong version of 1 or more jars at compile/runtime. Declaring your own version of the library in question or locking down the version with <dependencyManagement> are options here.
Now to answer your other question - how do you know what the right order is when declaring dependencies?
My suggestion - the right declaration order is the one that gets you the versions of the dependencies you want, in the order you want them in. Use the tools above to check your dependencies, and tweak the declared order if necessary.
Note that most jars contain disjointedly-named classes, so the exact order in which jars appear on your classpath is usually not that important. The only exception I've noticed is some jars in SLF4J which intentionally shadow classes from the other logger libraries it's intended to replace.

Change scope to provided generates compile errors

I had a dependency declared as followed:
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>${version.jboss.javaee6}</version>
<type>pom</type>
</dependency>
When I change the scope to provided I get compilation errors such as EJB cannot be resolved to a type. I didn't understand, the documentation says that dependencies declared as provided are still used at compile time, and discarded only at deploy time.
So can someone help me understand these compile errors?
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>${version.jboss.javaee6}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
I think the problem is related to the type that you have mentioned in the dependency of that artifact.
Till now whatever I have played with Maven I cannot think of any case when one would need to add pom type dependency. Generally pom type packaging is used for parent module in a project (specify common project configuration like plugin versions, common dependencies, like log4j for example, repositories, properties etc.) and for utility package module (the one that assembles the project and does some other necessary things).
So, as a suggestion remove the type tag from the dependency until you need it for any specific purpose, let it be default i.e jar.

Maven test dependency not being found

I'm declaring a test dependency on powermock with easymock bundled in.
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<version>1.4.12</version>
<type>pom</type>
<scope>test</scope>
</dependency>
When I run mvn test, the test src claims to be able to find org.powermock but not org.easymock, despite it being included in the above dependency.
I wondered whether it was a problem due to transitivity of the test scope, so i tried compile scope also (as the documentation http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html mentions that the compile dependencies are available at test time) without any luck.
I've also tried using a bundled jar instead of pom, to no avail. I realise i could declare the dependencies separately (ie separate dependencies for powermock and easymock) but for my purposes i'm restricted to having just the one dependency including all necessary test libs.
Tracing this back to the powermock parent pom I see that the easymock dependency is marked "provided."
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.1</version>
<scope>provided</scope>
</dependency>
Looks like powermock is expecting its clients (you in this case) to supply the easymock jars.
According to the powermock-easymock-release-full POM, it does not depend on easymock (ie easymock does not appear in the powermock-easymock-release-full dependencies). So you'll have to add another dependency to easymock, dependending on the test engine you're using (JUnit or TestNG): http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.powermock%22%20AND%20%22easymock%22

Resources