Java module system and AspectJ - java

I have 2 libraries, which I have migrated to Java 10 and used module system.
First thing which makes me worry is that I had a lot of errors like:
Error:java: the unnamed module reads package org.aspectj.internal.lang.reflect from both aspectjrt and org.aspectj.weaver. To fix that, I have added requires org.aspectj.weaver; to module info. Actually I had to put there lot of other things which I don't use, but e.g. Spring uses. Only then I was able to compile it.
So in the end, my module-info for the first library looks like this:
module my.lib1 {
requires spring.context;
requires spring.core;
requires spring.context.support;
requires spring.beans;
requires org.aspectj.weaver;
requires slf4j.api;
requires metrics.core;
requires com.fasterxml.jackson.databind;
requires java.validation;
requires org.hibernate.validator;
requires javax.el;
exports my.lib1;
}
For the second library I also had to add a lot of libs that are used by dependencies, not me:
module my.lib2 {
requires org.hibernate.orm.core;
requires java.sql;
requires java.persistence;
requires spring.context;
requires spring.tx;
requires spring.orm;
requires spring.data.jpa;
requires spring.beans;
requires HikariCP;
requires metrics.core;
requires slf4j.api;
requires spring.core;
exports my.lib2;
}
Both libs are compiling now. I put them in my local mvn repo and started third project which depends on this two.
module my.project {
requires my.lib1;
requires my.lib2;
}
And now I got the same error... Error:java: the unnamed module reads package org.aspectj.internal.lang.reflect from both aspectjrt and org.aspectj.weaver, but this time, adding requires org.aspectj.weaver; doesn't help. I have noticed when I put only one of the libs in the module (not both together, but one lib1 or lib2) it works.
Is it normal that I have to put different libs in my module-info which are used not by my but by other dependencies? (e.g. shouldn't it be Spring's responsibility to require aspectj?).
And the most important thing: how do I fix the problem with my project which depends on my two libs?

I have noticed when I put only one of the libs in the module (not both together, but one lib1 or lib2) it works.
Using the module system, a package may only be offered by a single module in your current module graph. This is one of the main reasons for the introduction of the module system: avoidance of ambiguous dependencies (as they occur on the classic class path; called split packages). And that's why it works with only one of your modules.
In your case, both modules aspectjrt and org.aspectj.weaver are offering the same package org.aspectj.internal.lang.reflect and that's where the error message comes from (the unnamed module reads package org.aspectj.internal.lang.reflect from both aspectjrt and org.aspectj.weaver).
how do I fix the problem with my project which depends on my two libs?
like Andy Guibert wrote to this topic, you could:
unsplit the package
bundle them in a single package
hope that third party modules become named modules in the future.
AspectJ has been ported to the module system. Check the newest version, if you don't use it (requires org.aspectj.runtime, requires org.aspectj.weaver)?
Additionally, here you can find some more information about the module system.

Related

Not finding automatic modules when compiling Java Application

I have a large multi module (100s) Java project and have been experimenting with adopting java module support. This is using Java 17 (temurin), gradle 7.6, and IntelliJ 2022.3.
I have hit a couple of stubborn errors with java modules where the module cannot be found.
I have one project which has some java code that uses plexus ie:
import org.codehaus.plexus.util.Base64;
...
byte[] encodedAuthorizationString = Base64.encodeBase64(authorizationString.getBytes(StandardCharsets.US_ASCII));
It has a gradle dependency
implementation 'org.codehaus.plexus:plexus-utils'
This has a version constraint in our main build.gradle (just salient lines included):
plexusVersion = '3.5.0'
implementation("org.codehaus.plexus:plexus-utils:${plexusVersion}")
Prior to adding module support this is working fine.
Now, with a module-info.java:
module egeria.open.metadata.implementation.adapters.open.connectors.rest.client.connectors.spring.rest.client.connector.main {
requires egeria.open.metadata.implementation.adapters.authentication.plugins.http.helper.main;
requires egeria.open.metadata.implementation.adapters.open.connectors.rest.client.connectors.rest.client.connectors.api.main;
//requires egeria.open.metadata.implementation.adapters.open.connectors.rest.client.connectors.rest.client.factory.main;
requires egeria.open.metadata.implementation.frameworks.open.connector.framework.main;
requires plexus.utils;
requires org.slf4j;
requires spring.core;
requires spring.web;
exports org.odpi.openmetadata.adapters.connectors.restclients.spring;
}
I am getting a compile error
Task ':open-metadata-implementation:adapters:open-connectors:rest-client-connectors:spring-rest-client-connector:compileJava' is not up-to-date because:
Task has failed previously.
The input changes require a full rebuild for incremental task ':open-metadata-implementation:adapters:open-connectors:rest-client-connectors:spring-rest-client-connector:compileJava'.
Full recompilation is required because no incremental change information is available. This is usually caused by clean builds or changing compiler arguments.
Compiling with toolchain '/Library/Java/JavaVirtualMachines/temurin-19.jdk/Contents/Home'.
Compiling with JDK Java compiler API.
/Users/jonesn/IdeaProjects/egeria/v4/open-metadata-implementation/adapters/open-connectors/rest-client-connectors/spring-rest-client-connector/src/main/java/module-info.java:6: error: module not found: plexus.utils
requires plexus.utils;
^
1 error
This is despite the fact, that having downloaded the jar file, the automatic module name looks to be what I am using ie:
jar --file=/Users/jonesn/Downloads/plexus-utils-3.5.0.jar --describe-module
No module descriptor found. Derived automatic module.
plexus.utils#3.5.0 automatic
requires java.base mandated
contains org.codehaus.plexus.util
contains org.codehaus.plexus.util.cli
contains org.codehaus.plexus.util.cli.shell
contains org.codehaus.plexus.util.dag
contains org.codehaus.plexus.util.introspection
contains org.codehaus.plexus.util.io
contains org.codehaus.plexus.util.reflection
contains org.codehaus.plexus.util.xml
contains org.codehaus.plexus.util.xml.pull
I am seeing the same error with kafka-clients
For most other code, including those libraries without full module support, all is good....
tried various compilers, such as openjdk 17 & temurin 19
built at cli & within IntelliJ
I was expecting this module to resolve ok
I have also reviewed Java 9 automatic modules not found but note that other automatic modules (including org.slf4j) are working just fine
I should add that I could refactor this code to use java.util.Base64 (probably makes sense)... but I'm still confused as to why the module error, which I also see in another project with 'kafka.clients'

How can I put javafaker in module-info.java

I am making a JavaFX application, and want to use javafaker (https://github.com/DiUS/java-faker) to create some testdata while I am developing the application. The problem is that when I import the package: import com.github.javafaker.Faker;, the compiler complains and warns me with:
The type com.github.javafaker.Faker is not accessible Java(16778666).
So far I've figured out that it's because I don't have javafaker required in module-info.java. If i delete module-info.java the problem goes away, however, I am not able to run the application. I get the error:
Error: JavaFX runtime components are missing, and are required to run this application.
I suppose this is because module-info.java is gone.
I have tried requiring javafaker like this in module-info.java:
open module my_project {
requires javafx.base;
requires javafx.controls;
requires javafx.fxml;
requires javafx.graphics;
requires com.github.javafaker;
}
However, I get the error:
com.github.javafaker cannot be resolved to a module Java(8389908).
What is the proper way to require such a package? I have tried searching for solutions, but I haven't been able to convert the solutions to something I can use for this problem.
I am using maven, and I have added javafaker as a dependency.

IntelliJ ResolutionException on Java modules - contains package/exports package

I wrote a Java module a.b.c and another module d.e.f that requires a.b.c. I'm using IntelliJ.
First module's module-info.java:
module a.b.c {
exports a.b.c;
requires org.jfree.jfreechart;
requires commons.cli;
requires java.desktop;
requires java.net.http;
}
Second module's module-info.java:
module d.e.f {
requires a.b.c;
requires org.json;
}
Both modules compile. When I run d.e.f, I get the following error.
java.lang.module.ResolutionException: Module a.b.c contains package org.jfree.chart.ui, module org.jfree.jfreechart exports package org.jfree.chart.ui to a.b.c
These modules aren't split as there is no redundant package between them.
What does this message mean?
How do I resolve it?
I received the ResolutionException error because my IntelliJ project was not set up correctly. The best guidance I found was at Java 9 Modules with IntelliJ IDE Quick Start. Both modules now run without any compile- or run-time errors.

How to fix cyclic dependency between java modules?

I'm refactoring the code so it uses modules . The problem I'm facing is, I got cyclic dependency between modules: convertersapp, validatorsapp and modelapp. There are 6 modules namely:
1. convertersapp
2. exceptionsapp
3. mainapp
4. modelapp
5. serviceapp
6. validatorapp
My current approach - module-info. java files for every modules are:
1. convertersapp: module convertersapp {
requires modelapp;
requires gson;
requires exceptionspp;
requires validatorapp;
exports converters.others to serviceapp;
exports converters.json to modelapp;
}
2. exceptionsapp: module exceptionspp {
exports exceptions to convertersapp, mainapp,serviceapp, modelapp;
}
3. mainapp: module mainapp {
requires serviceapp;
requires exceptionspp;
requires modelapp;
}
4. modelapp: module modelapp {
exports model to mainapp, validatorapp,convertersapp, serviceapp;
exports model.sorting to mainapp,serviceapp;
requires gson;
requires exceptionspp;
requires convertersapp;
}
5. servicapp: module serviceapp {
exports service to mainapp;
requires modelapp;
requires exceptionspp;
requires convertersapp;
}
6. validatorapp:
module validatorapp {
exports validator to convertersapp;
requires modelapp;
}
A cyclic dependency hierarchy should be avoided because it is difficult to understand and it is furthermore unclear in which order the modules should be build (A before B before C before A ...).
Common strategies:
Merge all three modules to one
Build a common utility module that is used by the others, but which itself does not use others.
Move some classes to avoid the cyclicity.
A corner case, nevertheless worth to look for:
Because I was lazy, I copied the module-info.java file from the 'parent' module to the child, and just added the dependency to that 'parent', ending up with a module info file in the 'child' as below:
module com.pany.parent
{
requires transitive com.pany.parent;
}
Gradle just complained about a cyclic dependency involving the module com.pany.parent …
Of course this was alone my fault, but after several hours working on the migration to Jigsaw, you sometimes don't see the forest because of so many trees …

Java 9 exports cycles [duplicate]

This is the module declaration of the java.rmi module:
module java.rmi {
requires java.base;
requires java.logging;
exports java.rmi.activation;
exports com.sun.rmi.rmid to java.base; // <-- cycle
...
}
So, there is a cyclic dependency between java.rmi and java.base, right? Are cycles allowed between platform modules?
The module system forbids statically declaring cycles with requires clauses. This is true for platform and application modules and the example you give does not violate that rule.
Requires clauses are just one source for readability edges in the module graph, though. Others are command line flags, reflection, requires transitive, and I'm sure there are more. Adding all these may result in cycles in the module graph and that is not forbidden.
In your concrete example the cycle is only created once java.base reads java.rmi, which could happen if it uses reflection on classes in com.sun.rmi.rmid.

Categories

Resources