Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add module-info for java9+ #566

Closed
lanthale opened this issue Jan 25, 2022 · 11 comments · Fixed by #621 · May be fixed by #620
Closed

Add module-info for java9+ #566

lanthale opened this issue Jan 25, 2022 · 11 comments · Fixed by #621 · May be fixed by #620

Comments

@lanthale
Copy link

Please can you add a module-info so that the lib is also usable with java 9+ ? If it needs to be compatible with java 8 than a multi-release lib would be an option.

@drewnoakes
Copy link
Owner

How is the library not usable with Java 9+?

Can you, or someone else, provide some more guidance here please?

@lanthale
Copy link
Author

lanthale commented Jan 26, 2022

It is usable on the classpath. But if you use the modulepath than you need in your lib a file “module-info” where you express which classes are exposed to the other modules. If this is not present jlink will not work because jlink cannot use automatic modules.

Adding this during compile time is easy. Adding afterwards is difficult because you must than use a tool such as moditect. And you can add it in a way that java 8 is not influenced during build.

Is java 8 a requirement ?

If you need I can create a pull request with the module-info and the changed pom.xml ?

@berndmichaely
Copy link

Unfortunately, there is a bit more involved into making the library modular than just adding a module-info.java file…

First of all, it is desirable to have a modular library for reasons, including:

  • Java9+ has its runtime library modularized, which (optionally) offers the ability to deploy only the JRE modules the application needs, thereby reducing the size of the resulting output
  • modules can not overlap in packages, which results in a speed advantage in class localization and loading

For this to work, it is necessary to use explicit modules only, that is modules, which explicitly declare their own requirements in a module descriptor (a module-info.class file).

Otherwise, if automatic ('just' named) modules or the unnamed module (containing the classpath) are involved, the compiler can not automatically deduce the needed modules. In this case, there will be an implicit dependency to the java.se aggregator module which contains the whole JavaSE.

Note, that all modules must have module descriptors, including third party dependencies, e.g. in this case the xmpcore lib (which is not modularized, I think? If so, one would need to provide a modularized version of this lib, too…).

@lanthale
Copy link
Author

To modularize the dependencies it is possible to use moditect. But you are right that the change is bigger than someone thinks of and means that the lib cannot be compiled longer with java8. I do not know if that is a problem.

@drewnoakes
Copy link
Owner

Thank you all for your input here. There seem to be two barriers to this:

  1. Adobe's xmp-core library must be made modular in this way
  2. Java 8 support must be dropped

Packaging Adobe's package ourselves seems like not such a great idea.

We currently support Java 1.6 IIRC.

How are modules packaged and deployed? Does this still use Maven tooling and hosting?

@Nadahar
Copy link
Contributor

Nadahar commented Jan 31, 2022

Dropping Java 8 support is very premature in my opinion. There are still lots of things that have no replacement after Java 9 was "nerfed", so I would expect that a lot of software will have to stay with Java 8 for years to come. Have libraries started to ditch Java 8 support? It's OK for an application to do it if it doesn't need any of the things that were removed, but libraries would narrow which projects that could use them considerably.

If all this achieves is to save some space for the runtime, it's hard for me to understand how it could be something to consider at all. I get that embedded systems might benefit substantially, but a Java installation isn't really a considerable "burden" on a computer these days.

@berndmichaely
Copy link

Indeed (and correct me, if I'm wrong) it basically remains as a problem to the end user to use third party modules as explicit modules, if desired. To compile the metadata library itself as a module, it should be sufficient to load the xmp-core module as automatic module through the module path (not the class path), with requires xmpcore added to the module-info.

@tsmock
Copy link
Contributor

tsmock commented Jul 6, 2022

As an alternative, the attribute Automatic-Module-Name could be added (see https://docs.oracle.com/javase/9/docs/specs/jar/jar.html#Modular ). The primary advantage is that downstream users can use requires com.drew.imaging instead of requires metadata-extractor (which can change -- it is generally recommended to use reverse-dns for module names to avoid conflicts). This does not require xmpcore to do anything (although they should still add an Automatic-Module-Name to their metadata).

It does not allow some of the other advantages of the module system (like specifying what is actually usable outside of the module).

If a module-info.java file is desired, it is possible to compile everything once with Java 9+, then recompile everything except module-info.java with Java 6. Kind of a PITA, but it does help upstream developers hide internals from other people.

How are modules packaged and deployed? Does this still use Maven tooling and hosting?

Just a jar with an additional file (module-info.class). Maven has some documentation on it.

Sample patch that keeps Java 6 compatibility (although it needs to be compiled with Java 9+).
Notes:

  • You'll probably want to export specific classes, and the module name might be changed (e.g., com.drew.imaging.metadata-extractor)
  • requires xmpcore; will probably have to be updated at some time
diff --git a/Source/module-info.java b/Source/module-info.java
new file mode 100644
index 00000000..13650da2
--- /dev/null
+++ b/Source/module-info.java
@@ -0,0 +1,3 @@
+open module com.drew.imaging {
+    requires xmpcore;
+}
diff --git a/pom.xml b/pom.xml
index d940cce1..728279cf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -117,11 +117,25 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.8.1</version>
+                <version>3.10.1</version>
                 <configuration>
-                    <source>1.6</source>
-                    <target>1.6</target>
+                    <release>6</release>
                 </configuration>
+                <executions>
+                    <execution>
+                        <id>default-compile</id>
+                        <configuration>
+                            <release>9</release>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>base-compile</id>
+                        <goals><goal>compile</goal></goals>
+                        <configuration>
+                            <excludes><exclude>module-info.java</exclude></excludes>
+                        </configuration>
+                    </execution>
+                </executions>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>

With that said, until xmp-core either is modularized or has declared an Automatic-Module-Name in their manifest, it is not recommended to fully modularize to avoid issues when xmp-core does modularize.

Possible source locations for xmp-core:

@drewnoakes
Copy link
Owner

@Nadahar, we have two PRs contributed by @tsmock (thanks!) with different approaches to address this. It seems like #621 would be the safest. I'd value your opinion here, and welcome others to comment too. I'm not familiar with Java modules so don't feel confident to judge.

@Nadahar
Copy link
Contributor

Nadahar commented Aug 15, 2023

@drewnoakes I've not done much development the last year due to health issues, so I don't feel very "up to date". I also still stick with Java 8 because of all the limitations introduced in Java 9 - so I have no experience with modules either. All I understand is that it's a problem for those that use modules when one of their dependencies don't have a module declaration. But, as far as I can remember, you can't build JARs that's compatible with earlier versions of Java while also including the module information, at least not without "cheating" like they do here.

Isn't that the crux of the problem - the fact that even though you can make the Maven build file build versions both for Java 9+ and for prior versions, it will generate different JARs and you can't have one that does both? That means, as far as I can understand, that you have to "choose" which version to publish with Maven, and there's no way to include "module support" in the published JAR without also breaking backwards compatibility (except by "cheating" as described above where you generate the modules file with Java 9 and then overwrite the compiled classes with their Java 8 versions).

I my assumption that you can't have one JAR support modules and work with earlier versions is wrong, then it all comes down to what is the best way to support modules - and there I have no clue.

@tsmock's post above seems to indicate that there's a way to achieve both - which would be great.

@tsmock
Copy link
Contributor

tsmock commented Aug 16, 2023

But, as far as I can remember, you can't build JARs that's compatible with earlier versions of Java while also including the module information, at least not without "cheating" like they do here.

I took a quick look at the article, and that is effectively what I did with #620 (double compilation; first compile is against Java 9, then we recompile everything besides module-info against Java 7).

As I noted in my previous comment, and the PRs, I think that the better option is the Automatic-Module-Name manifest attribute, since we have no clue when (or even if) the XMP library will indicate a module name either via Automatic-Module-Name or an actual module-info file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants