Deadlock with JerseyClassAnalyzer#resolverAnnotations #5996

Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
diff --git a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/JerseyClassAnalyzer.java b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/JerseyClassAnalyzer.java
index 92d8923..dadc488 100644
--- a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/JerseyClassAnalyzer.java
+++ b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/JerseyClassAnalyzer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -25,7 +25,6 @@
 import java.security.PrivilegedAction;
 import java.util.List;
 import java.util.Set;
-import java.util.function.Supplier;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -35,9 +34,6 @@
 import org.glassfish.jersey.internal.LocalizationMessages;
 import org.glassfish.jersey.internal.inject.InjectionResolver;
 import org.glassfish.jersey.internal.util.collection.ImmutableCollectors;
-import org.glassfish.jersey.internal.util.collection.LazyValue;
-import org.glassfish.jersey.internal.util.collection.Value;
-import org.glassfish.jersey.internal.util.collection.Values;
 
 import org.glassfish.hk2.api.ClassAnalyzer;
 import org.glassfish.hk2.api.MultiException;
@@ -79,33 +75,31 @@
 
         @Override
         protected void configure() {
-            ClassAnalyzer defaultAnalyzer =
-                    serviceLocator.getService(ClassAnalyzer.class, ClassAnalyzer.DEFAULT_IMPLEMENTATION_NAME);
-
-            Supplier<List<InjectionResolver>> resolvers = () -> serviceLocator.getAllServices(InjectionResolver.class);
-
-            bind(new JerseyClassAnalyzer(defaultAnalyzer, resolvers))
+            bind(JerseyClassAnalyzer.class)
                     .analyzeWith(ClassAnalyzer.DEFAULT_IMPLEMENTATION_NAME)
                     .named(JerseyClassAnalyzer.NAME)
                     .to(ClassAnalyzer.class);
         }
     }
 
+    private final Set<Class> resolverAnnotations;
     private final ClassAnalyzer defaultAnalyzer;
-    private final LazyValue<Set<Class>> resolverAnnotations;
+
     /**
      * Injection constructor.
      *
-     * @param defaultAnalyzer   default HK2 class analyzer.
-     * @param supplierResolvers configured injection resolvers.
+     * @param serviceLocator current injection manager.
      */
-    private JerseyClassAnalyzer(ClassAnalyzer defaultAnalyzer, Supplier<List<InjectionResolver>> supplierResolvers) {
-        this.defaultAnalyzer = defaultAnalyzer;
-        Value<Set<Class>> resolvers = () -> supplierResolvers.get().stream()
+    @Inject
+    public JerseyClassAnalyzer(ServiceLocator serviceLocator) {
+        defaultAnalyzer = serviceLocator.getService(ClassAnalyzer.class, ClassAnalyzer.DEFAULT_IMPLEMENTATION_NAME);
+        // Load the resolver annotations once to avoid potential deadlock later
+        // See https://github.com/eclipse-ee4j/jersey/issues/5996
+        List<InjectionResolver> resolvers = serviceLocator.getAllServices(InjectionResolver.class);
+        this.resolverAnnotations = resolvers.stream()
                 .filter(InjectionResolver::isConstructorParameterIndicator)
                 .map(InjectionResolver::getAnnotation)
                 .collect(ImmutableCollectors.toImmutableSet());
-        this.resolverAnnotations = Values.lazy(resolvers);
     }
 
     @SuppressWarnings("unchecked")
@@ -186,7 +180,7 @@
 
         final int paramSize = constructor.getParameterTypes().length;
 
-        if (paramSize != 0 && resolverAnnotations.get().isEmpty()) {
+        if (paramSize != 0 && resolverAnnotations.isEmpty()) {
             return false;
         }
 
@@ -200,7 +194,7 @@
         for (final Annotation[] paramAnnotations : constructor.getParameterAnnotations()) {
             boolean found = false;
             for (final Annotation paramAnnotation : paramAnnotations) {
-                if (resolverAnnotations.get().contains(paramAnnotation.annotationType())) {
+                if (resolverAnnotations.contains(paramAnnotation.annotationType())) {
                     found = true;
                     break;
                 }