Maven 2 - different dependency versions in test and compile - java

I have project that depends on commons-httpclient [2.0] (compile).
I would like to write some jbehave tests - jbehave-core 3.4.5 (test).
Both this dependencies depend on commons-lang but in different versions - 1.0.1 and 2.5.
When I execute mvn package I get [BUID FAILURE] in tests section.
There is an exception for my testcase in surefire-plugin output:
java.lang.NoSuchMethodError: org.apache.commons.lang.StringUtils.substringBeforeLast(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
As I looked in source code - in commons-lang 1.0.1 - indeed, there is no StringUtils.substringBeforeLast(...) method.
Why maven uses commons-lang from commons-httpclient (compile) and not from jbehave-core in testing?
I can't afford to exclude this conflicting dependency in commons-httpclient so it must stay in compile time.
So how can this be resolved - commons-lang 2.5 version in testing and 1.0.1 in compile time?

Maven 3:
Maven 3 will attempt to obtain the nearest dependency, effectively ensuring that only one of the compile or test scoped dependency is used for both the compile and test phases.
(Thanks Vineet Reynolds)
Maven 2 (OLD):
try to define 2 different <dependency> tags with different versions and scopes. Use tag <scope>test</scope> inside dependency for tests and <scope>compile</scope> for compilation.

In Maven 3, you can trick maven by adding a dot after groupId
<dependency>
<groupId>groupId.</groupId>
<artifactId>artifactId</artifactId>
<version>version1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>groupId</groupId>
<artifactId>artifactId</artifactId>
<version>version2</version>
<scope>compile</scope>
</dependency>
The sequence matters here. need to have test first and then compile.

<dependency>
<groupId>groupId.</groupId>
<artifactId>artifactId</artifactId>
<version>version1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>groupId</groupId>
<artifactId>artifactId</artifactId>
<version>version2</version>
<scope>compile</scope>
</dependency>
Adding a dot doesnt work in pom.xml as . is converted to slash which in return generated incorrect URL.
Is thr any other way to do this

It's a really bad idea to have two different versions for compile and test dependency:
Your non-test code might rely on behavior of the newer JAR and fail when using classes of the older JAR.
When you use the older JAR in your tests, the non-test code would fail with the old JAR.
Otherwise you could have used the older JAR anywhere, with the same version...
If you get both JAR versions into your classpath, you cannot know which one gets picked up when running your tests. That's also a bad idea.
Hence you should get non-test and test to the same JAR version dependency.

Related

Maven dependencies exclusions not working

I'm using enforcer plugin of Maven and I see a behavior that I dont quite understand and it's dangerous.
Let's say that I have a conflict since dependency A has bla.jar:1.0 and is in conflict with my dependnecy B which has bla.jar:2.0
Then to fix the conflict, I make an exclude of bla.jar:1.0 from A
<dependency>
<groupId>com.foo</groupId>
<artifactId>A</artifactId>
<version>a.version.bla</version>
<exclusions>
<exclusion>
<groupId>com.omg</groupId>
<artifactId>bla</artifactId>
</exclusion>
</exclusions>
</dependency>
expecting the application will get the bla.jar:2.0 fron classpath. But then I see when I run some unit test that the java proce3ss cannot find bla.jar ion the classpath at all and is giving me ClassNotFound in runtime.
Any idea what's wrong here?
I have in my pom defined from top to bottom B and then A
Please note that exclusions are not the best way to resolve dependency version conflicts.
The best approach is to use <dependencyManagement>. It allows you to set a version that replaces all transitive versions of that dependency.
In your case, I would first change the exclusion to <dependencyManagement>. Then I would proceed in the following way:
Check mvn dependency:list which version of the dependency is on the classpath. It should be the one specified in <dependencyManagement> unless there is no version of that dependency in your dependency tree. If you find more than one, then probably the groupId changed at some point. Then you need exclusions.
Check the scope of the dependency and verify that it is indeed compile.
Then open the dependency jar and see whether this jar really contains the class for which you get ClassNotFound. Often classes change from version to version.

Why Maven dependency exclusion would not cause compile error?

Newly exposed to Maven, I can understand the use case of the <exclusion> tag, but not sure why it wouldn't cause compile error:
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-embedder</artifactId>
<version>2.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
</exclusion>
</exclusions>
</dependency>
...
Is this only possible only when you have another direct dependency on maven-core? otherwise, compile error should happen. (assuming maven-core is used somewhere in maven-embedder)
You are excluding that artifact from that specific dependency, but it could be getting pulled in from another dependency. Using something mvn dependency:tree -Dverbose -Dincludes=maven-core should show you what else is introducing the dependency. The Maven Enforcer plugin can also help exclude transitive dependencies.
There are different possibilities:
As Carl said: Check your dependency:tree if the dependency is not pulled in from somewhere else.
It is possible that maven-core is not used at all, even if maven-embedder indeed uses it: Assume e.g. that maven-embedder has two classes A and B. You only use A, but maven-core is only used by B. Then (if A and B do not use each other), your project might be entirely independent of maven-core. (A side remark: some jars should logically be two separate jars, but where merged together by whatever reason - in our example, one should think about putting A and B in separate artifacts).
It is possible that transitive dependencies are not necessary at compile time, but are used at runtime.
The error will not thrown in the compile time, It will thrown in run time if you use any feature depends on maven-core

Maven test fails because of package junit.org does not exist but tests do work in eclipse [duplicate]

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.

Maven build - force the use of a newer version

I am trying to build protege-server (https://github.com/protegeproject/org.protege.owl.server) from source. I downloaded the source code. Using "mvm -X package" yields the following error:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.
0:compile (default-compile) on project org.protege.owl.server: Compilation failu
re
[ERROR] /c:/Users/user/Programs/webprotege/org.protege.owl.server-master/src/mai
n/java/org/protege/owl/server/connect/local/OSGiLocalTransport.java:[11,32] type
org.osgi.framework.ServiceRegistration does not take parameters
Based on a previous question, an OSGI blogpost explains that the problem was fixed in a later (4.3.1) version of the library.
I tried to refer a newer version of this library in the POM.xml file:
<dependency>
<groupId>org.osgi</groupId>
<artifactId>core</artifactId>
<version>6.0.0</version>
<scope>system</scope>
<systemPath>/c:/Users/user/Downloads/osgi.core-6.0.0.jar</systemPath>
</dependency>
and even downloaded the newer version to specifically target it.
The error still occurs. Is there any way to solve it?
EDIT:
Attempting the solution suggested by #Balazs Zsoldos didn't help and I received the same error message. I noted an import of this package (org.osgi.framework) referring version 1:
<Bundle-Activator>org.protege.owl.server.Activator</Bundle-Activator>
<Bundle-SymbolicName>org.protege.owl.server</Bundle-SymbolicName>
<Bundle-Vendor>The Protege Development Team</Bundle-Vendor>
<Embed-Dependency>antlr, antlr-runtime, stringtemplate</Embed-Dependency>
<Export-Package>org.protege.owl.server*;version=2.0.6-SNAPSHOT</Export-Package>
<Import-Package>!org.antlr.stringtemplate,
!org.apache.commons.cli,
org.osgi.framework;version="1",
*</Import-Package>
An attempt to remove this line did not help either, as it appears in another dependency down stream. I could not find out how to override the downstream import-package instruction.
The effective pom.xml, as generated by eclipse, is attached as a link: https://docs.google.com/document/d/1eHFalUHVZ45ejLes_eqaXLw6ttjcTryphbGr_CKbhRk/edit?usp=sharing
The issue is that older versions of osgi.core are still on the classpath of the as they are imported with different group and artifact ids. Drag and drop the pom.xml to your eclipse and see the Dependency Hierarchy tab of the pom editor to get more information.
The following two are imported by dependencies:
org.osgi:org.osgi.core (by org.apache.felix.log)
org.apache.felix:org.osgi.core (by owlapi distribution)
To solve the problem, you should add the following dependency:
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
And as this does not override the org.apache.felix:org.osgi.core dependency, exclude that one:
<dependency>
<groupId>net.sourceforge.owlapi</groupId>
<artifactId>owlapi-distribution</artifactId>
<version>3.4.5</version>
<exclusions>
<exclusion>
<groupId>org.apache.felix</groupId>
<artifactId>org.osgi.core</artifactId>
</exclusion>
</exclusions>
</dependency>
(and remove the dependency with system scope as you do not need it and its artifactId is different from the standard anyway).
Edit
Just realized that the old osgi.core package is also inside org.apache.felix:org.apache.felix.framework that is pulled transitively by ProtegeLauncher via org.apache.felix:org.apache.felix.main:4.0.3. This means that you should either
Increment the version of org.apache.felix:org.apache.felix.main to the newest (or to one that at least implements osgi 4.3). In this case you do not need osgi.core at all
exclude org.apache.felix:org.apache.felix.main from edu.stanford.protege:ProtegeLauncher (and keep version 4.3.1 or higher of osgi.core)
I tried the second one and another issue comes that surfire plugin cannot be downloaded from maven central (or something similar, you will see).
Notes
The developer of this protege library was clearly not familiar how maven dependency management works and what should have been imported as a dependency. The project imports an OSGi runtime environment transitively that should never happen. For compilation only API should be imported and if the target runtime surely contains that API, it should be imported with provided scope. I would recommend to
not use this library or
clean it out (at least the maven dependency part) and send a pull request so the library can have an acceptable quality

Need to configure Maven project dependency tree, but *not for me*--it's only for those using my projects via Maven Central

I have a new library, called Codelet. It depends on two other libraries I've created, called Template Featherweight and XBN-Java. But the primary library--the one I'm trying to get other people to use!--is Codelet. The other two are secondary. Both are required, but they are only directly used when advanced features are needed.
I build all aspects of all three of these projects with Ant. I use Maven for one reason only: To sign the jars
codelet-0.1.0.jar
codelet-0.1.0-sources.jar
codelet-0.1.0-javadoc.jar
and push them to Maven Central. After shedding significant blood, sweat, tears, and soul in the past week, as evidenced by these four questions
How to use Maven to only sign three jars and push them to Maven Central?
Followup questions: Using Maven to only sign and deploy jars to Maven Central. Build and compilation is done entirely with Ant
Followup part 2 -- Using Maven to only sign and deploy jars to Maven Central. Build and compilation is done entirely with Ant
Why am I getting a "401 Unauthorized" error in Maven?
I have finally gotten the jars to upload to Maven Central via mvn deploy, at least once anyway, so that's big progress.
I'm realizing, however, that in order for other people to actually use Codelet, they need the entire dependency tree to be mapped out in Codelet's POM. I believe this is correct.
I am concerned that mapping this three-project dependency tree, in their three POMs, will essentially require that I duplicate much of my Ant build process in Maven. I am hoping with all hope that I don't need to do this, as Ant works well for me, and Maven and I do not get along.
Here are the dependency trees:
Dependencies for compilation of core library classes and example code, only
All items are listed by Maven groupId / artifactId / version.
XBN-Java 0.1.3 depends on
org.apache.commons / commons-collections4 / 4.0
org.apache.commons / commons-io / 2.4
org.apache.commons / commons-lang3 / 3.3.2
com.google.guava / guava / 16.0
Template Featherweight 0.1.0 depends on
com.github.aliteralmind / xbnjava / 0.1.3 (and its dependencies)
Codelet 0.1.0 depends on
com.github.aliteralmind / templatefeather / 0.1.0 (and its dependencies)
${java.home}/../lib/tools.jar (This is considered "provided", since it's part of the JDK and not on Maven Central)
Dependencies for compilation and execution of unit tests, only
These are in addition to those needed for core-compilation.
For all projects: junit / junit / 4.11 (and its dependency: hamcrest core)
For compilation of "Codelets" (which are used only by javadoc.exe), and execution of javadoc.exe
These are in addition to those needed for core-compilation.
For all projects: com.github.aliteralmind / codelet / 0.1.0 (and all its "core-compilation" dependencies)
(Some background: Codelet automates the insertion of example code into JavaDoc, using inline taglets like
{#.codelet.and.out com.github.mylibrary.examples.AGoodExample}
These optional "Codelet classes", called "customizers", are compiled before running javadoc.exe. They are used to customize how example code is displayed. Once compiled, Codelet is executed automatically, as are all inline taglets, via javadoc.exe.)
For core-compilation it's pretty much linear:
XBN-Java is the root
Template Feather depends on XBN-Java, and
Codelet depends on Template Feather
But for "javadoc", all three projects depend on Codelet. So even XBN-Java depends on Codelet...which depends on Template Feather...which depends on XBN-Java.
The POMs in all three projects are working, although this is only as far as it concerns signing and pushing the jars to Maven Central.
After reading Maven's dependency Mechanism documentation, it seems that all three projects could have the same flat dependency tree
<dependencies>
<dependency>
<groupId>com.github.aliteralmind</groupId>
<artifactId>templatefeather</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.github.aliteralmind</groupId>
<artifactId>codelet</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
But the right way is to have a parent project, which is inherited by the other two. It seems that XBN-Java should be the parent, but given the recursive nature of the dependencies, I'm not sure.
I am not getting the difference between dependencies and dependencyManagement (why some dependencies blocks can go right into the project proper, and others are sub-blocks in dependencyManagement...although it seems related to parent-child), and I also don't understand how "javadoc" fits into the "scope" attribute. While compile and test are explicitely listed, the word "doc" doesn't even exist on the page.
I would appreciate some advice. Thank you.
If your code needs something, but not for compile-time (just for run-time) then declare the dependency, but add a runtime scope.
Now if you want to provide a "starter parent" pom.xml, then release a "starter parent" pom.xml but don't use it in your actual build chain.

Categories

Resources