Better @Inject support.  For servlet classes, a qualifier is used.

Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/ext/cdi/jersey-cdi-rs-inject/pom.xml b/ext/cdi/jersey-cdi-rs-inject/pom.xml
index 68505d2..537fb2a 100644
--- a/ext/cdi/jersey-cdi-rs-inject/pom.xml
+++ b/ext/cdi/jersey-cdi-rs-inject/pom.xml
@@ -45,6 +45,13 @@
             <artifactId>cdi-api</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <version>${servlet4.version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
     </dependencies>
 
     <build>
@@ -65,6 +72,7 @@
                     <instructions>
                         <Import-Package>
                             ${cdi.osgi.version},
+                            javax.servlet.*;version="[2.4,5.0)";resolution:=optional,
                             *
                         </Import-Package>
                     </instructions>
diff --git a/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/InjectExtension.java b/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/InjectExtension.java
index a6d2e09..3466852 100644
--- a/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/InjectExtension.java
+++ b/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/InjectExtension.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2022 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
@@ -22,12 +22,23 @@
 import org.glassfish.jersey.internal.util.collection.Value;
 import org.glassfish.jersey.internal.util.collection.Values;
 
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.context.spi.CreationalContext;
 import javax.enterprise.event.Observes;
 import javax.enterprise.inject.Alternative;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 import javax.enterprise.inject.spi.BeforeBeanDiscovery;
 import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.enterprise.inject.spi.InjectionTargetFactory;
+import javax.enterprise.inject.spi.PassivationCapable;
 import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import javax.inject.Singleton;
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.container.ResourceContext;
 import javax.ws.rs.container.ResourceInfo;
@@ -40,9 +51,13 @@
 import javax.ws.rs.ext.ParamConverterProvider;
 import javax.ws.rs.ext.Providers;
 import javax.ws.rs.sse.Sse;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
 import java.security.AccessController;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.UUID;
 
 /**
  * <p>
@@ -57,7 +72,12 @@
  */
 @SuppressWarnings("unused")
 class InjectExtension implements Extension {
-    private void processAnnotatedType(@Observes ProcessAnnotatedType<?> processAnnotatedType, BeanManager beanManager) {
+    private static final Class<?> WEB_CONFIG_CLASS =
+            AccessController.doPrivileged(ReflectionHelper.classForNamePA("org.glassfish.jersey.servlet.WebConfig"));
+    private AnnotatedType<ServletReferenceProducer> interceptorAnnotatedType;
+
+    private void processAnnotatedType(@Observes ProcessAnnotatedType<?> processAnnotatedType,
+                                      BeanManager beanManager) {
         final Class<?> baseClass = (Class<?>) processAnnotatedType.getAnnotatedType().getBaseType();
         if (Application.class.isAssignableFrom(baseClass) && Configuration.class.isAssignableFrom(baseClass)) {
             if (!baseClass.isAnnotationPresent(Alternative.class)) {
@@ -67,8 +87,103 @@
     }
 
     private void beforeDiscoveryObserver(@Observes final BeforeBeanDiscovery bbf, final BeanManager beanManager) {
-        final CdiComponentProvider cdiComponentProvider = beanManager.getExtension(CdiComponentProvider.class);
-        cdiComponentProvider.addHK2DepenendencyCheck(InjectExtension::isHK2Dependency);
+        if (WEB_CONFIG_CLASS != null) {
+            interceptorAnnotatedType = beanManager.createAnnotatedType(ServletReferenceProducer.class);
+            bbf.addAnnotatedType(interceptorAnnotatedType, ServletReferenceProducer.class.getName());
+        }
+        CdiComponentProvider.addHK2DepenendencyCheck(InjectExtension::isHK2Dependency);
+    }
+
+    private void afterDiscoveryObserver(@Observes final AfterBeanDiscovery abd, final BeanManager beanManager) {
+        if (WEB_CONFIG_CLASS != null) {
+            abd.addBean(new ServletReferenceProducerBean(beanManager));
+        }
+    }
+
+    @Singleton
+    private final class ServletReferenceProducerBean implements Bean<ServletReferenceProducer>, PassivationCapable {
+        private final Set<Annotation> qualifiers = new HashSet<>();
+        private final Set<Type> types = new HashSet<>(2);
+        private final InjectionTarget<ServletReferenceProducer> interceptorTarget;
+        private final String id = UUID.randomUUID().toString();
+
+        private ServletReferenceProducerBean(BeanManager beanManager) {
+            qualifiers.add(new CdiJerseyContextAnnotation());
+            qualifiers.add(new CdiAnyAnnotation());
+
+            types.add(ServletReferenceProducer.class);
+            types.add(Object.class);
+
+            final AnnotatedType<ServletReferenceProducer> interceptorType = interceptorAnnotatedType;
+            final InjectionTargetFactory<ServletReferenceProducer> injectionTargetFactory =
+                    beanManager.getInjectionTargetFactory(interceptorType);
+
+            interceptorTarget = injectionTargetFactory.createInjectionTarget(null);
+        }
+        @Override
+        public Set<Type> getTypes() {
+            return types;
+        }
+
+        @Override
+        public Set<Annotation> getQualifiers() {
+            return qualifiers;
+        }
+
+        @Override
+        public Class<? extends Annotation> getScope() {
+            return RequestScoped.class;
+        }
+
+        @Override
+        public String getName() {
+            return ServletReferenceProducer.class.getName();
+        }
+
+        @Override
+        public Set<Class<? extends Annotation>> getStereotypes() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public boolean isAlternative() {
+            return false;
+        }
+
+        @Override
+        public ServletReferenceProducer create(CreationalContext<ServletReferenceProducer> creationalContext) {
+            final ServletReferenceProducer result = interceptorTarget.produce(creationalContext);
+            interceptorTarget.inject(result, creationalContext);
+            interceptorTarget.postConstruct(result);
+            return result;
+        }
+
+        @Override
+        public void destroy(ServletReferenceProducer servletProducer,
+                            CreationalContext<ServletReferenceProducer> creationalContext) {
+            interceptorTarget.preDestroy(servletProducer);
+            interceptorTarget.dispose(servletProducer);
+            creationalContext.release();
+        }
+
+        @Override
+        public Class<?> getBeanClass() {
+            return ServletReferenceProducer.class;
+        }
+
+        @Override
+        public Set<InjectionPoint> getInjectionPoints() {
+            return interceptorTarget.getInjectionPoints();
+        }
+
+        public boolean isNullable() {
+            return false;
+        }
+
+        @Override
+        public String getId() {
+            return id;
+        }
     }
 
     private static final boolean isHK2Dependency(Class<?> clazz) {
@@ -95,20 +210,17 @@
         injectables.add(Sse.class);
         injectables.add(UriInfo.class);
 
-        //Servlet if available
-        addOptionally("javax.servlet.http.HttpServletRequest", injectables);
-        addOptionally("javax.servlet.http.HttpServletResponse", injectables);
-        addOptionally("javax.servlet.ServletConfig", injectables);
-        addOptionally("javax.servlet.ServletContext", injectables);
-        addOptionally("javax.servlet.FilterConfig", injectables);
-
         return injectables;
     }
 
-    private static void addOptionally(String className, Set<Class<?>> set) {
-        final Class<?> optionalClass = AccessController.doPrivileged(ReflectionHelper.classForNamePA(className));
-        if (optionalClass != null) {
-            set.add(optionalClass);
-        }
+    private static class CdiJerseyContextAnnotation
+            extends javax.enterprise.util.AnnotationLiteral<JerseyContext> implements JerseyContext {
+        private static final long serialVersionUID = 1L;
     }
+
+    private static class CdiAnyAnnotation
+            extends javax.enterprise.util.AnnotationLiteral<Any> implements Any {
+        private static final long serialVersionUID = 1L;
+    }
+
 }
diff --git a/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/JerseyContext.java b/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/JerseyContext.java
new file mode 100644
index 0000000..f238f53
--- /dev/null
+++ b/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/JerseyContext.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.ext.cdi1x.inject.internal;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>
+ *  Qualifier used for injecting the CDI beans using {@code @Inject}. Used only for beans that originate in Specification other
+ *  than Jakarta RESTful Web Services (such as Servlet). Such beans must not be produced with {@code @Default} qualifier so that
+ *  there is no ambiguity for the CDI injection.
+ * </p>
+ * <p>
+ *     Jakarta REST Spec. Section 11 demands {@code HttpServletRequest}, {@code HttpServletResponse}, {@code ServletContext},
+ *     {@code ServletConfig}, and {@code FilterConfig} to be available by injections using {@code @Context}. For CDI, these
+ *     servlet classes are available with {@link JerseyContext} qualifier.
+ * </p>
+ * <p>
+ *     Note that {@code @Context} injection is not aware of the qualifier and using {@code &#64;Context} in conjuction with
+ *     {@code &#64;JerseyContext} will not work.
+ * </p>
+ * <p>
+ *  Can be used as e.g.
+ *
+ * <pre>
+ * &#64;Inject
+ * &#64;JerseyContext //internal
+ * HttpServletRequest httpServletRequest;
+ * </pre>
+ * or as iterable of all {@code HttpServletRequest} beans
+ * <pre>
+ * &#64;Inject
+ * &#64;Any
+ * Instance&lt;HttpServletRequest&gt; httpServletRequests;
+ * </pre>
+ * </p>
+ * @since 2.38
+ */
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
+public @interface JerseyContext {
+}
diff --git a/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/ServletReferenceProducer.java b/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/ServletReferenceProducer.java
new file mode 100644
index 0000000..56f4e9f
--- /dev/null
+++ b/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/ServletReferenceProducer.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.ext.cdi1x.inject.internal;
+
+import org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A CDI producer producing servlet beans in a {@code RequestScope}.
+ */
+class ServletReferenceProducer {
+    @Inject
+    InjectionManager injectionManager;
+
+    @Inject
+    BeanManager beanManager;
+
+    @Produces
+    @JerseyContext
+    @RequestScoped
+    public HttpServletRequest produceHttpServletRequest() {
+        return injectionManager().getInstance(HttpServletRequest.class);
+    }
+
+    @Produces
+    @JerseyContext
+    @RequestScoped
+    public HttpServletResponse produceHttpServletResponse() {
+        return injectionManager().getInstance(HttpServletResponse.class);
+    }
+
+    @Produces
+    @JerseyContext
+    @RequestScoped
+    public ServletContext produceServletContext() {
+        return injectionManager().getInstance(ServletContext.class);
+    }
+
+    @Produces
+    @JerseyContext
+    @RequestScoped
+    public ServletConfig produceServletConfig() {
+        return injectionManager().getInstance(ServletConfig.class);
+    }
+
+    @Produces
+    @JerseyContext
+    @RequestScoped
+    public FilterConfig produceFilterConfig() {
+        return injectionManager().getInstance(FilterConfig.class);
+    }
+
+    private InjectionManager injectionManager() {
+        InjectionManager injectionManager = beanManager.getExtension(CdiComponentProvider.class).getEffectiveInjectionManager();
+        if (injectionManager != null && !injectionManager.isShutdown()) {
+            return injectionManager;
+        }
+        return this.injectionManager;
+    }
+}
diff --git a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java
index ff63759..5595b8a 100644
--- a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java
+++ b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java
@@ -68,7 +68,6 @@
 import javax.enterprise.inject.spi.ProcessAnnotatedType;
 import javax.enterprise.inject.spi.ProcessInjectionTarget;
 import javax.enterprise.util.AnnotationLiteral;
-import javax.inject.Qualifier;
 
 import org.glassfish.jersey.ext.cdi1x.internal.spi.InjectionManagerInjectedTarget;
 import org.glassfish.jersey.ext.cdi1x.internal.spi.InjectionManagerStore;
@@ -118,7 +117,7 @@
     private final Set<Type> jaxrsInjectableTypes = new HashSet<>();
     private final Set<Type> hk2ProvidedTypes = Collections.synchronizedSet(new HashSet<Type>());
     private final Set<Type> jerseyVetoedTypes = Collections.synchronizedSet(new HashSet<Type>());
-    private final Set<DependencyPredicate> jerseyOrDependencyTypes = Collections.synchronizedSet(new LinkedHashSet<>());
+    private static final Set<DependencyPredicate> jerseyOrDependencyTypes = Collections.synchronizedSet(new LinkedHashSet<>());
     private final ThreadLocal<InjectionManager> threadInjectionManagers = new ThreadLocal<>();
 
     /**
@@ -554,7 +553,7 @@
      *
      * @return HK2 injection manager.
      */
-    /* package */ InjectionManager getEffectiveInjectionManager() {
+    public InjectionManager getEffectiveInjectionManager() {
         return injectionManagerStore.getEffectiveInjectionManager();
     }
 
@@ -870,11 +869,11 @@
      * Add a predicate to test HK2 dependency to create a CDI bridge bean to HK2 for it.
      * @param predicate to test whether given class is a HK2 dependency.
      */
-    public void addHK2DepenendencyCheck(Predicate<Class<?>> predicate) {
+    public static void addHK2DepenendencyCheck(Predicate<Class<?>> predicate) {
         jerseyOrDependencyTypes.add(new DependencyPredicate(predicate));
     }
 
-    private final class DependencyPredicate implements Predicate<Class<?>> {
+    private static final class DependencyPredicate implements Predicate<Class<?>> {
         private final Predicate<Class<?>> predicate;
 
         public DependencyPredicate(Predicate<Class<?>> predicate) {
@@ -891,7 +890,7 @@
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             DependencyPredicate that = (DependencyPredicate) o;
-            return predicate.getClass().equals(that.predicate);
+            return predicate.getClass().equals(that.predicate.getClass());
         }
 
         @Override
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java
index 5b4de38..4f44123 100644
--- a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2022 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,7 +37,6 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.ext.ParamConverterProvider;
 import javax.ws.rs.ext.Providers;
 import java.lang.reflect.Field;
 import java.util.Iterator;
@@ -96,9 +95,6 @@
     @Context
     protected HttpServletRequest contextHttpServletRequest;
 
-    @Inject
-    protected HttpServletRequest injectHttpServletRequest;
-
     @Context
     protected WebConfig contextWebConfig;
 
@@ -108,21 +104,12 @@
     @Context
     protected HttpServletResponse contextHttpServletResponse;
 
-    @Inject
-    protected HttpServletResponse injectHttpServletResponse;
-
     @Context
     protected ServletConfig contextServletConfig;
 
-    @Inject
-    protected ServletConfig injectServletConfig;
-
     @Context
     protected ServletContext contextServletContext;
 
-    @Inject
-    protected ServletContext injectServletContext;
-
     static class InjectHolder extends ParentInject {
 
         @Override
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java
index 6a546fb..e4daf19 100644
--- a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2022 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
@@ -33,7 +33,6 @@
 import javax.ws.rs.core.Request;
 import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.ext.ParamConverterProvider;
 import javax.ws.rs.ext.Providers;
 
 public class ParentInject implements ParentChecker {
@@ -106,9 +105,6 @@
     @Context
     protected HttpServletRequest contextHttpServletRequest;
 
-    @Inject
-    protected HttpServletRequest injectHttpServletRequest;
-
     @Context
     protected WebConfig contextWebConfig;
 
@@ -118,21 +114,12 @@
     @Context
     protected HttpServletResponse contextHttpServletResponse;
 
-    @Inject
-    protected HttpServletResponse injectHttpServletResponse;
-
     @Context
     protected ServletConfig contextServletConfig;
 
-    @Inject
-    protected ServletConfig injectServletConfig;
-
     @Context
     protected ServletContext contextServletContext;
 
-    @Inject
-    protected ServletContext injectServletContext;
-
     @Override
     public boolean checkInjected(StringBuilder stringBuilder) {
         boolean injected = true;
@@ -148,11 +135,7 @@
         injected &= InjectionChecker.checkSecurityContext(injectSecurityContext, stringBuilder);
         injected &= InjectionChecker.checkUriInfo(injectUriInfo, stringBuilder);
 
-        injected &= InjectionChecker.checkHttpServletRequest(injectHttpServletRequest, stringBuilder);
-        injected &= InjectionChecker.checkHttpServletResponse(injectHttpServletResponse, stringBuilder);
         injected &= InjectionChecker.checkWebConfig(injectWebConfig, stringBuilder);
-        injected &= InjectionChecker.checkServletConfig(injectServletConfig, stringBuilder);
-        injected &= InjectionChecker.checkServletContext(injectServletContext, stringBuilder);
 
         return injected;
     }
@@ -182,7 +165,7 @@
     }
 
     protected boolean checkApplication(Application application, StringBuilder stringBuilder) {
-        return InjectionChecker.checkApplication(contextApplication, stringBuilder);
+        return InjectionChecker.checkApplication(application, stringBuilder);
     }
 
     protected boolean checkConfiguration(Configuration configuration, StringBuilder stringBuilder) {
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletApplication.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletApplication.java
new file mode 100644
index 0000000..ec50128
--- /dev/null
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletApplication.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.cdi.inject;
+
+import org.glassfish.jersey.server.ResourceConfig;
+
+import javax.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class ServletApplication extends ResourceConfig {
+    ServletApplication() {
+        super(ServletExceptionMapper.class,
+                ServletResponseFilter.class,
+                ServletRequestFilter.class,
+                ServletResource.class);
+    }
+}
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletExceptionMapper.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletExceptionMapper.java
new file mode 100644
index 0000000..9643019
--- /dev/null
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletExceptionMapper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.cdi.inject;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+@ApplicationScoped
+public class ServletExceptionMapper extends ServletInject implements ExceptionMapper<IllegalArgumentException> {
+    @Override
+    public Response toResponse(IllegalArgumentException exception) {
+        return super.check();
+    }
+}
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletInject.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletInject.java
new file mode 100644
index 0000000..57fa75a
--- /dev/null
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletInject.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.cdi.inject;
+
+import javax.enterprise.inject.Any;
+import javax.inject.Inject;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+
+public class ServletInject {
+    @Inject
+    @Any
+    protected HttpServletRequest injectHttpServletRequest;
+
+    @Inject
+    @Any
+    protected HttpServletResponse injectHttpServletResponse;
+
+    @Inject
+    @Any
+    protected ServletConfig injectServletConfig;
+
+    @Inject
+    @Any
+    protected ServletContext injectServletContext;
+
+    public boolean check(StringBuilder sb) {
+        boolean injected = true;
+        injected &= InjectionChecker.checkHttpServletRequest(injectHttpServletRequest, sb);
+        injected &= InjectionChecker.checkHttpServletResponse(injectHttpServletResponse, sb);
+        injected &= InjectionChecker.checkServletConfig(injectServletConfig, sb);
+        injected &= InjectionChecker.checkServletContext(injectServletContext, sb);
+        return injected;
+    }
+
+    public Response check() {
+        StringBuilder sb = new StringBuilder();
+        if (check(sb)) {
+            return Response.ok().entity("All injected").build();
+        } else {
+            return Response.status(Response.Status.EXPECTATION_FAILED).entity(sb.toString()).build();
+        }
+    }
+}
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletRequestFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletRequestFilter.java
new file mode 100644
index 0000000..21996cc
--- /dev/null
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletRequestFilter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.cdi.inject;
+
+import javax.enterprise.context.RequestScoped;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+@RequestScoped
+public class ServletRequestFilter extends ServletInject implements ContainerRequestFilter {
+    @Override
+    public void filter(ContainerRequestContext requestContext) throws IOException {
+        Response response = super.check();
+        if (response.getStatus() != Response.Status.OK.getStatusCode()) {
+            requestContext.abortWith(response);
+        }
+    }
+}
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletResource.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletResource.java
new file mode 100644
index 0000000..acddb88
--- /dev/null
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletResource.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.cdi.inject;
+
+import javax.enterprise.context.RequestScoped;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+@RequestScoped
+@Path("/servlet")
+public class ServletResource extends ServletInject {
+
+    @GET
+    public Response checkApp() {
+        return super.check();
+    }
+
+    @GET
+    @Path("exception")
+    public Response throwE() {
+        throw new IllegalArgumentException();
+    }
+}
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletResponseFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletResponseFilter.java
new file mode 100644
index 0000000..90cb656
--- /dev/null
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ServletResponseFilter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.cdi.inject;
+
+import javax.enterprise.context.RequestScoped;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+@RequestScoped
+public class ServletResponseFilter extends ServletInject implements ContainerResponseFilter {
+    @Override
+    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
+        if (responseContext.getStatus() != Response.Status.OK.getStatusCode()) {
+            Response response = super.check();
+            if (response.getStatus() != Response.Status.OK.getStatusCode()) {
+                responseContext.setStatus(response.getStatus());
+                responseContext.setEntity(response.getEntity());
+            }
+        }
+    }
+}
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ServletTest.java b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ServletTest.java
new file mode 100644
index 0000000..c3a77c7
--- /dev/null
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ServletTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2022 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.cdi.inject;
+
+import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory;
+import org.glassfish.jersey.servlet.ServletProperties;
+import org.glassfish.jersey.test.DeploymentContext;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.ServletDeploymentContext;
+import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
+import org.glassfish.jersey.test.spi.TestContainerException;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
+import org.jboss.weld.environment.se.Weld;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Response;
+
+public class ServletTest extends JerseyTest {
+    private Weld weld;
+
+    @Before
+    public void setup() {
+        Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy());
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        if (Hk2InjectionManagerFactory.isImmediateStrategy()) {
+            weld = new Weld();
+            weld.initialize();
+            super.setUp();
+        }
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (Hk2InjectionManagerFactory.isImmediateStrategy()) {
+            weld.shutdown();
+            super.tearDown();
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        return new ServletApplication();
+    }
+
+    @Override
+    protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
+        return new GrizzlyWebTestContainerFactory();
+    }
+
+    @Override
+    protected DeploymentContext configureDeployment() {
+        return ServletDeploymentContext.builder(configure())
+                .initParam(ServletProperties.JAXRS_APPLICATION_CLASS, ServletApplication.class.getName())
+                .build();
+    }
+
+    @Test
+    public void testServlet() {
+        try (Response response = target("servlet").request().header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) {
+            if (response.getStatus() != Response.Status.OK.getStatusCode()) {
+                System.out.println(response.readEntity(String.class));
+            }
+            Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
+        }
+    }
+
+    @Test
+    public void testServletExceptionMapper() {
+        try (Response response = target("servlet/exception").request()
+                .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) {
+            if (response.getStatus() != Response.Status.OK.getStatusCode()) {
+                System.out.println(response.readEntity(String.class));
+            }
+            Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
+        }
+    }
+
+}