Re: Problems creating custom appender using JPMS service in 3.0.0-beta3

"Piotr P. Karwasz" <[email protected]> Fri, 29 Nov 2024 09:07:27 +0100
Newsgroups gmane.comp.jakarta.log4j.user
Message-ID <[email protected]>
Hi Pavel,

On 28.11.2024 19:26, PavelTurk wrote:
> Thank you very much for your detailed and quick help.
>
> However, to tell the truth, I’m a bit confused. I’ve been waiting for 
> a long time for Log4j to finally work according to the JPMS rules. But 
> in your message, you talk about compile-time and, as I understood, the 
> use of some plugin-processor (from your project pom):
>
>           <annotationProcessorPaths>
>             <path>
> <groupId>org.apache.logging.log4j</groupId>
> <artifactId>log4j-plugin-processor</artifactId>
>               <version>3.0.0-beta3</version>
>             </path>
>           </annotationProcessorPaths>
>
> Doesn’t all this completely contradict JPMS?
 > (...)
> By the way, I noticed something seemed off when I saw code duplication 
> in your project:
>
> @Configurable(elementType = Appender.ELEMENT_TYPE, printObject = true)
> @Plugin(ConsoleAppender.PLUGIN_NAME)
> public final class ConsoleAppender...
>
> and
>
> PluginEntry.builder()
>   .setKey("console")
> .setClassName("org.apache.logging.log4j.core.appender.ConsoleAppender")
>   .setName("Console")
>   .setNamespace("Core")
>   .setElementType("appender")
>   .setPrintable(true)
>   .get(),
>
> Or am I mistaken (which is always possible) and misunderstood everything?

We have an annotation processor that automatically generates the 
required `PluginService` implementation, I don't see how that 
contradicts the principles behind JPMS.

In the lines above there is no code duplication, because the annotations 
are added by developers, while the `PluginEntry` code is automatically 
generated by `PluginProcessor`. This ensures that everything is 
perfectly synchronized.

If you don't want to use the annotation processor, you shouldn't use the 
`@Configurable` and `@Plugin` annotations. AFAIK, these are only used by 
the annotation processor.

Regarding JPMS compatibility, the main idea behind JPMS is to restrict 
access from one module to other modules in the system. We achieved that 
goal:

* for Log4j API in version 2.11.0, when we added a manually written 
`module-info.java` file.

* for Log4j Core and the remaining artifacts in version 2.21.0, when we 
added module descriptors automatically generated by BND.

Of course Log4j Core 2 is a bad JPMS module since:

* It contains many optional dependencies (`requires static`). These are 
bad for many reasons. In JPMS the main problem is that `static` 
dependencies are not automatically loaded by the JVM, so an application 
that wants them, needs to add an appropriate `requires` to its own 
module descriptor or `--add-modules` on the command line.

* There is no pointer from Log4j Core module descriptor to its extension 
modules. Therefore the JVM will not automatically load, e.g. the JSON 
Template Layout module, unless the application uses --add-modules or an 
apposite `requires` as above.

Both problems are solved in Log4j Core 3.0.0-beta3:

* There are no optional runtime dependencies any more.

* Additional Log4j Plugin modules are loaded automatically. I didn't 
find a documentation for this behavior, but at least HotSpot 
automatically loads all observable modules that `provide` a service that 
Log4j Core `uses`. In this case the service is `PluginService`.

Piotr