Enable to use @Context in constructors of classes instantiated by CDI

Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/InjectionManager.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/InjectionManager.java
index 10e3e45..36fc610 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/InjectionManager.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/InjectionManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2021 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
@@ -110,6 +110,17 @@
     boolean isRegistrable(Class<?> clazz);
 
     /**
+     * Creates an object with the given class.
+     * <p>
+     * The object created is not managed by the injection manager.
+     *
+     * @param createMe The non-null class to create this object from;
+     * @return An instance of the object that has been created.
+     * @since 2.35
+     */
+    <T> T create(Class<T> createMe);
+
+    /**
      * Creates, injects and post-constructs an object with the given class. This is equivalent to calling the
      * {@code create-class} method followed by the {@code inject-class} method followed by the {@code post-construct} method.
      * <p>
diff --git a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/AbstractCdiBeanSupplier.java b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/AbstractCdiBeanSupplier.java
index 5bea827..b681a2c 100644
--- a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/AbstractCdiBeanSupplier.java
+++ b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/AbstractCdiBeanSupplier.java
@@ -85,7 +85,7 @@
             @Override
             public T getInstance(final Class<T> clazz) {
                 final CreationalContext<T> creationalContext = beanManager.createCreationalContext(null);
-                final T instance = injectionTarget.produce(creationalContext);
+                final T instance = produce(injectionTarget, creationalContext, injectionManager, clazz);
                 final CdiComponentProvider cdiComponentProvider = beanManager.getExtension(CdiComponentProvider.class);
                 final CdiComponentProvider.InjectionManagerInjectedCdiTarget hk2managedTarget =
                      cdiComponentProvider.new InjectionManagerInjectedCdiTarget(injectionTarget) {
@@ -107,6 +107,18 @@
         };
     }
 
+    /*
+     * Let CDI produce the InjectionTarget. If the constructor contains @Context Args CDI won't be able to produce it.
+     * Let the HK2 try to produce the target then.
+     */
+    private static <T> T produce(InjectionTarget<T> target, CreationalContext<T> ctx, InjectionManager im, Class<T> clazz) {
+        try {
+            return target.produce(ctx);
+        } catch (Exception e) {
+            return im.create(clazz);
+        }
+    }
+
     @SuppressWarnings(value = "unchecked")
     /* package */ T _provide() {
         final T instance = referenceProvider.getInstance(clazz);
diff --git a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/CdiSeInjectionManager.java b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/CdiSeInjectionManager.java
index 7d1e88d..3096490 100644
--- a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/CdiSeInjectionManager.java
+++ b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/CdiSeInjectionManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2021 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
@@ -116,6 +116,23 @@
     }
 
     @Override
+    public <T> T create(Class<T> createMe) {
+        if (isInitialized()) {
+            Unmanaged.UnmanagedInstance<T> unmanaged = new Unmanaged<>(createMe).newInstance();
+            return unmanaged.produce().get();
+        } else {
+            // TODO: method is invoked before #completeRegistration - creates AutoDiscoverable, ForcedAutoDiscoverable.
+            // Hack: creates an object with default constructor and without an injection.
+            try {
+                Constructor<T> constructor = createMe.getConstructor();
+                return constructor.newInstance();
+            } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
+                throw new RuntimeException("Cannot create an instance of a class: " + createMe, e);
+            }
+        }
+    }
+
+    @Override
     @SuppressWarnings("unchecked")
     public <T> List<ServiceHolder<T>> getAllServiceHolders(Class<T> contractOrImpl, Annotation... qualifiers) {
         List<ServiceHolder<T>> result = new ArrayList<>();
diff --git a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/AbstractHk2InjectionManager.java b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/AbstractHk2InjectionManager.java
index 543f662..5a71084 100644
--- a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/AbstractHk2InjectionManager.java
+++ b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/AbstractHk2InjectionManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2021 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
@@ -185,6 +185,11 @@
     }
 
     @Override
+    public <U> U create(Class<U> clazz) {
+        return getServiceLocator().create(clazz);
+    }
+
+    @Override
     public <U> U createAndInitialize(Class<U> clazz) {
         return getServiceLocator().createAndInitialize(clazz);
     }
diff --git a/tests/integration/cdi-integration/cdi-resource-with-at-context/pom.xml b/tests/integration/cdi-integration/cdi-resource-with-at-context/pom.xml
new file mode 100644
index 0000000..aaf101f
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-resource-with-at-context/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2021 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
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.glassfish.jersey.tests.integration.cdi</groupId>
+        <artifactId>cdi-integration-project</artifactId>
+        <version>2.35-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>cdi-resource-with-at-context</artifactId>
+
+    <name>jersey-tests-resource-with-at-context</name>
+
+    <description>CDI works for a resource class with constructor with @Context</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>jakarta.ws.rs</groupId>
+            <artifactId>jakarta.ws.rs-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.annotation</groupId>
+            <artifactId>jakarta.annotation-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.enterprise</groupId>
+            <artifactId>cdi-api</artifactId>
+            <version>2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <version>${servlet4.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-weld2-se</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.weld.se</groupId>
+            <artifactId>weld-se-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-cdi1x</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-cdi-rs-inject</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-sse</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet-core</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/java/org/glassfish/jersey/tests/cdi/resourceatcontext/App.java b/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/java/org/glassfish/jersey/tests/cdi/resourceatcontext/App.java
new file mode 100644
index 0000000..c93cc61
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/java/org/glassfish/jersey/tests/cdi/resourceatcontext/App.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2021 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.resourceatcontext;
+
+import org.glassfish.jersey.server.ResourceConfig;
+
+public class App extends ResourceConfig {
+    public App() {
+           register(ResourceWithConstructor.class);
+    }
+}
diff --git a/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/java/org/glassfish/jersey/tests/cdi/resourceatcontext/ResourceWithConstructor.java b/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/java/org/glassfish/jersey/tests/cdi/resourceatcontext/ResourceWithConstructor.java
new file mode 100644
index 0000000..609b998
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/java/org/glassfish/jersey/tests/cdi/resourceatcontext/ResourceWithConstructor.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021 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.resourceatcontext;
+
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+
+@Path("/")
+public class ResourceWithConstructor {
+    HttpHeaders headers;
+
+    @Inject
+    BeanManager beanManager;
+
+    public ResourceWithConstructor(@Context HttpHeaders headers) {
+        this.headers = headers;
+    }
+
+    @GET
+    @Path("get")
+    public String get() {
+        return headers != null && beanManager != null ? "OK" : "NOK";
+    }
+}
diff --git a/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/resources/META-INF/beans.xml b/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..9ad6922
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-resource-with-at-context/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2021 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
+
+-->
+
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+	   http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+       bean-discovery-mode="none">
+</beans>
diff --git a/tests/integration/cdi-integration/cdi-resource-with-at-context/src/test/java/org/glassfish/jersey/tests/cdi/resourceatcontext/ResourceWithConstructorTest.java b/tests/integration/cdi-integration/cdi-resource-with-at-context/src/test/java/org/glassfish/jersey/tests/cdi/resourceatcontext/ResourceWithConstructorTest.java
new file mode 100644
index 0000000..ace3e0b
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-resource-with-at-context/src/test/java/org/glassfish/jersey/tests/cdi/resourceatcontext/ResourceWithConstructorTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2021 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.resourceatcontext;
+
+import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+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.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+public class ResourceWithConstructorTest 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 App();
+    }
+
+    @Override
+    protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
+        return new GrizzlyWebTestContainerFactory();
+    }
+
+    @Override
+    protected DeploymentContext configureDeployment() {
+        return ServletDeploymentContext.builder(configure())
+                .initParam(ServletProperties.JAXRS_APPLICATION_CLASS, App.class.getName())
+                .build();
+    }
+
+    @Test
+    public void testContextInConstructorAndInjectInClass() throws InterruptedException {
+        try (Response r = target().path("get").request().get()) {
+            Assert.assertEquals("OK", r.readEntity(String.class));
+        }
+    }
+}
diff --git a/tests/integration/cdi-integration/pom.xml b/tests/integration/cdi-integration/pom.xml
index 8de0c3f..9f7719d 100644
--- a/tests/integration/cdi-integration/pom.xml
+++ b/tests/integration/cdi-integration/pom.xml
@@ -41,6 +41,7 @@
         <module>cdi-log-check</module>
         <module>cdi-multimodule</module>
         <module>cdi-multipart-webapp</module>
+        <module>cdi-resource-with-at-context</module>
         <module>cdi-test-webapp</module>
         <module>cdi-with-jersey-injection-custom-cfg-webapp</module>
         <module>cdi-with-jersey-injection-custom-hk2-banned-webapp</module>