Java9 Multi-Module Maven Project Test Dependencies - java

I have a multi-module maven project with three modules core, utils and test-utils
Core has the following dependencies definition
<dependency>
<groupId>my.project</groupId>
<artifactId>utils</artifactId>
</dependency>
<dependency>
<groupId>my.project</groupId>
<artifactId>test-utils</artifactId>
<scope>test</scope>
</dependency>
I have added Java 9 module-info.java definitions for all three modules and core's looks like this:
module my.project.core {
requires my.project.utils;
}
However I cannot figure out how to get core's test classes to be able to see the test-utils classes during test execution. When maven-surefire-plugin attempts the test run I get class not found.
If I add a requires my.project.testutils; to core's module-info.java:
module my.project.core {
requires my.project.utils;
requires my.project.testutils; //test dependency
}
Then at compile time I get an error that the my.project.testutils module can't be found (presumably because it's only brought in as a test dependency).
How does one work with test dependencies in a Java 9 modular world? For obvious reason's I don't want my main code to pull in test dependencies. Am I missing something?

With maven and java9, if your my.project.testutils is a test scope dependency, you don't need to explicitly include(requires) it in the module descriptor.
The test dependencies are taken care via the classpath itself. So you can simply remove the testutils and it would be patched by maven while executing tests.
module my.project.core {
requires my.project.utils;
}
Refer to the slide 30 pertaining to maven-compiler-plugin.
I would also suggest you take a look at Where should I put unit tests when migrating a Java 8 project to Jigsaw and this comment by Robert confirming on the implementation that maven follows.
Edit: Created a sample project drawing an analogy that the main module is same as your core, the dependency on guava is same as your utils and the junit dependency is same as your testutils.

Related

Why are jackson library dependencies missing when used in sub project using gradle?

I have a gradle project P which has module A and B. Module A has this jackson dependencies:
...
dependencies {
...
compile 'com.fasterxml.jackson.core:jackson-core:2.12.0-rc1'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1'
compile 'com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1'
compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.12.0-rc1'
...
}
...
and module B uses module A, and has no need for including this dependencies because jackson usage is encapsulated in module A. But when code executed from module B reaches a statement that invokes code from Module A using it, I get exception:
java.lang.NoClassDefFoundError: com/fasterxml/jackson/dataformat/xml/XmlMapper
If I add the same dependencies to Module's B gradle.build file, the code works.
The question is, why would I include them if Module A does not use the library?
Shouldn't dependencies in Module A be compiled, packaged, so that when Module A is used elsewhere, its code works (using its included dependencies such as jackson library as in this example)
Disclaimer: I don't know Gradle, but this sounds like a problem common to Maven and Gradle.
The fact that you can build the module, but not run the module, means that somewhere you are not bringing the transitive dependencies into the Spring Boot fat jar. Jackson doesn't do anything weird with metadata files, classloaders, etc. It plays well with others in a fat jar.
Given that you haven't shared much of your build files, the easiest way to figure out if something has excluded the Jackson XML module is to just run jar -xvf target/app.jar and inspect the output to see if it's in there.
If it's not, look for a Gradle equivalent of the Maven dependency plugin's dependency-tree target that will show you the whole transitive dependency tree. If it's being excluded you'll definitely see it missing from a dependency dump.

Java 9, Hibernate and java.sql/javax.transaction

I've tried to "upgrade" a project using Hibernate to Java 9, but I am having problems getting the module to function properly.
The relevant part of my module-info.java looks like this:
module test {
...
requires java.base;
requires hibernate.core;
requires javax.transaction;
requires java.sql;
}
and the relevant dependencies in my POM are
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec, 2.0.0.Alpha1
org.hibernate:hibernate-core, 5.2.12.Final
javax.transaction:javax.transaction-api, 1.2
The problem is, if I run the program, I get a NoClassDefFoundError for javax.transaction.SystemException. I looked into this, and quite obviously, my module is missing a requires on javax.transaction.
So I add a module dependency on javax.transaction-api. I then go on and attempt to run the program again - now I'm missing java.sql.SQLException.
Here is what I am having a problem with: if I add a dependency on the module java.sql, which contains this class, I end up with a conflict:
module reads package javax.transaction.xa from both java.sql and javax.transaction.api
java.sql and javax.transaction.api contain different packages, and have one in common (javax.transaction.xa), but I require all of them.
How do I deal with this? Is there something simple I am missing?
Use version 1.3 instead of 1.2 of javax.transaction-api, in this version javax.transaction.xa has been removed.
Maven dependency:
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.3</version>
</dependency>

Including JUnit 5 dependency in IntelliJ IDEA

From jetbrains blog:
IntelliJ IDEA supports the ability to actually run tests written for
JUnit 5 – there’s no need to use the additional libraries (like the
Gradle or Maven plugins for example), all you need is to include the
JUnit 5 dependency.
I'm new to Java and IntelliJ IDEA and it's not clear to me what are the steps that I should do for making test using Junit 5.
If your project is Maven or Gradle based, the dependency is added via pom.xml or build.gradle, otherwise you just add the .jar files to the Module Dependencies.
IDE can help you with that, press Alt+Enter on the red code:
The following dependencies will be downloaded from the Maven repository and added to the classpath:
I made this work by adding this to my pom:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.0.0-M4</version>
<scope>test</scope>
</dependency>
Previously you need plugin to run unit test like this
buildscript {
repositories {
mavenCentral()
// The following is only necessary if you want to use SNAPSHOT releases.
// maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
}
dependencies {
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M2'
}
}
apply plugin: 'org.junit.platform.gradle.plugin'
But for JUnit5 no need of plugin just compile
dependencies {
testCompile 'org.junit.jupiter:junit-jupiter-api:5.0.0-M2'
}
Got the latest IntelliJ IDEA (2017.3), being able to add JUnit5 library when creating test class in IntelliJ, but still failed to find tests. Tried the suggestion by #CrazyCoder, and found out the org.junit.jupiter.api has existed in my IntelliJ and has the version 5.0.0-M6. And finally solved by downloading org.junit.platform:junit-platform-commons:1.0.0-M6 from Maven Repository and adding it into classpath.
For someone like me, new to the IntelliJ, the detailed steps I followed:
Open Project Settings -> Libraries -> + New Project Library -> from Maven...
Search and add org.junit.platform:junit-platform-commons:1.0.0-M6
Modules -> module name you want to add it to -> Dependencies -> + 2 Library ... (should have library jar listed)

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.

Get classpath for integration tests of multi-module project with maven-ant-task

I have a multi-module project built with maven. I need to run the project's integration tests daily. It is not possible to do this during the standard maven build cycle, because on runtime the integration tests defined within the modules have circular dependencies, which are illegal for me to declare on their poms.
Instead, I have created a separate project named Global that lists all modules jars and test-jars as its dependencies. Global has the same parent as all the modules. The idea is that using maven-ant-tasks I will be able to get a classpath of all modules jars and test-jars and go on from there. Global's pom.xml dependency section is as follows:
<dependency>
<groupId>mygroup</groupId>
<artifactId>A</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>mygroup</groupId>
<artifactId>A</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mygroup</groupId>
<artifactId>B</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>mygroup</groupId>
<artifactId>B</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
...etc
The problem is that I cannot seem to get a classpath that contains all jars and test-jars declared on Global's pom.xml (and their runtime dependencies) using the ant tasks available. I have tried (among other things):
<dependencies pathId="cp1" type="jar" usescope="runtime">
<pom file="${basedir}/pom.xml">
<profile id="DEV" />
</pom>
</dependencies>
[1] This one fetches all runtime dependencies. Nothing wrong with that.
<dependencies pathId="cp2">
<dependency groupId="mygroup" artifactId="Global" version="myVersion" scope="test" type="test-jar"/>
</dependencies>
[2] This one fetches all runtime dependencies along with Global-myversion-tests.jar, but no other test-jar.
<dependencies pathId="cp3" type="test-jar" usescope="test">
<pom file="${basedir}/pom.xml">
<profile id="DEV" />
</pom>
</dependencies>
[3] This one fetches nothing.
Obviously, declaring something like [2] once for each module will do the trick, but I am looking to create a setup that will not need to edit a gazillion files each time a new module is added or removed. BTW I am using maven-ant-task-2.1.3.
Thanks for any input.
---Edits for #yannisf accepted answer---
You should not ever have cyclic dependencies
I assume you mean for maven builds. Having cyclic dependencies on runtime is pretty common, for example:
Module A declares interface: UploadToDocumentManagementSystem
Module B implements it in : UploadToCoolDms (that way in the future, when the DMS system changes to CoolerDms module B can be replaced by a new implementation with no side-effects to the rest of the app).
Module B depends on A compile time (and, by definition, runtime as well)
Module A depends on B on runtime
Maven does not allow to declare this. The reason, that I can sympathize with, is that maven needs to complete build cycles (including tests) of multi-module projects in a specific order. Thing is, it is not really necessary to declare it if you get rid of any runtime dependecy to B for the tests of A (which is good practice and should happen anyway).
You should do things the maven way instead of resorting to ant-tasks
Fair enough, I can see how maven-ant-tasks was not made for this use.
In your global pom you are declaring dual types for the same artifact (jar, test-jar)
Is that a problem in general? For example module A contains some samples for its tests that I would like to use in the tests of module B as well. Is it wrong (by maven best practices standards) to declare that B depends on A jar (compile scope) and on A test-jar (test scope)? Won't an integration tests project justify to depend on a module as well as the same module's samples and resources used for its unit tests?
tl;dr version: I will attempt to rearrange the tests declared on the modules and create separate module(s) for integration tests (assuming I can get 20 developers to play ball). Thanks for the answer and for making me admit defeat and stop trying to make maven work with the project instead of making the project work with maven :).
You are trying to break the maven conventions in many ways. 1. You should not ever have cyclic dependencies, 2. You should do things the maven way instead of resorting to ant-tasks 3. In your global pom you are declaring dual types for the same artifact (jar, test-jar).
Although at first this might not seem to answer your question, you should take a step back and rethink your layout. Integration tests need all the dependencies and are much more demanding than unit tests. So, instead of trying to fit them into the existing projects, create a separate maven project in the same group, that will only host integration tests (under src/java/test, main will be blank) and will have as dependencies all the other projects.

Categories

Resources