9

Project structure

I have a project written in Java 8 and I want to update it to Java 9. So I separated the classes into 2 separate modules. Modules:

  • org.ggp.base with module-info.java in the directory org.ggp.base/src/main/java. Its build was automated with Gradle before I started the update to Java 9. The module uses an abstract class implementation included in pl.edu.prz.klopusz module.
  • pl.edu.prz.klopusz in the directory pl.edu.prz.klopusz/dolar-app/src/main/java. I want to automate its build using Maven. The module requires org.ggp.base module.

The file tree looks like:

.
├── org.ggp.base/
│   ├── build.gradle
│   └── src/
│       └── main/
│           ├── java/
│           │   ├── external/
│           │   │   └── JSON/
│           │   │       ├── JSONArray.java
│           │   │       └── JSONObject.java
│           │   ├── META-INF/
│           │   │   └── MANIFEST.MF
│           │   ├── module-info.java
│           │   └── org/
│           │       └── ggp/
│           │           └── base/
│           │               └── util/
│           │                   ├── statemachine/
│           │                   │   ├── MachineState.java
│           │                   │   └── StateMachine.java
│           │                   └── symbol/
│           └── resources/
│               └── org/
│                   └── ggp/
│                       └── base/
└── pl.edu.prz.klopusz/
    └── dolar-app/
        └── src/
            └── main/
                └── java/
                    ├── module-info.java
                    └── pl/
                        └── edu/
                            └── prz/
                                └── klopusz/
                                    └── utilities/
                                        └── decorators
                                          └──StateMachineDecorator.java

The contents of module-info.java files is the following:

org.ggp.base/src/main/java/module-info.java
module org.ggp.base {
    requires guava;
    requires reflections;
    requires jdk.httpserver;

    uses org.ggp.base.util.statemachine.StateMachine;

    exports org.ggp.base;
}
pl.edu.prz.klopusz/dolar-app/src/main/java/module-info.java
module pl.edu.prz.klopusz {
    requires org.ggp.base;

    provides org.ggp.base.util.statemachine.StateMachine
        with pl.edu.prz.klopusz.utilities.decorators.StateMachineDecorator;
}

Compilation

I try to compile the project, using the following command:

javac -d out \
  --module-source-path org.ggp.base/src/main/java:pl.edu.prz.klopusz/dolar-app/src/main/java \
  $(find org.ggp.base/src/main/java -name *.java) \
  $(find pl.edu.prz.klopusz/dolar-app/src/main/java -name *.java)

Errors

I get the following error:

org.ggp.base/src/main/java/module-info.java:1:

error: module not found on module source path
module org.ggp.base {

And 99 other errors for the classes inside org.ggp.base package, each is like:

org.ggp.base/src/main/java/external/JSON/JSONObject.java:1:

error: not in a module on the module source path
package external.JSON;

or

org.ggp.base/src/main/java/org/ggp/base/validator/OPNFValidator.java:1:

error: not in a module on the module source path
package org.ggp.base.validator;

What I want

I want to get rid of the errors and compile the project. I don't have to preserve the directory structure, but when I put it all together, with 2 module-info.java files, the compiler complainted about multiple modules. I can have it done by IntelliJ IDEA, I don't mind and I tried. But I don't know what is happening behind the scenes, and I don't know how to handle the errors either (Package is empty: org.ggp.base).

Package is empty: org.ggp.base

What I've already found

It was hard to find a documentation about --module-source-path switch in javac command. This site is what I found. It says:

if you arrange the code in your modules such that you put the code for a module in an enclosing directory named for the module, the module source path becomes more like a simple path, as in
--module-source-path Users/Me/MyProject/src
or if it is in multiple projects, use
    --module-source-path 
        /Users/Me/MyProject/src:/Users/Me/MyOtherProject/src

And for Windows use backslashes and semicolons, but I'm using Linux anyway.

There is also a comment to an issue on OpenJDK bugs site, with the same error as mine, but I guess it remains unsolved.

UPDATE

-verbose switch

I added -verbose switch at the end of command. That is a part of what compiler says:

[parsing started SimpleFileObject[/home/sensitive/org.ggp.base/src/main/java/module-info.java]]
[parsing started SimpleFileObject[/home/sensitive/org.ggp.base/src/main/java/org/ggp/base/util/statemachine/MachineState.java]]
[parsing started SimpleFileObject[/home/sensitive/pl.edu.prz.klopusz/dolar-app/src/main/java/module-info.java]]
[parsing started SimpleFileObject[/home/sensitive/pl.edu.prz.klopusz/dolar-app/src/main/java/pl/edu/prz/klopusz/utilities/decorators/StateMachineDecorator.java]]
org.ggp.base/src/main/java/org/ggp/base/util/statemachine/MachineState.java:1: error: not in a module on the module source path
package org.ggp.base.util.statemachine;
^
[loading /modules/jdk.httpserver/module-info.class]
[loading /modules/java.base/module-info.class]
[total 263ms]
100 errors

So, I think this is not a fault of the path in --module-source-path switch (the same behavior happens with *src/main/java pointed out by @StephanHerrmann). It reads all the java sources it should read. There's no problem with sources in the pl.edu.prz.klopusz module. These are the first lines of org.ggp.base.util.statemachine.MachineState:

package org.ggp.base.util.statemachine;

import org.ggp.base.util.gdl.grammar.GdlSentence;

import java.util.HashSet;
import java.util.Set;

public class MachineState {
    //...
}
Omid
  • 5,823
  • 4
  • 41
  • 50
banan3'14
  • 3,810
  • 3
  • 24
  • 47
  • I think `--module-source-path` want to find directories named like the modules at first level. OTOH, if I understand JEP 261 correctly, you could perhaps use a pattern like `*/src/main/java` where `*` would represent the module name. I haven't tried this, though. – Stephan Herrmann Mar 26 '18 at 23:14
  • @StephanHerrmann, it doesn't matter if I use `*/src/main/java` or `org.ggp.base/src/main/java:pl.edu.prz.klopusz/dolar-app/src/main/java`. – banan3'14 Mar 27 '18 at 10:51
  • your directory layout doesn't exactly fit to the `*/src/main/java` pattern, because of the extra `dolar-app` intermediate directory, which prevents matching to the module name. – Stephan Herrmann Mar 27 '18 at 12:45
  • After I removed `dolar-app` folder and spliced `pl.edu.prz.klopusz` and `src`, I used pattern `'./*/src/main/java'`. Neither `*/src/main/java` nor `'*/src/main/java'` nor `org.ggp.base/src/main/java:pl.edu.prz.klopusz/src/main/java` worked. After I used the right pattern, errors disappeared. So I guess you can make an answer out of it and I will accept it. – banan3'14 Mar 28 '18 at 16:41
  • The accepted answer doesn't say what's the exact `javac` command should look like, neither do you. For completeness sake, it is `javac -d out --module-source-path "./*/src/main/java/" $(find . -name "*.java")`, right? – Abhijit Sarkar Nov 01 '18 at 09:52
  • @AbhijitSarkar almost. For some reason, I have to use `$(find org.ggp.base/src/main/java -name *.java) $(find pl.edu.prz.klopusz/src/main/java -name *.java)`, because simple search in current dir `find .` doesn't work. I will add it to the answer https://stackoverflow.com/review/suggested-edits/21296807. – banan3'14 Nov 01 '18 at 11:01
  • I don't understand why the `find` like I showed won't simply work; it has nothing to do with `javac`. I think you're doing something wrong with the `find`. Your edit was rejected for a different reason, I'll post my comment as an answer. – Abhijit Sarkar Nov 01 '18 at 17:45

2 Answers2

19

As per JEP 261 the --module-source-path option (for compilation in "multi-module mode") must point to a directory that holds one subdirectory for each contained module, where the directory name must equal the module name.

To accommodate layouts where sources are not directly contained in the module directory, the option supports patterns where the token * can be used to represent the module name in any part of the path such as in "./*/src/main/java/", which will find the module my.mod1 in ./my.mod1/src/main/java/module-info.java etc.

JEP 261 does not mention any contraints on where in the pattern * may occur, but apparently javac doesn't like patterns starting with *. This may or may not be intentional.

Slightly related, I might add that in a previous discussion I was informed that JEP 261 contains outdated information, but my question whether and where this specification would be maintained after the JEP was completed, produced no answer. The javac manual entry is not the place that gives sufficient details for options like --module-source-path.

Stephan Herrmann
  • 7,963
  • 2
  • 27
  • 38
7

For completeness sake, the complete javac command is as follows:

javac -d out --module-source-path "./*/src/main/java/" $(find . -name "*.java")

Based on the official tutorial from OpenJDK (slightly modified directory structure shown below), and OpenJDK version "11.0.1", the above command javac works for me:

.
├── com.greetings
│   └── src
│       └── main
│           └── java
│               ├── com
│               │   └── greetings
│               │       └── Main.java
│               └── module-info.java
├── org.astro
│   └── src
│       └── main
│           └── java
│               ├── module-info.java
│               └── org
│                   └── astro
│                       └── World.java
├── out
│   ├── classes
│   │   ├── com.greetings
│   │   │   ├── com
│   │   │   │   └── greetings
│   │   │   │       └── Main.class
│   │   │   └── module-info.class
│   │   └── org.astro
│   │       ├── module-info.class
│   │       └── org
│   │           └── astro
│   │               └── World.class
│   └── lib
│       ├── com.greetings.jar
│       └── org.astro@1.0.jar
Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
  • Do you know how to write `javac -d out --module-source-path "./*/src/main/java/" $(find . -name "*.java")` using Windows not Linux/Mac OS ? – invzbl3 Aug 10 '19 at 00:39
  • @invzbl3 I believe powershell might provide a more useful set of command line utilities that mimic the Unix find command. Otherwise, you can certainly install a bash (or other) shell into windows. I think Cygwin is the general/GNU implementation, though I simply use the toolkit and shell provided by the git tools for windows. That bash shell (which I suspect is cygwin anyway) works just fine and has "find" and most of the other tools. Learn bash, you'll never look back :) – Toby Eggitt Jan 06 '20 at 17:34
  • 1
    It's an old question but just in case anyone stumbles upon this: You should be able to do in Windows cmd: dir /s /b *.java > mySourceFiles.txt & javac -d out --module-source-path ".\*\src\main\java\" @sourceFiles.txt &del mySourceFiles.txt – markus Mar 20 '21 at 08:10