merge of the current 2.x into the 3.0

diff --git a/core-common/src/main/java/org/glassfish/jersey/AbstractFeatureConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/AbstractFeatureConfigurator.java
index a73b185..36a3712 100644
--- a/core-common/src/main/java/org/glassfish/jersey/AbstractFeatureConfigurator.java
+++ b/core-common/src/main/java/org/glassfish/jersey/AbstractFeatureConfigurator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 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
@@ -49,9 +49,11 @@
      * @param loader specific classloader (must not be NULL)
      * @return list of found classes
      */
+
     protected List<Class<T>> loadImplementations(Map<String, Object> applicationProperties, ClassLoader loader) {
         if (PropertiesHelper.isMetaInfServicesEnabled(applicationProperties, getRuntimeType())) {
-            return Stream.of(ServiceFinder.find(getContract(), loader, true).toClassArray())
+            return Stream.of(ServiceFinder.service(getContract()).loader(loader).ignoreNotFound(true)
+                            .runtimeType(getRuntimeType()).find().toClassArray())
                     .collect(Collectors.toList());
         }
         return Collections.emptyList();
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
index ea7c62c..4a4972b 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2021 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
@@ -60,8 +60,8 @@
      */
     protected List<Class<T>> loadImplementations(Map<String, Object> applicationProperties) {
         if (PropertiesHelper.isMetaInfServicesEnabled(applicationProperties, runtimeType)) {
-            return Stream.of(ServiceFinder.find(contract, true).toClassArray())
-                    .collect(Collectors.toList());
+            return Stream.of(ServiceFinder.service(contract).ignoreNotFound(true).runtimeType(runtimeType)
+                    .find().toClassArray()).collect(Collectors.toList());
         }
         return Collections.emptyList();
     }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java
index 5f954ba..3b7bd24 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 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
@@ -114,7 +114,8 @@
 
         static {
             Set<HeaderDelegateProvider> hps = new HashSet<HeaderDelegateProvider>();
-            for (HeaderDelegateProvider provider : ServiceFinder.find(HeaderDelegateProvider.class, true)) {
+            for (HeaderDelegateProvider provider : ServiceFinder
+                    .service(HeaderDelegateProvider.class).ignoreNotFound(true).find()) {
                 hps.add(provider);
             }
             headerDelegateProviders = Collections.unmodifiableSet(hps);
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.java b/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.java
index 46184d8..5aa82a3 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -24,6 +24,7 @@
 import java.lang.reflect.ReflectPermission;
 import java.net.URL;
 import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.util.ArrayList;
@@ -38,6 +39,9 @@
 
 import org.glassfish.jersey.internal.util.ReflectionHelper;
 
+import jakarta.ws.rs.ConstrainedTo;
+import jakarta.ws.rs.RuntimeType;
+
 /**
  * A simple service-provider lookup mechanism.  A <i>service</i> is a
  * well-known set of interfaces and (usually abstract) classes.  A <i>service
@@ -106,7 +110,7 @@
  *   sun.io.StandardCodec    # Standard codecs for the platform
  * </pre>
  * <p/>
- * To locate an codec for a given encoding name, the internal I/O code would
+ * To locate a codec for a given encoding name, the internal I/O code would
  * do something like this:
  * <p/>
  * <pre>
@@ -133,10 +137,98 @@
 
     private static final Logger LOGGER = Logger.getLogger(ServiceFinder.class.getName());
     private static final String PREFIX = "META-INF/services/";
-    private final Class<T> serviceClass;
-    private final String serviceName;
-    private final ClassLoader classLoader;
-    private final boolean ignoreOnClassNotFound;
+
+    public static final class Builder<T> {
+        final Class<T> service;
+        String serviceName;
+        private ClassLoader loader;
+        private Boolean ignoreOnClassNotFound;
+        RuntimeType runtimeType = null;
+
+        private Builder(Class<T> serviceClass) {
+            this.service = serviceClass;
+        }
+
+        private Builder(Builder<T> builder) {
+            this.service = builder.service;
+            this.serviceName = builder.serviceName;
+            this.loader = builder.loader;
+            this.ignoreOnClassNotFound = builder.ignoreOnClassNotFound;
+            this.runtimeType = builder.runtimeType;
+        }
+
+        /**
+         * Create the service finder capable of locating the services with information specified by the builder.
+         * @return the service finder instance.
+         */
+        public ServiceFinder<T> find() {
+            if (serviceName == null) {
+                serviceName = service.getName();
+            }
+            if (loader == null) {
+                loader = _getContextClassLoader();
+            }
+            if (ignoreOnClassNotFound == null) {
+                ignoreOnClassNotFound = false;
+            }
+
+            return new ServiceFinder<T>(this);
+        }
+
+        /**
+         * Set the service name the service finder use to locate the services.
+         * @param serviceName the service name correspond to a file in
+         *        META-INF/services that contains a list of fully qualified class
+         *        names.
+         * @return the updated builder.
+         */
+        public Builder<T> serviceName(String serviceName) {
+            this.serviceName = serviceName;
+            return this;
+        }
+
+        /**
+         * Set the service finder to use the given {@code Classloader}. By default, the context classloader is used.
+         * @param loader the given classloader for the service finder to use when searching for the service.
+         * @return the updated builder.
+         */
+        public Builder<T> loader(ClassLoader loader) {
+            this.loader = loader;
+            return this;
+        }
+
+        /**
+         * Set the service finder to ignore the service if not found. The default is {@code false}.
+         * @param ignoreOnClassNotFound whether to ignore the service not found or not.
+         * @return the updated builder.
+         */
+        public Builder<T> ignoreNotFound(boolean ignoreOnClassNotFound) {
+            this.ignoreOnClassNotFound = ignoreOnClassNotFound;
+            return this;
+        }
+
+        /**
+         * Update the builder with a specified runtime type the searched services are constrained to it.
+         * @param runtimeType the specified runtime type.
+         * @return the updated builder.
+         */
+        public Builder<T> runtimeType(RuntimeType runtimeType) {
+            this.runtimeType = runtimeType;
+            return this;
+        }
+    }
+
+    /**
+     * Start configuring {@link Builder} with a specific service class to find.
+     * @param serviceClass the service class to find.
+     * @return a new instance of service finder builder.
+     * @param <T> type of the service class the service finder builder is created for.
+     */
+    public static <T> ServiceFinder.Builder<T> service(Class<T> serviceClass) {
+        return new Builder<>(serviceClass);
+    }
+
+    private final Builder<T> builder;
 
     static {
         final OsgiRegistry osgiRegistry = ReflectionHelper.getOsgiRegistryInstance();
@@ -201,11 +293,10 @@
      * @param <T> the type of the service instance.
      * @return the service finder
      */
+    @Deprecated
     public static <T> ServiceFinder<T> find(final Class<T> service, final ClassLoader loader)
             throws ServiceConfigurationError {
-        return find(service,
-                loader,
-                false);
+        return service(service).loader(loader).find();
     }
 
     /**
@@ -236,12 +327,11 @@
      * @param <T> the type of the service instance.
      * @return the service finder
      */
+    @Deprecated
     public static <T> ServiceFinder<T> find(final Class<T> service,
                                             final ClassLoader loader,
                                             final boolean ignoreOnClassNotFound) throws ServiceConfigurationError {
-        return new ServiceFinder<T>(service,
-                loader,
-                ignoreOnClassNotFound);
+        return service(service).loader(loader).ignoreNotFound(ignoreOnClassNotFound).find();
     }
 
     /**
@@ -251,7 +341,7 @@
      * <p/>
      * <pre>
      *   ClassLoader cl = Thread.currentThread().getContextClassLoader();
-     *   return Service.providers(service, cl, false);
+     *   return ServiceFinder.service(service).loader(cl).ignoreNotFound(false).find();
      * </pre>
      * @param service The service's abstract service class
      * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
@@ -262,9 +352,7 @@
      */
     public static <T> ServiceFinder<T> find(final Class<T> service)
             throws ServiceConfigurationError {
-        return find(service,
-                _getContextClassLoader(),
-                false);
+        return ServiceFinder.service(service).find();
     }
 
     /**
@@ -275,7 +363,7 @@
      * <pre>
      *   ClassLoader cl = Thread.currentThread().getContextClassLoader();
      *   boolean ingore = ...
-     *   return Service.providers(service, cl, ignore);
+     *   return ServiceFinder.service(service).loader(cl).ignoreNotFound(ignore).find();
      * </pre>
      * @param service The service's abstract service class
      * @param ignoreOnClassNotFound If a provider cannot be loaded by the class loader
@@ -286,11 +374,10 @@
      * @param <T> the type of the service instance.
      * @return the service finder
      */
+    @Deprecated
     public static <T> ServiceFinder<T> find(final Class<T> service,
                                             final boolean ignoreOnClassNotFound) throws ServiceConfigurationError {
-        return find(service,
-                _getContextClassLoader(),
-                ignoreOnClassNotFound);
+        return ServiceFinder.service(service).ignoreNotFound(ignoreOnClassNotFound).find();
     }
 
     /**
@@ -305,7 +392,7 @@
      * @return the service finder
      */
     public static ServiceFinder<?> find(final String serviceName) throws ServiceConfigurationError {
-        return new ServiceFinder<Object>(Object.class, serviceName, _getContextClassLoader(), false);
+        return service(Object.class).serviceName(serviceName).find();
     }
 
     /**
@@ -325,22 +412,8 @@
         ServiceIteratorProvider.setInstance(sip);
     }
 
-    private ServiceFinder(
-            final Class<T> service,
-            final ClassLoader loader,
-            final boolean ignoreOnClassNotFound) {
-        this(service, service.getName(), loader, ignoreOnClassNotFound);
-    }
-
-    private ServiceFinder(
-            final Class<T> service,
-            final String serviceName,
-            final ClassLoader loader,
-            final boolean ignoreOnClassNotFound) {
-        this.serviceClass = service;
-        this.serviceName = serviceName;
-        this.classLoader = loader;
-        this.ignoreOnClassNotFound = ignoreOnClassNotFound;
+    private ServiceFinder(Builder<T> builder) {
+        this.builder = new Builder<>(builder);
     }
 
     /**
@@ -354,8 +427,7 @@
      */
     @Override
     public Iterator<T> iterator() {
-        return ServiceIteratorProvider.getInstance()
-                .createIterator(serviceClass, serviceName, classLoader, ignoreOnClassNotFound);
+        return createIterator();
     }
 
     /**
@@ -373,7 +445,7 @@
         for (final T t : this) {
             result.add(t);
         }
-        return result.toArray((T[]) Array.newInstance(serviceClass, result.size()));
+        return result.toArray((T[]) Array.newInstance(builder.service, result.size()));
     }
 
     /**
@@ -388,16 +460,68 @@
     @SuppressWarnings("unchecked")
     public Class<T>[] toClassArray() throws ServiceConfigurationError {
         final List<Class<T>> result = new ArrayList<Class<T>>();
-
-        final ServiceIteratorProvider iteratorProvider = ServiceIteratorProvider.getInstance();
-        final Iterator<Class<T>> i = iteratorProvider
-                .createClassIterator(serviceClass, serviceName, classLoader, ignoreOnClassNotFound);
+        final Iterator<Class<T>> i = createClassIterator();
         while (i.hasNext()) {
             result.add(i.next());
         }
         return result.toArray((Class<T>[]) Array.newInstance(Class.class, result.size()));
     }
 
+    /**
+     * Return true iff the service class is not constrained to other runtime type.
+     * @param clazz the service class.
+     * @param runtimeType the expected constraint runtime type.
+     * @return {@code true} when the service class is constrained to configurator's runtime type or {@code false} otherwise.
+     */
+    private static boolean isConstrained(Class<?> clazz, RuntimeType runtimeType) {
+        final ConstrainedTo annotation = clazz.getAnnotation(ConstrainedTo.class);
+        return annotation == null || annotation.value() == runtimeType;
+    }
+
+    private Iterator<Class<T>> createClassIterator() {
+        final Iterator<Class<T>> it = ServiceIteratorProvider.getInstance().createClassIterator(
+                builder.service, builder.serviceName, builder.loader, builder.ignoreOnClassNotFound);
+        return builder.runtimeType == null ? it : new ConstrainedIterator<Class<T>>(it, builder.runtimeType);
+    }
+
+    private Iterator<T> createIterator() {
+        final Iterator<T> it = ServiceIteratorProvider.getInstance().createIterator(
+                builder.service, builder.serviceName, builder.loader, builder.ignoreOnClassNotFound);
+        return builder.runtimeType == null ? it : new ConstrainedIterator<T>(it, builder.runtimeType);
+    }
+
+    private static final class ConstrainedIterator<IT> implements Iterator<IT> {
+        private final Iterator<IT> i;
+        private final RuntimeType runtimeType;
+        private IT next;
+
+        private ConstrainedIterator(Iterator<IT> i, RuntimeType runtimeType) {
+            this.i = i;
+            this.runtimeType = runtimeType;
+        }
+
+        @Override
+        public boolean hasNext() {
+            while (next == null && i.hasNext()) {
+                next = i.next();
+                if (!isConstrained(next.getClass() == Class.class ? (Class<?>) next : next.getClass(), runtimeType)) {
+                    next = null;
+                }
+            }
+            return next != null;
+        }
+
+        @Override
+        public IT next() {
+            if (next == null && !hasNext()) {
+                throw new NoSuchElementException();
+            }
+            final IT n = next;
+            next = null;
+            return n;
+        }
+    }
+
     private static void fail(final String serviceName, final String msg, final Throwable cause)
             throws ServiceConfigurationError {
         final ServiceConfigurationError sce = new ServiceConfigurationError(serviceName + ": " + msg);
@@ -480,7 +604,7 @@
             final URLConnection uConn = u.openConnection();
             uConn.setUseCaches(false);
             in = uConn.getInputStream();
-            r = new BufferedReader(new InputStreamReader(in, "utf-8"));
+            r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
             int lc = 1;
             while ((lc = parseLine(serviceName, u, r, lc, names, returned)) >= 0) {
                 // continue
@@ -863,7 +987,7 @@
      * The default service iterator provider that looks up provider classes in
      * META-INF/services files.
      * <p>
-     * This class may utilized if a {@link ServiceIteratorProvider} needs to
+     * This class may be utilized if a {@link ServiceIteratorProvider} needs to
      * reuse the default implementation.
      */
     public static final class DefaultServiceIteratorProvider extends ServiceIteratorProvider {
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinderBinder.java b/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinderBinder.java
index 223d32b..670562d 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinderBinder.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinderBinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -58,7 +58,8 @@
     @Override
     protected void configure() {
         if (PropertiesHelper.isMetaInfServicesEnabled(applicationProperties, runtimeType)) {
-            for (Class<T> t : ServiceFinder.find(contract, true).toClassArray()) {
+            for (Class<T> t : ServiceFinder.service(contract).ignoreNotFound(true).runtimeType(runtimeType).find()
+                    .toClassArray()) {
                 bind(t).to(contract);
             }
         }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java
index 1750dd8..9444e9c 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -93,16 +93,12 @@
      * @param clazz type of service to look for.
      * @param <T>   type of service to look for.
      * @param type {@link RuntimeType} the {@link InjectionManagerFactory} must be {@link ConstrainedTo} if annotated.
-     * @return instance of service with highest priority or {@code null} if service of given type cannot be found.
+     * @return instance of service with the highest priority or {@code null} if service of given type cannot be found.
      * @see jakarta.annotation.Priority
      */
     private static <T> Optional<T> lookupService(final Class<T> clazz, RuntimeType type) {
         List<RankedProvider<T>> providers = new LinkedList<>();
-        for (T provider : ServiceFinder.find(clazz)) {
-            ConstrainedTo constrain = provider.getClass().getAnnotation(ConstrainedTo.class);
-            if (constrain != null && type != constrain.value()) {
-                continue;
-            }
+        for (T provider : ServiceFinder.service(clazz).runtimeType(type).find()) {
             providers.add(new RankedProvider<>(provider));
         }
         providers.sort(new RankedComparator<>(RankedComparator.Order.DESCENDING));
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Providers.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Providers.java
index f5c467a..e0aa5bf 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Providers.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Providers.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -107,7 +107,8 @@
         interfaces.put(Binder.class, ProviderRuntime.BOTH);
 
         try {
-            ServiceFinder<ExternalRegistrables> registerables = ServiceFinder.find(ExternalRegistrables.class, true);
+            ServiceFinder<ExternalRegistrables> registerables =
+                    ServiceFinder.service(ExternalRegistrables.class).ignoreNotFound(true).find();
             registerables.forEach(regs -> regs.registrableContracts()
                     .forEach(pair -> interfaces.put(pair.getContract(), ProviderRuntime.fromRuntimeType(pair.getRuntimeType()))));
         } catch (Throwable t) {
diff --git a/core-common/src/main/java/org/glassfish/jersey/model/internal/CommonConfig.java b/core-common/src/main/java/org/glassfish/jersey/model/internal/CommonConfig.java
index 1afa8c1..41d0868 100644
--- a/core-common/src/main/java/org/glassfish/jersey/model/internal/CommonConfig.java
+++ b/core-common/src/main/java/org/glassfish/jersey/model/internal/CommonConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -596,8 +596,8 @@
 
             // Forced (always invoked).
             final List<ForcedAutoDiscoverable> forcedAutoDiscroverables = new LinkedList<>();
-            for (Class<ForcedAutoDiscoverable> forcedADType : ServiceFinder.find(ForcedAutoDiscoverable.class, true)
-                    .toClassArray()) {
+            for (Class<ForcedAutoDiscoverable> forcedADType : ServiceFinder.service(ForcedAutoDiscoverable.class)
+                    .ignoreNotFound(true).runtimeType(getRuntimeType()).find().toClassArray()) {
                 forcedAutoDiscroverables.add(injectionManager.createAndInitialize(forcedADType));
             }
             providers.addAll(forcedAutoDiscroverables);
@@ -608,15 +608,11 @@
             }
 
             for (final AutoDiscoverable autoDiscoverable : providers) {
-                final ConstrainedTo constrainedTo = autoDiscoverable.getClass().getAnnotation(ConstrainedTo.class);
-
-                if (constrainedTo == null || type.equals(constrainedTo.value())) {
-                    try {
-                        autoDiscoverable.configure(this);
-                    } catch (final Exception e) {
-                        LOGGER.log(Level.FINE,
-                                LocalizationMessages.AUTODISCOVERABLE_CONFIGURATION_FAILED(autoDiscoverable.getClass()), e);
-                    }
+                try {
+                    autoDiscoverable.configure(this);
+                } catch (final Exception e) {
+                    LOGGER.log(Level.FINE,
+                            LocalizationMessages.AUTODISCOVERABLE_CONFIGURATION_FAILED(autoDiscoverable.getClass()), e);
                 }
             }
         }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java b/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
index 42d11dd..10e0d81 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2025 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2018 Payara Foundation and/or its affiliates.
  *
  * This program and the accompanying materials are made available under the
@@ -366,7 +366,7 @@
 
             if (!disableValidation()) {
                 ComponentModelValidator validator = new ComponentModelValidator(
-                        bootstrapBag.getValueParamProviders(), bootstrapBag.getMessageBodyWorkers());
+                        bootstrapBag.getValueParamProviders(), bootstrapBag.getMessageBodyWorkers(), runtimeConfig);
                     validator.validate(bootstrapBag.getResourceModel());
             }
 
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ExternalRequestScopeConfigurator.java b/core-server/src/main/java/org/glassfish/jersey/server/ExternalRequestScopeConfigurator.java
index d3d67d2..7619fcf 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ExternalRequestScopeConfigurator.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ExternalRequestScopeConfigurator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018 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
@@ -43,7 +43,8 @@
     public void init(InjectionManager injectionManager, BootstrapBag bootstrapBag) {
         ServerBootstrapBag serverBag = (ServerBootstrapBag) bootstrapBag;
 
-        Class<ExternalRequestScope>[] extScopes = ServiceFinder.find(ExternalRequestScope.class, true).toClassArray();
+        Class<ExternalRequestScope>[] extScopes =
+                ServiceFinder.service(ExternalRequestScope.class).ignoreNotFound(true).find().toClassArray();
         boolean extScopeBound = false;
 
         if (extScopes.length == 1) {
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java
index 6414204..47c784e 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -462,6 +462,23 @@
             "jersey.config.server.resource.validation.ignoreErrors";
 
     /**
+     * If {@code true} then validation of application resource models will not log a warning when a get resource method consumes an entity.
+     *
+     * This impacts both the validation of root resources during deployment as well as validation of any sub resources
+     * returned from sub-resource locators.
+     * <p>
+     * The default value is {@code false}.
+     * </p>
+     * <p>
+     * The name of the configuration property is <tt>{@value}</tt>.
+     * </p>
+     *
+     * @see #RESOURCE_VALIDATION_DISABLE
+     */
+    public static final String RESOURCE_VALIDATION_IGNORE_GET_CONSUMES_ENTITY_WARNINGS =
+            "jersey.config.server.resource.validation.ignoreGetConsumesEntityWarnings";
+
+    /**
      * If {@code true} then application monitoring will be enabled.
      *
      * This will enable the possibility
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/routing/RuntimeLocatorModelBuilder.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/routing/RuntimeLocatorModelBuilder.java
index aa5c0f3..23b926f 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/routing/RuntimeLocatorModelBuilder.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/routing/RuntimeLocatorModelBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -228,7 +228,7 @@
         Errors.process(new Runnable() {
             @Override
             public void run() {
-                final ComponentModelValidator validator = new ComponentModelValidator(valueSuppliers, messageBodyWorkers);
+                final ComponentModelValidator validator = new ComponentModelValidator(valueSuppliers, messageBodyWorkers, config);
                 validator.validate(component);
 
                 if (Errors.fatalIssuesFound() && !ignoreValidationErrors) {
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/model/ComponentModelValidator.java b/core-server/src/main/java/org/glassfish/jersey/server/model/ComponentModelValidator.java
index b93b172..5cd6878 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/model/ComponentModelValidator.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/model/ComponentModelValidator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -26,6 +26,8 @@
 import org.glassfish.jersey.server.model.internal.ModelErrors;
 import org.glassfish.jersey.server.spi.internal.ValueParamProvider;
 
+import jakarta.ws.rs.core.Configuration;
+
 /**
  * A resource model validator that checks the given resource model.
  *
@@ -57,10 +59,16 @@
     private final List<ResourceModelIssue> issueList = new LinkedList<>();
 
     public ComponentModelValidator(Collection<ValueParamProvider> valueParamProviders, MessageBodyWorkers msgBodyWorkers) {
+        this(valueParamProviders, msgBodyWorkers, null);
+    }
+
+    public ComponentModelValidator(Collection<ValueParamProvider> valueParamProviders,
+                                   MessageBodyWorkers msgBodyWorkers,
+                                   Configuration configuration) {
         validators = new ArrayList<>();
         validators.add(new ResourceValidator());
         validators.add(new RuntimeResourceModelValidator(msgBodyWorkers));
-        validators.add(new ResourceMethodValidator(valueParamProviders));
+        validators.add(new ResourceMethodValidator(valueParamProviders, configuration));
         validators.add(new InvocableValidator());
     }
 
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/model/ResourceMethodValidator.java b/core-server/src/main/java/org/glassfish/jersey/server/model/ResourceMethodValidator.java
index ac0c1da..2ab0707 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/model/ResourceMethodValidator.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/model/ResourceMethodValidator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -37,10 +37,11 @@
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.QueryParam;
-import jakarta.ws.rs.sse.SseEventSink;
+import jakarta.ws.rs.core.Configuration;
 
 import org.glassfish.jersey.internal.Errors;
 import org.glassfish.jersey.server.ContainerRequest;
+import org.glassfish.jersey.server.ServerProperties;
 import org.glassfish.jersey.server.internal.LocalizationMessages;
 import org.glassfish.jersey.server.model.internal.SseTypeResolver;
 import org.glassfish.jersey.server.spi.internal.ParameterValueHelper;
@@ -55,9 +56,15 @@
 class ResourceMethodValidator extends AbstractResourceModelVisitor {
 
     private final Collection<ValueParamProvider> valueParamProviders;
+    private final Configuration configuration;
 
     ResourceMethodValidator(Collection<ValueParamProvider> valueParamProviders) {
+        this(valueParamProviders, null);
+    }
+
+    ResourceMethodValidator(Collection<ValueParamProvider> valueParamProviders, Configuration configuration) {
         this.valueParamProviders = valueParamProviders;
+        this.configuration = configuration;
     }
 
     @Override
@@ -100,7 +107,7 @@
             }
 
             // ensure GET does not consume an entity parameter, if not inflector-based
-            if (invocable.requiresEntity() && !invocable.isInflector()) {
+            if (invocable.requiresEntity() && !invocable.isInflector() && !shouldIgnoreGetConsumesEntityWarnings(configuration)) {
                 Errors.warning(method, LocalizationMessages.GET_CONSUMES_ENTITY(invocable.getHandlingMethod()));
             }
             // ensure GET does not consume any @FormParam annotated parameter
@@ -154,6 +161,16 @@
         }
     }
 
+    private static Boolean shouldIgnoreGetConsumesEntityWarnings(Configuration configuration) {
+        if (configuration == null) {
+            return Boolean.FALSE;
+        }
+        return ServerProperties.getValue(configuration.getProperties(),
+                ServerProperties.RESOURCE_VALIDATION_IGNORE_GET_CONSUMES_ENTITY_WARNINGS,
+                Boolean.FALSE,
+                Boolean.class);
+    }
+
     private void checkUnexpectedAnnotations(ResourceMethod resourceMethod) {
         Invocable invocable = resourceMethod.getInvocable();
         for (Annotation annotation : invocable.getHandlingMethod().getDeclaredAnnotations()) {
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 bceaeda..d9963b5 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, 2020 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 jakarta.inject.Inject;
 import jakarta.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;
                 }
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/AutoDiscoverableTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/AutoDiscoverableTest.java
index 3dea887..476c255 100644
--- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/AutoDiscoverableTest.java
+++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/AutoDiscoverableTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -17,6 +17,9 @@
 package org.glassfish.jersey.tests.e2e.common;
 
 import java.io.IOException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.stream.Collectors;
 
 import jakarta.ws.rs.ConstrainedTo;
 import jakarta.ws.rs.POST;
@@ -31,13 +34,20 @@
 import jakarta.ws.rs.ext.WriterInterceptorContext;
 
 import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.internal.AutoDiscoverableConfigurator;
+import org.glassfish.jersey.internal.BootstrapBag;
+import org.glassfish.jersey.internal.ServiceFinder;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.Injections;
 import org.glassfish.jersey.internal.spi.AutoDiscoverable;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
+import org.glassfish.jersey.model.internal.CommonConfig;
+import org.glassfish.jersey.model.internal.ComponentBag;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
  * Note: Auto-discoverables from this test "affects" all other tests in suit.
@@ -133,6 +143,84 @@
     public void testAutoDiscoverableConstrainedTo() throws Exception {
         final Response response = target().request().post(Entity.text("value"));
 
-        assertEquals("value-common-client-common-server", response.readEntity(String.class));
+        Assertions.assertEquals("value-common-client-common-server", response.readEntity(String.class));
+    }
+
+    @Test
+    public void testServiceFinderIterator() {
+        Class<AutoDiscoverable>[] array =
+                ServiceFinder.service(AutoDiscoverable.class).runtimeType(RuntimeType.SERVER).find().toClassArray();
+        int size = array.length;
+
+        Assertions.assertTrue(size > 3);
+
+        ServiceFinder<AutoDiscoverable> finder =
+                ServiceFinder.service(AutoDiscoverable.class).runtimeType(RuntimeType.SERVER).find();
+        AutoDiscoverable next = null;
+        // check next()
+        final Iterator<AutoDiscoverable> it = finder.iterator();
+        for (int i = 0; i != size; i++) {
+            AutoDiscoverable n = it.next();
+            Assertions.assertNotSame(next, n);
+            next = n;
+        }
+        Assertions.assertThrows(NoSuchElementException.class, it::next);
+
+        // check hasNext();
+        final Iterator<AutoDiscoverable> it2 = finder.iterator();
+        next = null;
+        for (int i = 0; i != size; i++) {
+            for (int j = 0; j != size + 1; j++) {
+                Assertions.assertTrue(it2.hasNext());
+            }
+            AutoDiscoverable n = it2.next();
+            Assertions.assertNotSame(next, n);
+            next = n;
+        }
+        Assertions.assertFalse(it2.hasNext());
+        Assertions.assertThrows(NoSuchElementException.class, it2::next);
+    }
+
+    @Test
+    public void testAutoDiscoverableConstrainedConfigurator() {
+        Class<?>[] array = ServiceFinder.find(AutoDiscoverable.class).toClassArray();
+        Assertions.assertTrue(contains(ClientAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(CommonAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(ServerAutoDiscoverable.class, array));
+
+        array = ServiceFinder.service(AutoDiscoverable.class).find().toClassArray();
+        Assertions.assertTrue(contains(ClientAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(CommonAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(ServerAutoDiscoverable.class, array));
+
+        array = ServiceFinder.service(AutoDiscoverable.class).runtimeType(RuntimeType.SERVER).find().toClassArray();
+        Assertions.assertFalse(contains(ClientAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(CommonAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(ServerAutoDiscoverable.class, array));
+
+        array = ServiceFinder.service(AutoDiscoverable.class).runtimeType(RuntimeType.CLIENT).find().toClassArray();
+        Assertions.assertTrue(contains(ClientAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(CommonAutoDiscoverable.class, array));
+        Assertions.assertFalse(contains(ServerAutoDiscoverable.class, array));
+
+        AutoDiscoverableConfigurator configurator = new AutoDiscoverableConfigurator(RuntimeType.SERVER);
+        InjectionManager injectionManager = Injections.createInjectionManager();
+        BootstrapBag bb = new BootstrapBag();
+        bb.setConfiguration(new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL));
+        configurator.init(injectionManager, bb);
+        array = bb.getAutoDiscoverables().stream().map(ad -> ad.getClass()).collect(Collectors.toList())
+                .toArray(new Class[0]);
+        Assertions.assertFalse(contains(ClientAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(CommonAutoDiscoverable.class, array));
+        Assertions.assertTrue(contains(ServerAutoDiscoverable.class, array));
+    }
+
+    private static boolean contains(Class<?> clazz, Class<?>... list) {
+        for (Class<?> listClass : list) {
+            if (listClass.equals(clazz)) {
+                return true;
+            }
+        }
+        return false;
     }
 }