JdkHttpHandlerContainer: Allow injecting HttpExchange by providing container-specific binder

Signed-off-by: Matthias Van der Hallen <matthias.vanderhallen@gmail.com>
diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java
index d1ebf61..90c9998 100644
--- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java
+++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 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
@@ -29,14 +29,21 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.inject.Inject;
+import javax.inject.Provider;
 import javax.ws.rs.core.Application;
+import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriBuilder;
 
 import org.glassfish.jersey.internal.MapPropertiesDelegate;
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.ReferencingFactory;
+import org.glassfish.jersey.internal.util.collection.Ref;
 import org.glassfish.jersey.jdkhttp.internal.LocalizationMessages;
+import org.glassfish.jersey.process.internal.RequestScoped;
 import org.glassfish.jersey.server.ApplicationHandler;
 import org.glassfish.jersey.server.ContainerException;
 import org.glassfish.jersey.server.ContainerRequest;
@@ -60,6 +67,7 @@
 public class JdkHttpHandlerContainer implements HttpHandler, Container {
 
     private static final Logger LOGGER = Logger.getLogger(JdkHttpHandlerContainer.class.getName());
+    private static final GenericType<Ref<HttpExchange>> httpExchangeType = new GenericType<Ref<HttpExchange>>() {};
 
     private volatile ApplicationHandler appHandler;
 
@@ -69,7 +77,7 @@
      * @param application JAX-RS / Jersey application to be deployed on the container.
      */
     JdkHttpHandlerContainer(final Application application) {
-        this.appHandler = new ApplicationHandler(application);
+        this(application, null);
     }
 
     /**
@@ -79,7 +87,7 @@
      * @param parentContext DI provider specific context with application's registered bindings.
      */
     JdkHttpHandlerContainer(final Application application, final Object parentContext) {
-        this.appHandler = new ApplicationHandler(application, null, parentContext);
+        this.appHandler = new ApplicationHandler(application, new JdkBinder(), parentContext);
     }
 
     @Override
@@ -131,6 +139,9 @@
         requestContext.setEntityStream(exchange.getRequestBody());
         requestContext.getHeaders().putAll(exchange.getRequestHeaders());
         requestContext.setWriter(responseWriter);
+        requestContext.setRequestScopedInitializer((injectionManager) -> {
+            injectionManager.<Ref<HttpExchange>>getInstance(httpExchangeType.getType()).set(exchange);
+        });
         try {
             appHandler.handle(requestContext);
         } finally {
@@ -208,7 +219,7 @@
     public void reload(final ResourceConfig configuration) {
         appHandler.onShutdown(this);
 
-        appHandler = new ApplicationHandler(configuration);
+        appHandler = new ApplicationHandler(configuration, new JdkBinder());
         appHandler.onReload(this);
         appHandler.onStartup(this);
     }
@@ -236,6 +247,24 @@
         this.appHandler.onShutdown(this);
     }
 
+    private static class JdkBinder extends AbstractBinder {
+        @Override
+        protected void configure() {
+            bindFactory(ReferencingFactory.<HttpExchange>referenceFactory()).to(httpExchangeType)
+                                                                              .in(RequestScoped.class);
+            bindFactory(HttpExchangeReferencingFactory.class).to(HttpExchange.class)
+                                                              .proxy(false).in(RequestScoped.class);
+        }
+    }
+
+    private static class HttpExchangeReferencingFactory
+        extends ReferencingFactory<HttpExchange> {
+        @Inject
+        public HttpExchangeReferencingFactory(final Provider<Ref<HttpExchange>> referenceFactory) {
+            super(referenceFactory);
+        }
+    }
+
     private static final class ResponseWriter implements ContainerResponseWriter {
 
         private final HttpExchange exchange;