apache / pulsar

Apache Pulsar - distributed pub-sub messaging system
https://pulsar.apache.org/
Apache License 2.0
14.27k stars 3.59k forks source link

Upgrade to jakarta-annotation-api, javax.annotation-api has been deprecated #21297

Open michalcukierman opened 1 year ago

michalcukierman commented 1 year ago

Search before asking

Motivation

It seems like Pulsar, (especially Pulsar Admin Client) still depends on javax.annotation-api 1.3.2, which has been archived, deprecated and replaced by jakarta-annotation-api. This can block the future libraries upgrade and make it complicated to integrate with new framworks/libraries, due to classloading issues.

Observed on using Pulsar Admin Client with Quarkus.

Solution

Upgrade to jakarta-annotation-api, which is also used by transitive dependencies. The source code can be found here: https://github.com/eclipse-ee4j/common-annotations-api

Alternatives

Not a long-term solution, but we could stick with javax.annotation-api for a while. Sooner or later we need to upgrade.

Anything else?

No response

Are you willing to submit a PR?

github-actions[bot] commented 1 year ago

The issue had no activity for 30 days, mark with Stale label.

lhotari commented 3 weeks ago

What is the impact of the deprecated annotations library?

In the Pulsar code base, there are some dependencies to javax libraries due to Jetty 9.4.x dependencies. It could be useful to first upgrade to Jetty 12 (#22939) and then migrating to use Jakarta annotations and libraries (Servlet) during that. The reason for this is that in Pulsar, all dependencies are in a flat classpath structure.

michalcukierman commented 3 weeks ago

To use this with Quarkus, you’ll need to add the following dependency:

    <!-- Use an alternative package because Quarkus excludes javax.annotation-api after build -->
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-annotations-api</artifactId>
    </dependency>

This is necessary because javax.annotation-api is removed from the build artifact by Quarkus. What's more - the annotation API is often available in recent versions (using Jakarta) in the project classpaths, so relying on the deprecated javax.annotation can be inconvenient.

Although this isn’t a critical issue, I believe it may make it progressively more challenging to integrate admin-client with codebases over time.

lhotari commented 3 weeks ago

To use this with Quarkus, you’ll need to add the following dependency:

    <!-- Use an alternative package because Quarkus excludes javax.annotation-api after build -->
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-annotations-api</artifactId>
    </dependency>

This is necessary because javax.annotation-api is removed from the build artifact by Quarkus. What's more - the annotation API is often available in recent versions (using Jakarta) in the project classpaths, so relying on the deprecated javax.annotation can be inconvenient.

Although this isn’t a critical issue, I believe it may make it progressively more challenging to integrate admin-client with codebases over time.

@michalcukierman what's the impact if you don't specify this library? do you get some error message or does something fail? Please share the possible error message to make it searchable.

lhotari commented 3 weeks ago

Jakarta migration dev mailing list thread: https://lists.apache.org/thread/dp2zkqxorqpwsjg2yjmmqgq4lrfst1r8

michalcukierman commented 3 weeks ago

Without tomcat annotations-api, the exception is thrown at runtime:

2024-11-02 19:13:51 INFO exec -a "java" java -XX:MaxRAMPercentage=80.0 -XX:+UseParallelGC -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+ExitOnOutOfMemoryError -Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -cp "." -jar /deployments/quarkus-run.jar 
2024-11-02 19:13:51 INFO running in /deployments
2024-11-02 19:13:51 __  ____  __  _____   ___  __ ____  ______ 
2024-11-02 19:13:51  --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
2024-11-02 19:13:51  -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
2024-11-02 19:13:51 --\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2024-11-02 19:13:51 2024-11-02 18:13:51,648 WARN  [io.qua.config] (main) Unrecognized configuration key "quarkus.http.host" was provided; it will be ignored; verify that the dependency extension for this configuration is set or that you did not make a typo
2024-11-02 19:13:51 2024-11-02 18:13:51,738 INFO  [dev.str.pul.ini.PulsarInitializer] (main) Starting Pulsar initialization
2024-11-02 19:13:51 2024-11-02 18:13:51,766 ERROR [io.qua.run.Application] (main) Failed to start application: java.lang.RuntimeException: Failed to start quarkus
2024-11-02 19:13:51     at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
2024-11-02 19:13:51     at io.quarkus.runtime.Application.start(Application.java:101)
2024-11-02 19:13:51     at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:119)
2024-11-02 19:13:51     at io.quarkus.runtime.Quarkus.run(Quarkus.java:71)
2024-11-02 19:13:51     at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
2024-11-02 19:13:51     at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
2024-11-02 19:13:51     at io.quarkus.runner.GeneratedMain.main(Unknown Source)
2024-11-02 19:13:51     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2024-11-02 19:13:51     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
2024-11-02 19:13:51     at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2024-11-02 19:13:51     at java.base/java.lang.reflect.Method.invoke(Method.java:568)
2024-11-02 19:13:51     at io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:62)
2024-11-02 19:13:51     at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:33)
2024-11-02 19:13:51 Caused by: java.lang.NoClassDefFoundError: javax/annotation/Priority
2024-11-02 19:13:51     at org.glassfish.jersey.JerseyPriorities.getPriorityValue(JerseyPriorities.java:48)
2024-11-02 19:13:51     at org.glassfish.jersey.model.internal.CommonConfig$FeatureRegistration.priority(CommonConfig.java:133)
2024-11-02 19:13:51     at org.glassfish.jersey.model.internal.CommonConfig$FeatureRegistration.<init>(CommonConfig.java:118)
2024-11-02 19:13:51     at org.glassfish.jersey.model.internal.CommonConfig$FeatureRegistration.<init>(CommonConfig.java:106)
2024-11-02 19:13:51     at org.glassfish.jersey.model.internal.CommonConfig.processFeatureRegistration(CommonConfig.java:505)
2024-11-02 19:13:51     at org.glassfish.jersey.model.internal.CommonConfig.register(CommonConfig.java:412)
2024-11-02 19:13:51     at org.glassfish.jersey.client.ClientConfig$State.register(ClientConfig.java:217)
2024-11-02 19:13:51     at org.glassfish.jersey.client.ClientConfig.register(ClientConfig.java:616)
2024-11-02 19:13:51     at org.apache.pulsar.client.admin.internal.PulsarAdminImpl.<init>(PulsarAdminImpl.java:133)
2024-11-02 19:13:51     at org.apache.pulsar.client.admin.internal.PulsarAdminBuilderImpl.build(PulsarAdminBuilderImpl.java:45)
2024-11-02 19:13:51     at dev.streamx.pulsar.init.PulsarInitializer.init(PulsarInitializer.java:56)
2024-11-02 19:13:51     at dev.streamx.pulsar.init.PulsarInitializer_Bean.doCreate(Unknown Source)
2024-11-02 19:13:51     at dev.streamx.pulsar.init.PulsarInitializer_Bean.create(Unknown Source)
2024-11-02 19:13:51     at dev.streamx.pulsar.init.PulsarInitializer_Bean.create(Unknown Source)
2024-11-02 19:13:51     at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119)
2024-11-02 19:13:51     at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38)
2024-11-02 19:13:51     at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35)
2024-11-02 19:13:51     at io.quarkus.arc.generator.Default_jakarta_enterprise_context_ApplicationScoped_ContextInstances.c1(Unknown Source)
2024-11-02 19:13:51     at io.quarkus.arc.generator.Default_jakarta_enterprise_context_ApplicationScoped_ContextInstances.computeIfAbsent(Unknown Source)
2024-11-02 19:13:51     at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35)
2024-11-02 19:13:51     at io.quarkus.arc.impl.ClientProxies.getApplicationScopedDelegate(ClientProxies.java:21)
2024-11-02 19:13:51     at dev.streamx.pulsar.init.PulsarInitializer_ClientProxy.arc$delegate(Unknown Source)
2024-11-02 19:13:51     at dev.streamx.pulsar.init.PulsarInitializer_ClientProxy.arc_contextualInstance(Unknown Source)
2024-11-02 19:13:51     at dev.streamx.pulsar.init.PulsarInitializer_Observer_Synthetic_dU_lJeM9CzqEdv-Hh8KHZ1SYvpE.notify(Unknown Source)
2024-11-02 19:13:51     at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:351)
2024-11-02 19:13:51     at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:333)
2024-11-02 19:13:51     at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:80)
2024-11-02 19:13:51     at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:156)
2024-11-02 19:13:51     at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:107)
2024-11-02 19:13:51     at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
2024-11-02 19:13:51     at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
2024-11-02 19:13:51     ... 13 more
2024-11-02 19:13:51 Caused by: java.lang.ClassNotFoundException: javax.annotation.Priority
2024-11-02 19:13:51     at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
2024-11-02 19:13:51     at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
2024-11-02 19:13:51     at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
2024-11-02 19:13:51     at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:114)
2024-11-02 19:13:51     at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:72)
2024-11-02 19:13:51     ... 44 more
2024-11-02 19:13:51 
2024-11-02 19:13:51 Exception in thread "Shutdown thread" java.lang.NullPointerException: Cannot invoke "io.quarkus.runtime.Application.isStarted()" because "app" is null
2024-11-02 19:13:51     at io.quarkus.runtime.ApplicationLifecycleManager$ShutdownHookThread.run(ApplicationLifecycleManager.java:455)

This is happening, because annotation-api is banned. The mechanism is explained here: https://quarkus.io/guides/class-loading-reference#banned-dependencies

I don't argue with the reasoning.

lhotari commented 2 weeks ago

Without tomcat annotations-api, the exception is thrown at runtime:

@michalcukierman Thanks. It looks like it's jersey-client 2.42 which pulls in the annotation-api dependency:

[INFO] |  +- org.glassfish.jersey.core:jersey-client:jar:2.42:compile
[INFO] |  |  +- jakarta.ws.rs:jakarta.ws.rs-api:jar:2.1.6:compile
[INFO] |  |  +- org.glassfish.jersey.core:jersey-common:jar:2.42:compile
[INFO] |  |  |  +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] |  |  |  \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile
[INFO] |  |  \- org.glassfish.hk2.external:jakarta.inject:jar:2.6.1:compile

We'd have to migrate to jersey-client 3.0.x or higher to get rid of the dependency.

lhotari commented 2 weeks ago

Without tomcat annotations-api, the exception is thrown at runtime:

@michalcukierman Thanks. It looks like it's jersey-client 2.42 which pulls in the annotation-api dependency:

[INFO] |  +- org.glassfish.jersey.core:jersey-client:jar:2.42:compile
[INFO] |  |  +- jakarta.ws.rs:jakarta.ws.rs-api:jar:2.1.6:compile
[INFO] |  |  +- org.glassfish.jersey.core:jersey-common:jar:2.42:compile
[INFO] |  |  |  +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] |  |  |  \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile
[INFO] |  |  \- org.glassfish.hk2.external:jakarta.inject:jar:2.6.1:compile

We'd have to migrate to jersey-client 3.0.x or higher to get rid of the dependency.

Actually that's already using jakarta.annotation-api.

lhotari commented 2 weeks ago

It looks like there are problems with the shading configuration of pulsar-client-all and pulsar-client-admin-shaded. There are transitive dependencies which should be shaded. This could be seen in the published pom.xml files (https://repo1.maven.org/maven2/org/apache/pulsar/pulsar-client-all/4.0.0/pulsar-client-all-4.0.0.pom and https://repo1.maven.org/maven2/org/apache/pulsar/pulsar-client-admin/4.0.0/pulsar-client-admin-4.0.0.pom).

cortlepp commented 1 week ago

Actually that's already using jakarta.annotation-api.

Yes, but in version 1.x the jakarta annotation api is still using the javax package :).

Regarding the shading configuration: I've taken a look at the pulsar-client-shaded pom, but it is unclear to me what exactly should be shaded and what should not. I see that there is an exclude for jackson-annotations and bouncycastle, from what I can tell it attempts to shade the rest? Would the solution to this problem be to complete this list with the missing javax libraries?

cortlepp commented 1 week ago

@lhotari I would happily contribute a PR for this, but right now I'm still not sure what the desired outcome of the shading configuration is exactly.

Also, can you maybe remove the Stale label from this Issue, I don't think it applies anymore and it might make it harder to find it in searches.

eolivelli commented 1 week ago

I have recently worked on moving Starlight for JMS to the Jakarta packages and I had many problems due to this issue (and the users have to import the old package anyway) We should move to Jakarta