hypfvieh / dbus-java

Improved version of java DBus library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/)
https://hypfvieh.github.io/dbus-java/
MIT License
185 stars 73 forks source link

Modularise dbus-java (MRJAR, so supports Java 8 and Java 9+). #125

Closed brett-smith closed 3 years ago

brett-smith commented 3 years ago

Now that JNR at least uses Automatic-Module-Name, dbus-java itself can modularised. The largest change was the need to rename org.freedesktop.dbus.bin to org.freedesktop.dbus.utils.bin. No more than one particular module may export the same package, and both dbus-java-utils and dbus-java tried to export org.freedesktop.dbus.bin.

I should also point our that having classes in the org.freedesktop namespace is probably a bad idea (org.freedesktop.DBus and org.freedesktop.Hexdump classes), as this would mean that no modular project could use dbus-java and another module that happens to export org.freedesktop. One of my own projects did this (jfreedesktop), and exposed the issue. It can be left as org.freedesktop for now, but to be a good modular citizen this should be changed.

The other modular imperfection is java.utils. This is using an automatic module name, and should itself be modularised.

The Jar produced by the build is a multi-release Jar. So the bulk of it is compiled to Java 8, but Java 9 code is also compiled and placed in META-INF/versions/9. This is of course only used for module-info.class.

I had to disable animal-sniffer-maven-plugin to get this built. This doesn't appear to work with modules, and I can't find anything newer that 2017 for this apparently unmaintained plugin, so it may need to be removed.

SLF4J also required use of an alpha version for module support. It appears otherwise stable.

hypfvieh commented 3 years ago

Thanks for your PR.

I have to admit that I'm not a friend of this whole modularization stuff. In my opinion it does not serve any purpose and just adds extra complexity. Creating smaller JREs is not a valid argument for me. The platforms on which Java would be an option like Raspi and friends have enough space and memory to handle the full JRE. Other platforms are so low (like Arduino) that Java is not an option at all.

Anyways, a few things that I have to mention here:

First, using "org.freedesktop" as package for the DBus class is somehow required. The library uses the package names and class names (FQCN) as DBus object pathes. The main DBus object is org.freedesktop.DBus, so the interface should be in that package.

It would be possible to use an annotation to place the interface in another package. But this feature should only be used if it is not possible to use the package name (e.g. illegal package name), because using this will always require some 'extra' lookups on runtime. Another thing is, that moving this interface will break every existing application extending this interface. In short: I want to avoid moving that class anywhere.

The Hexdump class can be moved in my opinion, as this is only a helper class used internally.

Second: java-utils. I have to investigate which parts of java-utils are actually used. I would then integrate that few classes/methods to dbus-java directly and drop the dependency.

Third: animal-sniffer. I used that to ensure I write Java 8 compatible code. I'm using Java 11 for developing and sometimes one tries to use Java 11 features (like List.of, Map.of, anonymous innerclasses with diamond operator etc). Compiling would be fine, but running the code in Java 8 will fail.

I'm also wondering how long I should keep up the Java 8 support. For me Java 8 is already a way too old, even Java 11 will be EOL'd soon. But because I do not know how many folks out there still use ancient Java versions, I will at least stick to Java 8 until the next Java LTS version is available. Then I will bump the required version to Java 11.

Fourth: slf4j/logback. It is really a shame that there is no 'stable' slf4j versions supporting Jigsaw after so many years. I know that the latest alpha is out for quite some time. Same for logback, but logback is only runtime/test dependency so I can live with alpha/beta versions in this context.

I don't like to use alpha/beta versions as dependency in libraries which are not alpha/beta itself. Using slf4j alpha leaves some bad taste behind, because I'll force every project which includes dbus-java (no matter if Java 8 or higher) to use slf4j alpha version. I don't want to do that.

Fifth: The indenting in pom.xml seems to be broken (at least in the diff-view of github). I always uses spaces for identing, while your change is using tabs.

brett-smith commented 3 years ago

I have to admit that I'm not a friend of this whole modularization stuff. In my opinion it does not serve any purpose and just adds extra complexity. Creating smaller JREs is not a valid argument for me. The platforms on which Java would be an option like Raspi and friends have enough space and memory to handle the full JRE. Other platforms are so low (like Arduino) that Java is not an option at all.

It is a complex beast, although nowhere near as complex as OSGi it has to be said. It has taken many years, but i'm starting to find that many more libraries support modules at least to some basic degree. This job has to start with libraries at the lowest levels really for the rest of the Java ecosystem to have a chance. This article - https://blog.frankel.ch/hard-look-state-java-modularization/ - is not hopeful, although it's a couple of years old now, it would be interesting to see the current state.

As for the actual usefulness of modules themselves, I confess I do like being able to distribute a complete app along with a cut down runtime using jlink and friends, so for me its useful for that. As you say though there isnt a massive technical need for it.

The reason I made this PR was that my current main project (https://github.com/bithatch/snake) is totally modular except for dbus-java and one other library (that I intend to replace).

First, using "org.freedesktop" as package for the DBus class is somehow required. The library uses the package names and class names (FQCN) as DBus object pathes. The main DBus object is org.freedesktop.DBus, so the interface should be in that package.

It would be possible to use an annotation to place the interface in another package. But this feature should only be used if it is not possible to use the package name (e.g. illegal package name), because using this will always require some 'extra' lookups on runtime. Another thing is, that moving this interface will break every existing application extending this interface. In short: I want to avoid moving that class anywher

Understood, but you are saying here "dbus-java" owns the org.freedesktop package and no other library can use it and be used at the same time in a modular runtime. That being said, the conflicting library would also be saying the same thing I suppose, so who takes priority here? A quick search suggests that there are a few libraries out there use org.freedesktop, how many if any have classes and might export that package I couldn't say. Perhaps just ignore this particular problem for and defer it to a major release or something where a namespace change would be more acceptable.

The Hexdump class can be moved in my opinion, as this is only a helper class used internally.

Understood, I'll update this PR accordingly later.

Second: java-utils. I have to investigate which parts of java-utils are actually used. I would then integrate that few classes/methods to dbus-java directly and drop the dependency.

Understood. Will keep an eye out for this change.

I'm also wondering how long I should keep up the Java 8 support. For me Java 8 is already a way too old, even Java 11 will be EOL'd soon. But because I do not know how many folks out there still use ancient Java versions, I will at least stick to Java 8 until the next Java LTS version is available. Then I will bump the required version to Java 11.

Will get no complaints here. No new projects I am involved in use Java 8, but I do still maintain a significant number that do, a few even use dbus-java. By they are fine and stable on the current versions of dbus-java.

Fourth: slf4j/logback. It is really a shame that there is no 'stable' slf4j versions supporting Jigsaw after so many years. I know that the latest alpha is out for quite some time. Same for logback, but logback is only runtime/test dependency so I can live with alpha/beta versions in this context.

I have since realised that slf4j-1.8.0 is also actually modularised. However this itself is only beta! But that perhaps would leave a less bad taste. https://mvnrepository.com/artifact/org.slf4j/slf4j-api/1.8.0-beta4

Fifth: The indenting in pom.xml seems to be broken (at least in the diff-view of github). I always uses spaces for identing, while your change is using tabs.

Apologies, will correct.

hypfvieh commented 3 years ago

It is a complex beast, although nowhere near as complex as OSGi it has to be said. It has taken many years, but i'm starting to find that many more libraries support modules at least to some basic degree. This job has to start with libraries at the lowest levels really for the rest of the Java ecosystem to have a chance. This article - https://blog.frankel.ch/hard-look-state-java-modularization/ - is not hopeful, although it's a couple of years old now, it would be interesting to see the current state.

I don't like OSGi too. Every system which creates more complexity than it solves are a no go. Sadly there are much of those useless things in the java world :-\

Understood, but you are saying here "dbus-java" owns the org.freedesktop package and no other library can use it and be used at the same time in a modular runtime. That being said, the conflicting library would also be saying the same thing I suppose, so who takes priority here? A quick search suggests that there are a few libraries out there use org.freedesktop, how many if any have classes and might export that package I couldn't say. Perhaps just ignore this particular problem for and defer it to a major release or something where a namespace change would be more acceptable.

The thing is, DBus does not know or care about what Java wants. By the time the original dbus-java library was written, there were no such thing as Jigsaw, Lambdas and stuff (the original lib was written for Java 5). The DBus object naming scheme looks like FQCN, so the original author used the FQCN structure in Java for representing DBus object names (and I can't blame him, I would have done the same).

I moved the DBus main interface to org.freedesktop.dbus.interfaces and added the required annotation. I'm not convinced that this is the right decision, but we'll see.

I have since realised that slf4j-1.8.0 is also actually modularised. However this itself is only beta! But that perhaps would leave a less bad taste. https://mvnrepository.com/artifact/org.slf4j/slf4j-api/1.8.0-beta4

The bad taste stays. As far as I can see, slf4j 1.8 will be superseded by 2.0. There is no really active development in slf4j for 1.8.x and 2.0 for over a year. I don't expect that there will be a release version any time soon.

But maybe we can stick to 1.7.30, as there is an 'automatic-module-name' entry in the MANIFEST since 1.7.25. Can you take a look at that?

Automatic-Module-Name: org.slf4j Export-Package: org.slf4j;version=1.7.30, org.slf4j.spi;version=1.7.30 , org.slf4j.helpers;version=1.7.30, org.slf4j.event;version=1.7.30 Import-Package: org.slf4j.impl;version=1.6.0

brett-smith commented 3 years ago

The bad taste stays. As far as I can see, slf4j 1.8 will be superseded by 2.0. There is no really active development in slf4j for 1.8.x and 2.0 for over a year. I don't expect that there will be a release version any time soon.

But maybe we can stick to 1.7.30, as there is an 'automatic-module-name' entry in the MANIFEST since 1.7.25. Can you take a look at that?

That works out absolutely fine, have updated the PR accordingly (and also corrected those tabs to spaces).

If you are considering dropping Java 8 support at some stage, you could get rid of SLF4J entirely and replace it with SystemLogger (https://docs.oracle.com/javase/9/docs/api/java/lang/System.Logger.html). This is available in Java 9 onwards. For some reason, Oracle went with only log(level, message) type methods instead of convenience methods like log.info(message) or whatever, but at least there is now a facade API in the core (not even a Jigsaw module is needed).