Java 9 Modules and JUnit 4 - java

Eclipse oxygen; windows 7; JDK 9 final from 9, 21; JUnit 4.12 and an existing application. As starting point the application can be compiled, executed and all JUnit Tests shows green. Now we use eclipse to generate the file module-info.java. The outcome looks like:
module ch.commcity.topsort {
exports ch.commcity.topsort;
requires junit;
}
But with the error: junit cannot be resolved to module.
The question is: How to tell the file that junit does not define any module and it should be run in compatibility mode?

How to tell the file that junit does not define any module and it should be run in compatibility mode?
Your question seems to be based on several misconceptions:
You can not tell module-info.java whether JUnit defines a module or not. If a module says it requires another module then the compiler expects that module to be present - no way around that.
Whether JUnit 4 comes as a module or not is not overly important - as long as you place it on the module path, it will end up being treated as a module (possibly as an automatic one).
There is no "compatibility mode". You can continue to write code as you did before the module system (almost), but once you're creating module declarations you need to play by its rules.
I recommend to give the outstanding State of the Module System a thorough read and then ask yourself what exactly you are trying to accomplish. Are you really trying to create a module that depends on JUnit? Or was that just accidental because you use its API for testing. If the latter, you should not depend on it - instead your IDE / build tool needs to figure out how to compile and run your tests.
Expansion on "a module that depends on JUnit"
The module system does not classify dependencies as "compile" or "test" - if a module requires another module, it has to be present, always. That means a module that requires junit would force the presence of JUnit. Unless the module provides testing-related features, that is most certainly wrong.
In other words, requires junit is akin to adding JUnit to a project's POM, using the compile scope.

First, please update your Java 9 support for Eclipse Oxygen or use the latest available release candidate build for Eclipse 4.7.1a (to be released on October 11, 2017).
To add a library or a container to the modulepath of a Java 9 project in Eclipse, open the project's Java Build Path dialog. On the Libraries tab, select the node Modulepath and add your library to it. Make sure to first remove that library from the Classpath node if it is already present there.
As mentioned by others, in your case, the JUnit libraries will be considered as automatic modules.

How to tell the file that junit does not define any module and it should be run in compatibility mode?
Since the module junit as generated in the module-info would be an automatic module converted from its artifact. You need to make sure that the jar for Junit junit:junit:4.12 is available on the modulepath of your project and the module would be resolved itself.
In order to make sure of the above, you can check dependencies of your project/module as configured in the IDE to include junit:4.12:jar.

Related

Java Gradle Missing libraries Modue that exists or have been imported - > Task :compileJava

So I have been facing these issues in so many JavaFX Gradle based projects in Intelli J Idea IDE. This has pushed me to the point where I had to manually download library files and make them part of my projects as a workaround.
The gradle projects I have they keeping failing when ever i run the > Task :compileJava in the IDE, for example in this particular that made me create the issue is that i have successfully imported the socket io lib from maven implementation 'io.socket:socket.io-client:2.0.1' , i have managed to import it and write a bit of sample code for it and i have added
requires engine.io.client;
requires socket.io.client;
in the module info file . So when its time to run this fails stating that
error: module not found: socket.io.client
requires socket.io.client;
error: module not found: engine.io.client
requires engine.io.client;
I have tried on JDK 13,16,17 to see if I am missing something but keeps on failing to run , so I have noticed now as a trend in my previous JavaFX project in which i managed to get away with.
So if there is anyone who understands what's wrong with Gradle set up please help.
This answer outlines an approach rather than a concrete solution.
socket.io.client and engine.io.client are not module names.
The socket.io-client library is not Java platform modularized (as far as I can tell), so it will be an automatic module.
The name of the module will be derived from the jar name. I don't know the exact translation as the jar name has . and - characters which may be remapped (or not) to make the module name valid. Try first the exact jar file name. There can be only one module per jar.
Additionally to requiring the right name, the jar needs to be on the module path. Maven will do this automatically for automatic modules, Gradle will not. I am not a Gradle expert, so will not provide advice on how to do that for Gradle.
If you use the right name in module-info and ensure the jar is on the module path, then it may work, or it may be incompatible with the Java module system in ways that are not easily fixable by you (i.e. the broken module must be fixed by the module maintainers).
You can raise an issue for the library maintainer for them to create module-info.java files for the modules and update their documentation on how to use their libraries in a Java module environment.
If the library you are trying to use is incompatible with the Java module system when used as a module, then you could try making your project non-modular by deleting module-info.java from your project and adding appropriate command-line switches. To understand how to do this, refer to documentation on non-modular projects at openjfx.io.

How to depend on java validation api /hibernate modules in java with gradle as build tool?

I have similar question as here. However that question does not mention what build tool he is using and I assume that he is using maven as I didn't have problems with maven when using java 9 modules with it previously.
I am using the hibernate validator and I want to use java 9 modules, so I added a module-info file to the package of the module where I am depending on the validator api (the classes I am using are Validator, ValidatiorFactory , ... from packages like javax.validation)
I searched for these classes and found that they reside in this jar in my project dependencies: validation-api-2.0.1.Final.jar, the classes I am using are inside package validation.
I used the command jar --file=/path-to-the-jar-on-my-pc/validation-api-2.0.1.Final.jar --describe-module in the terminal and got the names of the modules exported from that jar:
No module descriptor found. Derived automatic module.
java.validation#2.0.1.Final automatic
requires java.base mandated
contains javax.validation
contains javax.validation.bootstrap
contains javax.validation.constraints
contains javax.validation.constraintvalidation
contains javax.validation.executable
contains javax.validation.groups
contains javax.validation.metadata
contains javax.validation.spi
contains javax.validation.valueextraction
So now when I put in my module-info file for example requires javax.validation the IDE complains that module is not found . I even added the dependency manually in the project structure (pressing ctrl+shift+alt+s to access it in intellij) where I added it from the path where it is stored in my machine but still same result.
I also tried the help tool from intellij and I found that it added requires java.validation; to my module-info and not requires javax.validation;, but anyway neither of them work.
I searched in pom.xml of that module and found this element <Automatic-Module-Name>java.validation</Automatic-Module-Name>, so now I am almost sure that gradle is causing the problem but I am no expert in gradle and how building tools work, so how can I solve this with staying at using gradle as build tool?
Gradle didn't add proper support for the Java Platform Module System until version 6.4. However, you have to explicitly configure Gradle to work with modules.
// build.gradle
java {
modularity.inferModulePath = true
}
Though if I'm not mistaken, inferModulePath is true by default as of Gradle 7.0.
For more information regarding Java modules and Gradle see https://docs.gradle.org/current/samples/sample_java_modules_multi_project.html
I had the same issue. Changing javax.validation to jakarta.validation resolved it.
build.gradle.kts:
implementation("jakarta.validation:jakarta.validation-api:3.0.1")
module-info.java:
requires jakarta.validation;
I am using gradle java modularity plugin
https://plugins.gradle.org/plugin/org.javamodularity.moduleplugin
here is what I set on my build.gradle.kts:
java {
modularity.inferModulePath.set(false)
}
application {
// Define the main class for the application.
mainModule.set("modules.demo.gradle.consumer")
mainClass.set("com.demo.gradle.consumer.Consumer")
}
I know modularity.inferModulePath.set(false) contradicts what Slaw wrote, but it is necessary if you use the plugin. See documentation
https://github.com/java9-modularity/gradle-modules-plugin

Test dependencies for white-box unit testing Java modules with Maven and Eclipse

I'm trying to convert existing Java projects with Maven and Eclipse into Java 9+ modules. The projects have unit tests and the unit tests have test dependencies. I need the test dependencies to be available in the test code, but I don't want them exposed to the rest of the world in the published modules.
I think Testing in the Modular World describes the Maven solutions well. In summary one solution is to create one module-info.java in the main source folder and another in the testing folder. The file in the main folder has the real dependencies. The file in the test folder adds the test dependencies.
The solution works well in Maven and I can build and run tests from the command line. However, when I import the project into Eclipse as a Maven project it balks. Eclipse complains that "build path contains duplicate entry module-info" and refuses to build the project at all.
Using the other suggested solution in the article with a module-info.test containing --add-reads has no effect and the build fails in both Maven and Eclipse as the tests can't find their dependencies.
To make matters more complex I need to import the test dependencies from Maven, but I also need to import standard Java modules that are not used by the main code. For example one unit test relies on the built-in web server provided by java.httpserver and as it is part of the JDK any magic done on the test dependencies will miss it.
Is there a solution for this that works in Maven and Eclipse (latest versions)? It sounds like a very common problem and the module system has been around for a while by now.
Note that I really don't want to change the project settings in Eclipse. I can fiddle with plugins in the pom files, but adding a manual routine where all developers need to edit the generated/imported project settings manually is not an option.
EDIT:
There is an open Eclipse bug report for this, see Eclipse bug 536847. It seems it is not supported yet, but perhaps someone can suggest a workaround?
The Eclipse emulation of the multiple-classpaths-per-project feature in Maven has been broken for very long. The symptom is that you can have non-test classes using test dependencies just fine.
Essentially Eclipse just considers each project to have a single classpath instead of two parallel ones which causes things like this to ... not do the right thing.
I would suggest splitting each of the problematic projects into two. One with the actual sources and one with the test sources (depending on the actual source). This will avoid the Eclipse bug and also allow you to use the newest version of Java for your tests while having your application built for an older version of Java.

Eclipse + m2e + junit5 - already possible?

Tried to get Eclipse 2018-09 + Patch with Java 11 support, m2e, and junit5 working together.
As recommended in junit5-modular-world example I introduced a second module-info.java under test/java.
The reaction of Eclipse was astonishing to me:
I could not save that file after changing it.
It was saved only by closing Eclipse at all.
However, re-opening, bewildered Eclipse. It cannot show any details of the project hosting multiple module-info.java, just the project name.
Probably Eclipse identifies one project with one Java module, while mvn test compiles and executes obviously a different module than the one created by mvn install.
Experienced a lot of options I can think of. Currently I had to give up and fall back to junit 4.12.
Do you know of a better solution?
A secondary module-info.java in the test source folder is not supported by Eclipse at this time (but its behaviour if you try to do that should probably be improved).
For now, you probably won't need it at all:
Maven puts dependencies that are mentioned in the module-info.java on the module path, all others (e.g. test-only dependencies like junit) on the class path, so they become part of the unnamed module. When tests are compiled, command line options are added, so the test code that is treated as part of the module in the main source folder still can read the unnamed module (by adding --add-reads modulename=ALL-UNNAMED), so junit is visible to the test code.
Eclipse Photon and later also supports this behaviour.
Some background regarding the secondary test module-info.java: maven-compiler-plugin supports this since version 3.8 (see https://www.mail-archive.com/announce#maven.apache.org/msg00866.html, implemented in issue https://issues.apache.org/jira/browse/MCOMPILER-341), but I'm not aware that a matching maven-surefire-plugin has been released, so I think you currently wouldn't be able to run these kinds of tests with maven.
Implementing support for a secondary test module-info.java in Eclipse may be possible, as long as it is a strict superset of of the primary module-info.java in the main source folder, or maybe as long as they specify the same module and their contents would get merged as in the "pro" build tool https://github.com/forax/pro. But nobody has worked on that yet.
What will probably be never supported in Eclipse, is to have a secondary test module-info.java that specifies a different module as Eclipse has the assumption that one java project belongs to only one module. But that shouldn't matter, as these tests can only use public and exported code of the main sources, so they can simply be put into their own maven module.

Ant/JUnit - How to assert package dependencies/non-dependencies?

Is there a code analysis tool for Java for asserting package dependencies/non-dependencies?
I have a project where dependencies have crept in between packages that should not know about each other - in particular back-dependencies, which should have been one way.
I'd like to specify which pairs of packages (in which direction) are allowed to be dependent. Alternatively, specifying packages that are NOT allowed to depend on each other - or not both ways - would help. Ideally this would be something that could run as part of an Ant build and/or JUnit run and fail the build if new dependencies, in violation of the rules, are introduced. We'd then add this to our CI process.
It would also be useful to be able to specify dependencies at the level of groups of packages (for example, all packages and sub-packages in 'web' CAN depend on any package in 'api' or its sub-packages).
Some specifics in case relevant, for my particular project:
The Java version is 1.7
The build process is based around Ant (can upgrade to latest version if needed)
Testing is with JUnit (can upgrade to latest version if needed)
You need a solution like Jdepend. There is an example on how to use with junit

Categories