Unable to derive module descriptor for auto generated module names in Java 9?
Asked Answered
K

2

25

My project depends on Netty Epoll transport. Here is dependency:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-transport-native-epoll</artifactId>
    <version>${netty.version}</version>
    <classifier>${epoll.os}</classifier>
</dependency>

The auto-generated module name for this dependency is:

netty.transport.native.epoll

And as the native keyword is reserved in Java 9 I can't add this module as a dependency to my project:

module core {
    requires netty.transport.native.epoll;
}

Due to:

module not found: netty.transport.<error>

Additionally the jar tool --describe-module reports the following:

Unable to derive module descriptor for: netty-transport-native-epoll-4.1.17.Final-SNAPSHOT-linux-x86‌_64.jar netty.transport.native.epoll: Invalid module name: 'native' is not a Java identifier

Are there any workarounds? (except "release correct netty artifact", of course).

EDIT:

As the quick fix for maintainers - you can add next line to build:

<manifestEntries>
   <Automatic-Module-Name>netty.transport.epoll</Automatic-Module-Name>
</manifestEntries>
Kassia answered 30/9, 2017 at 9:17 Comment(0)
L
12

The solution to this seems to be:-

  • A way possible to uninterruptedly using the same artifact name with a new(different) module name could be by packaging META-INF/MANIFEST.MF of the artifact with an attribute Automatic-Module-Name which governs the name of the module to be used by the module descriptor when converted as an automatic module.

OR

  • Artifact owners can add module declarations using module-info.java to their JAR. (this could result in a slow bottom-up migration)

Since the module declaration defined in the specs as:

A module declaration introduces a module name that can be used in other module declarations to express relationships between modules. A module name consists of one or more Java identifiers (§3.8) separated by "." tokens.


Intersetingly the declarations suggests -

In some cases, the Internet domain name may not be a valid package name. Here are some suggested conventions for dealing with these situations:

  • If the domain name contains a hyphen, or any other special character not allowed in an identifier (§3.8), convert it into an underscore.

  • If any of the resulting package name components are keywords (§3.9), append an underscore to them.

  • If any of the resulting package name components start with a digit, or any other character that is not allowed as an initial character of an identifier, have an underscore prefixed to the component.

But keep in mind as you do so that Underscore is a keyword in Java9

enter image description here

int _;  // is would throw an error on javac based out of JDK9
int _native; // works fine
Lavonlavona answered 30/9, 2017 at 10:21 Comment(4)
Thanks man. Added <Automatic-Module-Name>netty.transport.epoll</Automatic-Module-Name> during netty build and it works.Kassia
Both of the two methods require modifying the dependent package(e.g. netty in the question). Is there a way to specify the module name without modifying the package?Chimere
@Chimere I have read and heard about something like moditect plugin on Maven. But honestly, I haven't given it a try. I had really considered reaching out to the authors or trying to submit fixes as the best approach to deal with it. Of course, it doesn't solve things immediately but avoids multiple iterations in the direction of making things work for one's specific use case.Lavonlavona
@Chimere I totally agree with you. This doesn't truly resolve the problem. As usual when we develope a project, I seldom would build the depdent packages ourselves. So I thumbs down this answerKochi
L
1

From now on you can also use this small Maven plugin to automatically modify the manifest file in a Scala jar in your local Maven repo: https://github.com/makingthematrix/scala-suffix

Under the link you will find the overview of the whole issue and what you need to add to you pom.xml, but I was asked to also explain here, so here it goes:

As it was mentioned already, Java does not recognize suffixes in modules names like _2.13 as version numbers and treat them as integral parts of modules names. So, when your project tries to use a class from the Scala dependency, it will look for your.scala.dependency.2.13 instead of just your.scala.dependency, it will fail to do it, and it will crash.

To fix this on your side (i.e. without any action from the library's creator) add this to the <plugins> section of your pom.xml:

<plugin>
  <groupId>io.github.makingthematrix</groupId>
  <artifactId>scala-suffix-maven-plugin</artifactId>
  <version>0.1.0</version>
  <configuration>
    <libraries>
      <param>your-scala-dependency</param>
    </libraries>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>suffix</goal>
      </goals>
    </execution>
  </executions>
</plugin>

where your-scala-dependency is a name of your Scala dependency without the version suffix (if there are more than one, just add them with more <param> tags). This should be the same as artifactId in your <dependency> section.

The plugin modifies the dependency's JAR file in your local Maven repository. It opens the jar, reads META-INF/MANIFEST.MF and adds to it a line:

Automatic-Module-Name: your-scala-dependency

If the property Automatic-Module-Name already exists, the plugin does nothing - we assume that in that case the dependency should already work. This prevents the plugin from modifying the same JAR file more than once.

Loosejointed answered 5/5, 2021 at 8:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.