I'm in the process of trying to migrate a large code base from Java 8 to modular (JPMS) Java 11, and I'm encountering significant pain and finding consistent advice on project structure and how to use module-info files for actual production projects is hard.
The project in question follows the conventional gradle structure for source and test files:
src/main/java/org/abc/...
src/test/java/org/abc/...
I have a module-info.java
file in src/main/java/module-info.java
, is this the right location? The quick-start for modular java and this seems to contradict this; however other resources do it the way I did.
When trying to run a unit test that looks like this:
@RunWith(MockitoJUnitRunner.class)
public class ABCTest {
@Mock
public SomeClass mock;
...
}
I get:
Unable to make field public SomeClass mock accessible: module org.abc does not "exports org.abc"
to module org.mockito
which indicates that I need to add exports org.abc to org.mockito
in my module-info.java
file but this seems clunky and verbose having to do this for all sub packages in my test tree which aren't even part of the module, and it seems like the wrong place to do it since the tests shouldn't be exported with the release jar.
The seemingly most up to date guidance I could find suggests adding a module-info.[test|java]
file to my test tree. What is the difference between these two files (.java
and .test
)? I couldn't find any hits on Google explaining this. Also I'm supposedly going to have to copy content from the main/java/module-info.java
to the test/java/module-info.test
and keep them in sync? This seems tedious.
I also understand that gradle doesn't have native support for modular java yet and one must rely on plugins for this, what are the "defacto" plugins that one should use?
I'm confused by the information available, it seems contradicting, very low level or not applicable when using gradle. Could some one please provide an example project with conventional source layout using mockito, junit, gradle and modular java (version 9+, preferably 11)?
Gradle doesn't have built-in out-of-the-box support for JPMS, as you've found out.
Gradle's JPMS policy can be summed up by this comment from one of the Gradle Core Devs...
„...There's no short-term plan to work on jigsaw support, so please don't hold your breath...“
I've developed a plugin that JPMS-enables Gradle and Eclipse though.
Here is a simple test project that is implemented with Gradle, JPMS, JavaFX 13, JUnit 4 and Mockito. The mrJar JPMS development-enabling plugin is what ties it all together.
You could run the :test
task or the :run
task of that test project from the command line with just raw Gradle. Or follow these steps to use the test project in Eclipse...
Import the project into Eclipse
Execute the :eclipse
task in Eclipse's Gradle Tasks
view
Open the project's properties dialog
Java Build Path
properties tabNot all modules could be found. Click Apply to synchronize
)Apply
button to synchronize the module pathExecute the :test
task
Run As Gradle Test
from the Package Explorer
context menu:check
task is another option that has the same Eclipse Modulefication effect as :eclipse
, :test
and Run As Gradle Test
The recording might help clarify the steps you need to follow to run the unit tests and the JavaFX application in Eclipse.
Hopefully you will find the attached test project pretty straightforward. But if you get stuck, there are more detailed usage instructions and screen recordings in this Gradle Communnity Forum thread.
I'm also happy to engage with you in that forum thread and clarify anything that might not be obvious in either the video or any of the steps.
Also, here's a github repository with a fully JPMS-enabled copy of your project @EmilyL...