diff --git a/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsService.java b/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsService.java
index e003b25985c..a6140a5063d 100644
--- a/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsService.java
+++ b/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 Oracle and/or its affiliates.
+ * Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -184,7 +184,14 @@ private static URI baseUri(ServerRequest req) {
}
private void handle(ServerRequest req, ServerResponse res) {
- Contexts.runInContext(req.context(), () -> doHandle(req.context(), req, res));
+ Context context = req.context();
+
+ // make these available in context for ServerCdiExtension
+ context.supply(ServerRequest.class, () -> req);
+ context.supply(ServerResponse.class, () -> res);
+
+ // call doHandle in active context
+ Contexts.runInContext(context, () -> doHandle(context, req, res));
}
private void doHandle(Context ctx, ServerRequest req, ServerResponse res) {
diff --git a/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java b/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java
index 4aa7d73f1ef..3d9785e148b 100644
--- a/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java
+++ b/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java
@@ -43,14 +43,21 @@
import io.helidon.nima.webserver.context.ContextFeature;
import io.helidon.nima.webserver.http.HttpRouting;
import io.helidon.nima.webserver.http.HttpService;
+import io.helidon.nima.webserver.http.ServerRequest;
+import io.helidon.nima.webserver.http.ServerResponse;
import io.helidon.nima.webserver.staticcontent.StaticContentService;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.BeforeDestroyed;
import jakarta.enterprise.context.Initialized;
+import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.event.Observes;
+import jakarta.enterprise.inject.Any;
+import jakarta.enterprise.inject.CreationException;
+import jakarta.enterprise.inject.Default;
+import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.CDI;
@@ -361,6 +368,27 @@ private void startServer(@Observes @Priority(PLATFORM_AFTER + 100) @Initialized(
STARTUP_LOGGER.log(Level.TRACE, "Server created");
}
+ /**
+ * Make Nima's {@code ServerRequest} and {@code ServerResponse} available for injection
+ * via CDI by registering them as beans.
+ *
+ * @param event after bean discovery event
+ */
+ private void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {
+ event.addBean()
+ .qualifiers(Set.of(Default.Literal.INSTANCE, Any.Literal.INSTANCE))
+ .addTransitiveTypeClosure(ServerRequest.class)
+ .scope(RequestScoped.class)
+ .createWith(cc -> Contexts.context().flatMap(c -> c.get(ServerRequest.class))
+ .orElseThrow(() -> new CreationException("Unable to retrieve ServerRequest from context")));
+ event.addBean()
+ .qualifiers(Set.of(Default.Literal.INSTANCE, Any.Literal.INSTANCE))
+ .addTransitiveTypeClosure(ServerResponse.class)
+ .scope(RequestScoped.class)
+ .createWith(cc -> Contexts.context().flatMap(c -> c.get(ServerResponse.class))
+ .orElseThrow(() -> new CreationException("Unable to retrieve ServerResponse from context")));
+ }
+
private void registerJaxRsApplications(BeanManager beanManager) {
JaxRsCdiExtension jaxRs = beanManager.getExtension(JaxRsCdiExtension.class);
diff --git a/tests/functional/pom.xml b/tests/functional/pom.xml
index 2912264af02..e224578e232 100644
--- a/tests/functional/pom.xml
+++ b/tests/functional/pom.xml
@@ -42,6 +42,7 @@
mp-compression
request-scope
request-scope-cdi
+ request-scope-injection
jax-rs-multiple-apps
param-converter-provider
config-profiles
diff --git a/tests/functional/request-scope-injection/pom.xml b/tests/functional/request-scope-injection/pom.xml
new file mode 100644
index 00000000000..154d98e8846
--- /dev/null
+++ b/tests/functional/request-scope-injection/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+
+ 4.0.0
+
+ helidon-tests-functional-project
+ io.helidon.tests.functional
+ 4.0.0-SNAPSHOT
+
+
+ helidon-tests-functional-request-scope-injection
+ Helidon Functional Test: Helidon Request Scope Injection
+
+
+
+ io.helidon.microprofile.bundles
+ helidon-microprofile-core
+
+
+ io.helidon.config
+ helidon-config-yaml
+
+
+ io.helidon.microprofile.tests
+ helidon-microprofile-tests-junit5
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+
diff --git a/tests/functional/request-scope-injection/src/main/java/io/helidon/tests/functional/context/injection/CheckInjectionResource.java b/tests/functional/request-scope-injection/src/main/java/io/helidon/tests/functional/context/injection/CheckInjectionResource.java
new file mode 100644
index 00000000000..d85f9d3abb5
--- /dev/null
+++ b/tests/functional/request-scope-injection/src/main/java/io/helidon/tests/functional/context/injection/CheckInjectionResource.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.tests.functional.context.injection;
+
+import java.util.Objects;
+
+import io.helidon.nima.webserver.http.ServerRequest;
+import io.helidon.nima.webserver.http.ServerResponse;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Response;
+
+/**
+ * Verifies that {@code ServerRequest} and {@code ServerResponse} are injectable
+ * both via {@code @Context} and {@code @Inject}.
+ */
+@Path("/check")
+public class CheckInjectionResource {
+
+ @Context
+ private ServerRequest serverRequest;
+
+ @Context
+ private ServerResponse serverResponse;
+
+ @Inject
+ private ServerRequest serverRequestCdi;
+
+ @Inject
+ private ServerResponse serverResponseCdi;
+
+ @GET
+ public Response checkInjection() {
+ Objects.requireNonNull(serverRequest);
+ Objects.requireNonNull(serverResponse);
+ Objects.requireNonNull(serverRequestCdi);
+ Objects.requireNonNull(serverResponseCdi);
+ if (!serverRequestCdi.path().equals(serverRequest.path())
+ || !serverResponseCdi.status().equals(serverResponse.status())) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+ }
+ return Response.ok().build();
+ }
+}
diff --git a/tests/functional/request-scope-injection/src/main/java/io/helidon/tests/functional/context/injection/package-info.java b/tests/functional/request-scope-injection/src/main/java/io/helidon/tests/functional/context/injection/package-info.java
new file mode 100644
index 00000000000..a597378ffd6
--- /dev/null
+++ b/tests/functional/request-scope-injection/src/main/java/io/helidon/tests/functional/context/injection/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Simple app to verify injection of {@code ServerRequest} and {@code ServerResponse}.
+ */
+package io.helidon.tests.functional.context.injection;
diff --git a/tests/functional/request-scope-injection/src/main/resources/META-INF/beans.xml b/tests/functional/request-scope-injection/src/main/resources/META-INF/beans.xml
new file mode 100644
index 00000000000..cf179d28185
--- /dev/null
+++ b/tests/functional/request-scope-injection/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/tests/functional/request-scope-injection/src/test/java/io/helidon/tests/functional/context/injection/CheckInjectionTest.java b/tests/functional/request-scope-injection/src/test/java/io/helidon/tests/functional/context/injection/CheckInjectionTest.java
new file mode 100644
index 00000000000..d29e2383545
--- /dev/null
+++ b/tests/functional/request-scope-injection/src/test/java/io/helidon/tests/functional/context/injection/CheckInjectionTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.tests.functional.context.injection;
+
+import io.helidon.microprofile.tests.junit5.HelidonTest;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.client.WebTarget;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * Unit test for {@link CheckInjectionResource}.
+ */
+@HelidonTest
+class CheckInjectionTest {
+
+ private final WebTarget baseTarget;
+
+ @Inject
+ CheckInjectionTest(WebTarget baseTarget) {
+ this.baseTarget = baseTarget;
+ }
+
+ @Test
+ void testCheckInjection() {
+ WebTarget target = baseTarget.path("/check");
+ assertThat(target.request().get().getStatus(), is(200));
+ }
+}
\ No newline at end of file
diff --git a/tests/functional/request-scope-injection/src/test/resources/logging.properties b/tests/functional/request-scope-injection/src/test/resources/logging.properties
new file mode 100644
index 00000000000..2f5fd9c9515
--- /dev/null
+++ b/tests/functional/request-scope-injection/src/test/resources/logging.properties
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2023 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Example Logging Configuration File
+# For more information see $JAVA_HOME/jre/lib/logging.properties
+
+# Send messages to the console
+handlers=io.helidon.logging.jul.HelidonConsoleHandler
+
+# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread
+java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
+
+# Global logging level. Can be overridden by specific loggers
+.level=INFO
+
+# Component specific log levels
+AUDIT.level=FINEST