I'm trying to migrate some legacy applications to the new Java 9 module system, to strengthen its encapsulation.
I'm starting from the outside-in, with the assumption that classes on the periphery will have the least external dependencies.
As you'd expect, I've declared a very open module to start with:
module com.example.user {
exports com.example.user;
}
This instantly breaks the entire project (inside all classes), when suddenly every import for an external dependency no longer resolves (causing over 1k Java problems):
The import com.otherexample cannot be resolved
The import org.springframework cannot be resolved
etc.
Local packages in the same project com.example.price
still work - as do java.util
etc.
All of the external dependencies are (were) managed with Maven. In the (Eclipse project) build path, I can still see them as "Classpath" dependencies - but only the JRE system libraries in the "Modulepath".
Can the two concepts co-exist? Currently it seems by having a single module-info.java
anywhere in the project, all classpath dependencies stop working?
I did read about using automatic modules, which seemed to imply you could use legacy / non-modular jars by including them in your modulepath, then referring to them by their filename. They use the example:
module com.foo.myapp {
requires guava; // guava not yet modularised, so use the filename
}
I couldn't find much other info, but this appears to match the convention Eclipse uses when it auto-generates a module-info.java for example:
spring-core-4.3.8.RELEASE.jar
becomes:
requires spring.core;
However, this still results in a Java error reported by Eclipse:
spring.core cannot be resolved to a module
Maven reports:
[ERROR] module-info.java:[39,16] error: module not found: spring.core
...and every class in the project with an external dependency is still broken.
Thanks to Robert Scholte for pointing out the updated maven-compiler-plugin 3.7.0 (I had been using 3.6.1), this really cleaned up the compile goal command-line output (with Java 9 specifics), to help me get to the route of the problem. This narrowed down the reported errors from every requires
giving me the error to:
[WARNING] ********************************************************************************************************************
[WARNING] * Required filename-based automodules detected. Please don't publish this project to a public artifact repository! *
[WARNING] ********************************************************************************************************************
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 56 source files to ./target/classes
~~~ snip ~~~
[ERROR] module-info.java error: module not found: foo.bar
Matching Eclipse:
foo.bar cannot be resolved to a module
The errors appearing for just six automatic modules / libraries (jar) - rather than all (24) of them. Great.
In my POM, I'd split the output of source directories, to their own output directories (target/classes
). However, as the module-info.java
referred to dependencies (such as requires spring.core;
) that are not used / referenced by the code (classes) in that folder - it couldn't resolve them.
Why? Basic Maven dependency management - I'd scoped those libraries outside of the default goal (to match the output directories split).
A fairly basic outcome - but I'd imagine I will not be the only person to encounter this as Java begins to encroach on some aspects of dependency management that overlap with the traditional use of Maven.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With