drewnoakes / metadata-extractor

Extracts Exif, IPTC, XMP, ICC and other metadata from image, video and audio files
Apache License 2.0
2.57k stars 482 forks source link

Add module-info for java9+ #566

Closed lanthale closed 7 months ago

lanthale commented 2 years ago

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 commented 2 years ago

How is the library not usable with Java 9+?

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

lanthale commented 2 years ago

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 commented 2 years ago

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:

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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:

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 commented 1 year ago

@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 commented 1 year ago

@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 commented 1 year ago

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.