merge of the actual 2.x into the 3.0
diff --git a/NOTICE.md b/NOTICE.md
index 3596992..2818e63 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -70,7 +70,7 @@
* Project: http://www.javassist.org/
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
-Jackson JAX-RS Providers Version 2.17.0
+Jackson JAX-RS Providers Version 2.17.1
* License: Apache License, 2.0
* Project: https://github.com/FasterXML/jackson-jaxrs-providers
* Copyright: (c) 2009-2024 FasterXML, LLC. All rights reserved unless otherwise indicated.
diff --git a/archetypes/jersey-example-java8-webapp/src/main/resources/archetype-resources/pom.xml b/archetypes/jersey-example-java8-webapp/src/main/resources/archetype-resources/pom.xml
index dc88fe1..af777dd 100644
--- a/archetypes/jersey-example-java8-webapp/src/main/resources/archetype-resources/pom.xml
+++ b/archetypes/jersey-example-java8-webapp/src/main/resources/archetype-resources/pom.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2015, 2024 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
@@ -127,6 +127,5 @@
<properties>
<java.version>1.8</java.version>
<jersey.config.test.container.port>8080</jersey.config.test.container.port>
- <war.mvn.plugin.version>3.4.0</war.mvn.plugin.version>
</properties>
</project>
diff --git a/archetypes/jersey-heroku-webapp/pom.xml b/archetypes/jersey-heroku-webapp/pom.xml
index 176eefd..a3b4e18 100644
--- a/archetypes/jersey-heroku-webapp/pom.xml
+++ b/archetypes/jersey-heroku-webapp/pom.xml
@@ -37,7 +37,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
- <version>2.5</version>
+ <version>${resources.mvn.plugin.version}</version>
<configuration>
<escapeString>\</escapeString>
</configuration>
diff --git a/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/pom.xml b/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/pom.xml
index 00afb9c..3afa9e3 100644
--- a/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/pom.xml
+++ b/archetypes/jersey-heroku-webapp/src/main/resources/archetype-resources/pom.xml
@@ -64,7 +64,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.8.1</version>
+ <version>${compiler.mvn.plugin.version}</version>
<inherited>true</inherited>
<configuration>
<source>11</source>
@@ -117,9 +117,6 @@
<properties>
<jersey.version>${project.version}</jersey.version>
- <jetty.version>11.0.20</jetty.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <surefire.mvn.plugin.version>3.2.5</surefire.mvn.plugin.version>
- <war.mvn.plugin.version>3.4.0</war.mvn.plugin.version>
</properties>
</project>
diff --git a/archetypes/jersey-quickstart-grizzly2/pom.xml b/archetypes/jersey-quickstart-grizzly2/pom.xml
index c777ef4..b0a9775 100644
--- a/archetypes/jersey-quickstart-grizzly2/pom.xml
+++ b/archetypes/jersey-quickstart-grizzly2/pom.xml
@@ -45,7 +45,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
- <version>2.5</version>
+ <version>${resources.mvn.plugin.version}</version>
<configuration>
<escapeString>\</escapeString>
</configuration>
diff --git a/archetypes/jersey-quickstart-grizzly2/src/main/resources/META-INF/archetype.xml b/archetypes/jersey-quickstart-grizzly2/src/main/resources/META-INF/archetype.xml
deleted file mode 100644
index 8a4f997..0000000
--- a/archetypes/jersey-quickstart-grizzly2/src/main/resources/META-INF/archetype.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright (c) 2010, 2018 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
-
--->
-
-<archetype>
- <id>jersey-quickstart-grizzly2</id>
- <sources>
- <source>src/main/java/Main.java</source>
- <source>src/main/java/MyResource.java</source>
- </sources>
- <testSources>
- <source>src/test/java/MyResourceTest.java</source>
- </testSources>
-</archetype>
diff --git a/archetypes/jersey-quickstart-grizzly2/src/main/resources/META-INF/maven/archetype-metadata.xml b/archetypes/jersey-quickstart-grizzly2/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644
index 0000000..54380e5
--- /dev/null
+++ b/archetypes/jersey-quickstart-grizzly2/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright (c) 2024 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
+
+-->
+
+<archetype-descriptor
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
+ name="jersey-quickstart-webapp"
+ xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <fileSets>
+ <fileSet filtered="true" packaged="true" encoding="UTF-8">
+ <directory>src/main/java</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
+ <!--<fileSet filtered="true" encoding="UTF-8">
+ <directory>src/main/webapp</directory>
+ </fileSet>-->
+ <fileSet filtered="true" packaged="true" encoding="UTF-8">
+ <directory>src/test/java</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</archetype-descriptor>
\ No newline at end of file
diff --git a/archetypes/jersey-quickstart-grizzly2/src/main/resources/archetype-resources/pom.xml b/archetypes/jersey-quickstart-grizzly2/src/main/resources/archetype-resources/pom.xml
index 779f080..087417f 100644
--- a/archetypes/jersey-quickstart-grizzly2/src/main/resources/archetype-resources/pom.xml
+++ b/archetypes/jersey-quickstart-grizzly2/src/main/resources/archetype-resources/pom.xml
@@ -40,7 +40,7 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
- <version>\${junit-jupiter.version}</version>
+ <version>\${junit5.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -50,7 +50,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.8.1</version>
+ <version>${compiler.mvn.plugin.version}</version>
<inherited>true</inherited>
<configuration>
<source>1.8</source>
@@ -60,7 +60,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
- <version>1.2.1</version>
+ <version>${exec.mvn.plugin.version}</version>
<executions>
<execution>
<goals>
@@ -83,8 +83,7 @@
<properties>
<jersey.version>${project.version}</jersey.version>
- <junit-jupiter.version>5.10.2</junit-jupiter.version>
+ <junit5.version>${junit5.version}</junit5.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <surefire.mvn.plugin.version>3.2.5</surefire.mvn.plugin.version>
</properties>
</project>
diff --git a/archetypes/jersey-quickstart-webapp/pom.xml b/archetypes/jersey-quickstart-webapp/pom.xml
index 33b1eca..32e2969 100644
--- a/archetypes/jersey-quickstart-webapp/pom.xml
+++ b/archetypes/jersey-quickstart-webapp/pom.xml
@@ -36,7 +36,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
- <version>2.5</version>
+ <version>${resources.mvn.plugin.version}</version>
<configuration>
<escapeString>\</escapeString>
</configuration>
diff --git a/archetypes/jersey-quickstart-webapp/src/main/resources/META-INF/archetype.xml b/archetypes/jersey-quickstart-webapp/src/main/resources/META-INF/archetype.xml
deleted file mode 100644
index cea1eea..0000000
--- a/archetypes/jersey-quickstart-webapp/src/main/resources/META-INF/archetype.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright (c) 2010, 2018 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
-
--->
-
-<archetype>
- <id>jersey-quickstart-webapp</id>
- <sources>
- <source>src/main/java/MyResource.java</source>
- </sources>
- <resources>
- <resource>src/main/webapp/index.jsp</resource>
- <resource>src/main/webapp/WEB-INF/web.xml</resource>
- </resources>
-</archetype>
diff --git a/archetypes/jersey-quickstart-webapp/src/main/resources/META-INF/maven/archetype-metadata.xml b/archetypes/jersey-quickstart-webapp/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644
index 0000000..bea65b3
--- /dev/null
+++ b/archetypes/jersey-quickstart-webapp/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright (c) 2024 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
+
+-->
+
+<archetype-descriptor
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
+ name="jersey-quickstart-webapp"
+ xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <fileSets>
+ <fileSet filtered="true" packaged="true" encoding="UTF-8">
+ <directory>src/main/java</directory>
+ </fileSet>
+ <fileSet filtered="true" encoding="UTF-8">
+ <directory>src/main/webapp</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
+ <fileSet filtered="true" packaged="true" encoding="UTF-8">
+ <directory>src/test/java</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</archetype-descriptor>
\ No newline at end of file
diff --git a/archetypes/jersey-quickstart-webapp/src/main/resources/archetype-resources/pom.xml b/archetypes/jersey-quickstart-webapp/src/main/resources/archetype-resources/pom.xml
index fc70d51..341fb67 100644
--- a/archetypes/jersey-quickstart-webapp/src/main/resources/archetype-resources/pom.xml
+++ b/archetypes/jersey-quickstart-webapp/src/main/resources/archetype-resources/pom.xml
@@ -15,7 +15,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.8.1</version>
+ <version>${compiler.mvn.plugin.version}</version>
<inherited>true</inherited>
<configuration>
<source>1.8</source>
@@ -63,6 +63,5 @@
<properties>
<jersey.version>${project.version}</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <war.mvn.plugin.version>3.4.0</war.mvn.plugin.version>
</properties>
</project>
diff --git a/bundles/apidocs/pom.xml b/bundles/apidocs/pom.xml
index 709d10c..b7c9921 100644
--- a/bundles/apidocs/pom.xml
+++ b/bundles/apidocs/pom.xml
@@ -125,7 +125,7 @@
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.servlet</artifactId>
- <version>3.1</version>
+ <version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
diff --git a/bundles/jaxrs-ri/pom.xml b/bundles/jaxrs-ri/pom.xml
index d3eb536..e6a7a7f 100644
--- a/bundles/jaxrs-ri/pom.xml
+++ b/bundles/jaxrs-ri/pom.xml
@@ -424,7 +424,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
- <version>1.0-beta-4</version>
+ <version>2.0.2</version>
<inherited>false</inherited>
<executions>
<execution>
diff --git a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
index d53401e..dd3c4c4 100644
--- a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
+++ b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
@@ -60,6 +60,7 @@
import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
import org.glassfish.jersey.client.spi.Connector;
+import org.glassfish.jersey.innate.io.InputStreamWrapper;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.message.internal.HeaderUtils;
import org.glassfish.jersey.message.internal.OutboundMessageContext;
@@ -890,7 +891,7 @@
}
}
- private static class CancellableInputStream extends InputStream {
+ private static class CancellableInputStream extends InputStreamWrapper {
private final InputStream in;
private final Supplier<Boolean> isCancelled;
@@ -899,58 +900,17 @@
this.isCancelled = isCancelled;
}
- public int read(byte b[]) throws IOException {
- checkAborted();
- return in.read();
- }
-
- public int read(byte b[], int off, int len) throws IOException {
- checkAborted();
- return in.read(b, off, len);
+ @Override
+ protected InputStream getWrapped() {
+ return in;
}
@Override
- public int read() throws IOException {
- checkAborted();
- return in.read();
- }
-
- public boolean markSupported() {
- return in.markSupported();
- }
-
- @Override
- public long skip(long n) throws IOException {
- checkAborted();
- return in.skip(n);
- }
-
- @Override
- public int available() throws IOException {
- checkAborted();
- return in.available();
- }
-
- @Override
- public void close() throws IOException {
- in.close();
- }
-
- @Override
- public void mark(int readlimit) {
- in.mark(readlimit);
- }
-
- @Override
- public void reset() throws IOException {
- checkAborted();
- in.reset();
- }
-
- private void checkAborted() throws IOException {
+ protected InputStream getWrappedIOE() throws IOException {
if (isCancelled.get()) {
throw new IOException(new CancellationException());
}
+ return in;
}
}
}
diff --git a/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java b/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
index 56f8dd5..d797f11 100644
--- a/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
+++ b/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
@@ -105,6 +105,7 @@
import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
import org.glassfish.jersey.client.spi.Connector;
+import org.glassfish.jersey.innate.io.InputStreamWrapper;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.message.internal.HeaderUtils;
import org.glassfish.jersey.message.internal.OutboundMessageContext;
@@ -521,7 +522,7 @@
final HttpEntity entity = response.getEntity();
if (entity != null) {
- if (headers.get(HttpHeaders.CONTENT_LENGTH) == null) {
+ if (headers.get(HttpHeaders.CONTENT_LENGTH) == null && entity.getContentLength() >= 0) {
headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(entity.getContentLength()));
}
@@ -894,7 +895,7 @@
}
}
- private static class CancellableInputStream extends InputStream {
+ private static class CancellableInputStream extends InputStreamWrapper {
private final InputStream in;
private final Supplier<Boolean> isCancelled;
@@ -903,58 +904,17 @@
this.isCancelled = isCancelled;
}
- public int read(byte b[]) throws IOException {
- checkAborted();
- return in.read();
- }
-
- public int read(byte b[], int off, int len) throws IOException {
- checkAborted();
- return in.read(b, off, len);
+ @Override
+ protected InputStream getWrapped() {
+ return in;
}
@Override
- public int read() throws IOException {
- checkAborted();
- return in.read();
- }
-
- public boolean markSupported() {
- return in.markSupported();
- }
-
- @Override
- public long skip(long n) throws IOException {
- checkAborted();
- return in.skip(n);
- }
-
- @Override
- public int available() throws IOException {
- checkAborted();
- return in.available();
- }
-
- @Override
- public void close() throws IOException {
- in.close();
- }
-
- @Override
- public void mark(int readlimit) {
- in.mark(readlimit);
- }
-
- @Override
- public void reset() throws IOException {
- checkAborted();
- in.reset();
- }
-
- private void checkAborted() throws IOException {
+ protected InputStream getWrappedIOE() throws IOException {
if (isCancelled.get()) {
throw new IOException(new CancellationException());
}
+ return in;
}
}
diff --git a/connectors/helidon-connector/pom.xml b/connectors/helidon-connector/pom.xml
index 515e3b3..8453f9b 100644
--- a/connectors/helidon-connector/pom.xml
+++ b/connectors/helidon-connector/pom.xml
@@ -42,7 +42,7 @@
<dependency>
<groupId>io.helidon.jersey</groupId>
<artifactId>helidon-jersey-connector</artifactId>
- <version>${helidon.jersey.connector.version}</version>
+ <version>${helidon.connector.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
index 4070300..6099e8e 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpParser.java
@@ -514,8 +514,15 @@
}
return;
+ } else if (httpResponse.getHasContent()) {
+ // missing Content-Length
+ transferEncodingParser = TransferEncodingParser
+ .createFixedLengthParser(httpResponse.getBodyStream(), Long.MAX_VALUE);
+ return;
}
+
+
// TODO what now? Expect no content or fail loudly?
}
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
index 7dccd87..1a94ff7 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/TransferEncodingParser.java
@@ -63,7 +63,7 @@
responseBody.notifyDataAvailable(parsed);
consumedLength += data.length;
- return consumedLength == expectedLength;
+ return consumedLength == expectedLength || expectedLength == Long.MAX_VALUE /* unknown at the beginning */;
}
}
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
index 5d1d2f2..adf8e03 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
@@ -99,6 +99,8 @@
if (readTimedOut) {
responseDone.completeExceptionally(new TimeoutException("Stream closed: read timeout"));
+ } else if (jerseyRequest.isCancelled()) {
+ responseDone.completeExceptionally(new CancellationException());
} else {
responseDone.completeExceptionally(new IOException("Stream closed"));
}
@@ -187,21 +189,10 @@
}
// request entity handling.
- if ((response.headers().contains(HttpHeaders.CONTENT_LENGTH) && HttpUtil.getContentLength(response) > 0)
- || HttpUtil.isTransferEncodingChunked(response)) {
+ nis = new NettyInputStream();
+ responseDone.whenComplete((_r, th) -> nis.complete(th));
- nis = new NettyInputStream();
- responseDone.whenComplete((_r, th) -> nis.complete(th));
-
- jerseyResponse.setEntityStream(nis);
- } else {
- jerseyResponse.setEntityStream(new InputStream() {
- @Override
- public int read() throws IOException {
- return -1;
- }
- });
- }
+ jerseyResponse.setEntityStream(nis);
}
if (msg instanceof HttpContent) {
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
index 4fbec4c..cec1348 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
@@ -89,6 +89,9 @@
import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
import org.glassfish.jersey.client.spi.Connector;
import org.glassfish.jersey.innate.VirtualThreadUtil;
+import org.glassfish.jersey.internal.util.collection.LazyValue;
+import org.glassfish.jersey.internal.util.collection.Value;
+import org.glassfish.jersey.internal.util.collection.Values;
import org.glassfish.jersey.message.internal.OutboundMessageContext;
import org.glassfish.jersey.netty.connector.internal.NettyEntityWriter;
@@ -104,6 +107,17 @@
final Client client;
final HashMap<String, ArrayList<Channel>> connections = new HashMap<>();
+ private static final LazyValue<String> NETTY_VERSION = Values.lazy(
+ (Value<String>) () -> {
+ String nettyVersion = null;
+ try {
+ nettyVersion = io.netty.util.Version.identify().values().iterator().next().artifactVersion();
+ } catch (Throwable t) {
+ nettyVersion = "4.1.x";
+ }
+ return "Netty " + nettyVersion;
+ });
+
// If HTTP keepalive is enabled the value of "http.maxConnections" determines the maximum number
// of idle connections that will be simultaneously kept alive, per destination.
private static final String HTTP_KEEPALIVE_STRING = System.getProperty("http.keepAlive");
@@ -525,7 +539,7 @@
@Override
public String getName() {
- return "Netty 4.1.x";
+ return NETTY_VERSION.get();
}
@Override
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/NettyEntityWriter.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/NettyEntityWriter.java
index a9e7040..bcd3fd8 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/NettyEntityWriter.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/NettyEntityWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 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
@@ -24,8 +24,10 @@
import java.io.IOException;
import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* The Entity Writer is used to write entity in Netty. One implementation is delayed,
@@ -196,10 +198,7 @@
for (Runnable runnable : delayedOps) {
runnable.run();
}
-
- if (outputStream.b != null) {
- writer.getOutputStream().write(outputStream.b, outputStream.off, outputStream.len);
- }
+ outputStream._flush();
}
}
@@ -216,7 +215,7 @@
@Override
public long getLength() {
- return outputStream.len - outputStream.off;
+ return outputStream.writeLen;
}
@Override
@@ -225,9 +224,9 @@
}
private class DelayedOutputStream extends OutputStream {
- private byte[] b;
- private int off;
- private int len;
+ private final List<WriteAction> actions = new ArrayList<>();
+ private int writeLen = 0;
+ private AtomicBoolean streamFlushed = new AtomicBoolean(false);
@Override
public void write(int b) throws IOException {
@@ -241,15 +240,39 @@
@Override
public void write(byte[] b, int off, int len) throws IOException {
- if (!flushed && this.b == null) {
- this.b = b;
- this.off = off;
- this.len = len;
+ if (!flushed) {
+ actions.add(new WriteAction(b, off, len));
+ writeLen += len;
} else {
- DelayedEntityWriter.this._flush();
+ _flush();
writer.getOutputStream().write(b, off, len);
+ writer.getOutputStream().flush();
}
}
+
+ public void _flush() throws IOException {
+ if (streamFlushed.compareAndSet(false, true)) {
+ DelayedEntityWriter.this._flush();
+ for (WriteAction action : actions) {
+ action.run();
+ }
+ actions.clear();
+ }
+ }
+ }
+
+ private class WriteAction {
+ private final byte[] b;
+
+ private WriteAction(byte[] b, int off, int len) {
+ this.b = new byte[len]; // b passed in can be reused
+ System.arraycopy(b, off, this.b, 0, len);
+ }
+
+ public void run() throws IOException {
+ writer.getOutputStream().write(b, 0, b.length);
+ writer.getOutputStream().flush();
+ }
}
}
}
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java
index 147ce8c..abde2ac 100644
--- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java
+++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java
@@ -318,13 +318,33 @@
final Response.Status badRequest = Response.Status.BAD_REQUEST;
if (webComponent.configSetStatusOverSendError) {
response.reset();
- //noinspection deprecation
- response.setStatus(badRequest.getStatusCode(), badRequest.getReasonPhrase());
+ setStatus(response, badRequest.getStatusCode(), badRequest.getReasonPhrase());
} else {
response.sendError(badRequest.getStatusCode(), badRequest.getReasonPhrase());
}
}
+ /**
+ * <p>
+ * Set status and reason-phrase if the API still contains the method. Otherwise, only a status is sent.
+ * </p>
+ * <p>
+ * It can happen the Servlet 6 API is used and the method is not there any longer. A proprietary API can be used,
+ * or the class is transformed to Jakarta using some transformer means.
+ * </p>
+ * @param response the servlet {@link HttpServletResponse}
+ * @param statusCode the status code
+ * @param reasonPhrase the reason phrase
+ */
+ public static void setStatus(HttpServletResponse response, int statusCode, String reasonPhrase) {
+ try {
+ // noinspection deprecation
+ response.setStatus(statusCode, reasonPhrase);
+ } catch (NoSuchMethodError noSuchMethodError) {
+ response.setStatus(statusCode);
+ }
+ }
+
@Override
public void destroy() {
super.destroy();
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
index 59b1da9..6e795f1 100644
--- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
+++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -17,6 +17,8 @@
package org.glassfish.jersey.servlet;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
import java.lang.reflect.Type;
import java.net.URI;
import java.security.AccessController;
@@ -54,6 +56,7 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import org.glassfish.jersey.innate.io.InputStreamWrapper;
import org.glassfish.jersey.internal.ServiceFinderBinder;
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.internal.inject.InjectionManager;
@@ -401,8 +404,7 @@
if (configSetStatusOverSendError) {
servletResponse.reset();
- //noinspection deprecation
- servletResponse.setStatus(status.getStatusCode(), status.getReasonPhrase());
+ ServletContainer.setStatus(servletResponse, status.getStatusCode(), status.getReasonPhrase());
} else {
servletResponse.sendError(status.getStatusCode(), status.getReasonPhrase());
}
@@ -413,7 +415,7 @@
}
/**
- * Initialize {@code ContainerRequest} instance to used used to handle {@code servletRequest}.
+ * Initialize {@code ContainerRequest} instance to used to handle {@code servletRequest}.
*/
private void initContainerRequest(
final ContainerRequest requestContext,
@@ -421,7 +423,21 @@
final HttpServletResponse servletResponse,
final ResponseWriter responseWriter) throws IOException {
- requestContext.setEntityStream(servletRequest.getInputStream());
+ try {
+ requestContext.setEntityStream(new InputStreamWrapper() {
+ @Override
+ protected InputStream getWrapped() {
+ try {
+ return servletRequest.getInputStream();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ });
+ } catch (UncheckedIOException e) {
+ throw e.getCause();
+ }
+
requestContext.setRequestScopedInitializer(requestScopedInitializer.get(new RequestContextProvider() {
@Override
public HttpServletRequest getHttpServletRequest() {
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java
index 31b8f93..5188a1a 100644
--- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java
+++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -37,6 +37,7 @@
import org.glassfish.jersey.server.ContainerResponse;
import org.glassfish.jersey.server.internal.JerseyRequestTimeoutHandler;
import org.glassfish.jersey.server.spi.ContainerResponseWriter;
+import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.spi.AsyncContextDelegate;
/**
@@ -144,7 +145,7 @@
final String reasonPhrase = responseContext.getStatusInfo().getReasonPhrase();
if (reasonPhrase != null) {
- response.setStatus(responseContext.getStatus(), reasonPhrase);
+ ServletContainer.setStatus(response, responseContext.getStatus(), reasonPhrase);
} else {
response.setStatus(responseContext.getStatus());
}
@@ -214,12 +215,12 @@
try {
if (!response.isCommitted()) {
try {
+ final int statusCode = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
if (configSetStatusOverSendError) {
response.reset();
- //noinspection deprecation
- response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), "Request failed.");
+ ServletContainer.setStatus(response, statusCode, "Request failed.");
} else {
- response.sendError(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), "Request failed.");
+ response.sendError(statusCode, "Request failed.");
}
} catch (final IllegalStateException ex) {
// a race condition externally committing the response can still occur...
diff --git a/containers/jersey-servlet-core/src/test/java/org/glassfish/jersey/servlet/internal/RequestInputStreamTest.java b/containers/jersey-servlet-core/src/test/java/org/glassfish/jersey/servlet/internal/RequestInputStreamTest.java
new file mode 100644
index 0000000..feb899c
--- /dev/null
+++ b/containers/jersey-servlet-core/src/test/java/org/glassfish/jersey/servlet/internal/RequestInputStreamTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2024 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.servlet.internal;
+
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.servlet.ServletProperties;
+import org.glassfish.jersey.servlet.WebComponent;
+import org.glassfish.jersey.servlet.WebConfig;
+import org.glassfish.jersey.servlet.WebFilterConfig;
+import org.junit.jupiter.api.Test;
+
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URI;
+import java.util.Collections;
+import java.util.Enumeration;
+
+public class RequestInputStreamTest {
+ @Test
+ public void test404RequestInputStream() throws ServletException, IOException {
+ InvocationHandler handler = new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ switch (method.getName()) {
+ case "getHeaderNames":
+ return Collections.emptyEnumeration();
+ case "getInputStream":
+ throw new IllegalStateException("ServletRequest#getInputStream clashes with ServletRequest#getReader");
+ }
+ return null;
+ }
+ };
+
+ FilterConfig filterConfig = new FilterConfig() {
+ @Override
+ public String getFilterName() {
+ return null;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return (ServletContext) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class[]{ServletContext.class},
+ handler);
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return null;
+ }
+ };
+ WebConfig dummyWebConfig = new WebFilterConfig(filterConfig);
+ ResourceConfig resourceConfig = new ResourceConfig()
+ .property(CommonProperties.PROVIDER_DEFAULT_DISABLE, "ALL")
+ .property(ServerProperties.WADL_FEATURE_DISABLE, true)
+ .property(ServletProperties.FILTER_FORWARD_ON_404, true)
+ .property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true);
+ WebComponent component = new WebComponent(dummyWebConfig, resourceConfig);
+ component.service(URI.create("http://localhost"), URI.create("http://localhost"),
+ (HttpServletRequest) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class[] {HttpServletRequest.class},
+ handler
+ ),
+ (HttpServletResponse) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class[]{HttpServletResponse.class},
+ handler)
+ );
+ }
+}
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 b5b28f3..ca73f4c 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
@@ -66,6 +66,7 @@
import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
import org.glassfish.jersey.client.spi.Connector;
import org.glassfish.jersey.internal.util.PropertiesHelper;
+import org.glassfish.jersey.internal.util.collection.LRU;
import org.glassfish.jersey.internal.util.collection.LazyValue;
import org.glassfish.jersey.internal.util.collection.UnsafeValue;
import org.glassfish.jersey.internal.util.collection.Value;
@@ -83,7 +84,7 @@
private static final String ALLOW_RESTRICTED_HEADERS_SYSTEM_PROPERTY = "sun.net.http.allowRestrictedHeaders";
// Avoid multi-thread uses of HttpsURLConnection.getDefaultSSLSocketFactory() because it does not implement a
// proper lazy-initialization. See https://github.com/jersey/jersey/issues/3293
- private static final LazyValue<SSLSocketFactory> DEFAULT_SSL_SOCKET_FACTORY =
+ private static final Value<SSLSocketFactory> DEFAULT_SSL_SOCKET_FACTORY =
Values.lazy((Value<SSLSocketFactory>) () -> HttpsURLConnection.getDefaultSSLSocketFactory());
// The list of restricted headers is extracted from sun.net.www.protocol.http.HttpURLConnection
private static final String[] restrictedHeaders = {
@@ -114,7 +115,12 @@
private final boolean fixLengthStreaming;
private final boolean setMethodWorkaround;
private final boolean isRestrictedHeaderPropertySet;
- private LazyValue<SSLSocketFactory> sslSocketFactory;
+ private Value<SSLSocketFactory> sslSocketFactory;
+
+ // SSLContext#getSocketFactory not idempotent
+ // JDK KeepAliveCache keeps connections per Factory
+ // SSLContext set per request blows that -> keep factory in LRU
+ private final LRU<SSLContext, SSLSocketFactory> sslSocketFactoryCache = LRU.create();
private final ConnectorExtension<HttpURLConnection, IOException> connectorExtension
= new HttpUrlExpect100ContinueConnectorExtension();
@@ -143,6 +149,13 @@
this.fixLengthStreaming = fixLengthStreaming;
this.setMethodWorkaround = setMethodWorkaround;
+ this.sslSocketFactory = Values.lazy(new Value<SSLSocketFactory>() {
+ @Override
+ public SSLSocketFactory get() {
+ return client.getSslContext().getSocketFactory();
+ }
+ });
+
// check if sun.net.http.allowRestrictedHeaders system property has been set and log the result
// the property is being cached in the HttpURLConnection, so this is only informative - there might
// already be some connection(s), that existed before the property was set/changed.
@@ -342,16 +355,23 @@
}
}
- private void setSslContextFactory(Client client, ClientRequest request) {
+ protected void setSslContextFactory(Client client, ClientRequest request) {
final Supplier<SSLContext> supplier = request.resolveProperty(ClientProperties.SSL_CONTEXT_SUPPLIER, Supplier.class);
- sslSocketFactory = Values.lazy(new Value<SSLSocketFactory>() {
- @Override
- public SSLSocketFactory get() {
- final SSLContext ctx = supplier == null ? client.getSslContext() : supplier.get();
- return ctx.getSocketFactory();
- }
- });
+ if (supplier != null) {
+ sslSocketFactory = Values.lazy(new Value<SSLSocketFactory>() { // lazy for double-check locking if multiple requests
+ @Override
+ public SSLSocketFactory get() {
+ SSLContext sslContext = supplier.get();
+ SSLSocketFactory factory = sslSocketFactoryCache.getIfPresent(sslContext);
+ if (factory == null) {
+ factory = sslContext.getSocketFactory();
+ sslSocketFactoryCache.put(sslContext, factory);
+ }
+ return factory;
+ }
+ });
+ }
}
private ClientResponse _apply(final ClientRequest request) throws IOException {
diff --git a/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties b/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
index 291ac98..8940d72 100644
--- a/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
+++ b/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2024 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
@@ -50,7 +50,7 @@
Reverting to programmatically set default: [{1}]
negative.input.parameter="Input parameter {0} must not be negative1."
noninject.ambiguous.services=Ambiguous providing services ${0}.
-noninject.fallback=Falling back to injection-less client.
+noninject.fallback=Jersey-HK2 module is missing. Falling back to injection-less client. Injection may not be supported on the client.
noninject.no.constructor=No applicable constructor for ${0} found.
noninject.no.binding=No binding found for ${0}.
noninject.requestscope.created=RequestScope already created.
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/SSLSocketFactoryTest.java b/core-client/src/test/java/org/glassfish/jersey/client/SSLSocketFactoryTest.java
new file mode 100644
index 0000000..362bbe6
--- /dev/null
+++ b/core-client/src/test/java/org/glassfish/jersey/client/SSLSocketFactoryTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2024 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.client;
+
+import org.glassfish.jersey.client.internal.HttpUrlConnector;
+import org.glassfish.jersey.client.spi.Connector;
+import org.glassfish.jersey.internal.MapPropertiesDelegate;
+import org.glassfish.jersey.internal.PropertiesDelegate;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.core.Response;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+public class SSLSocketFactoryTest {
+ static final AtomicReference<SSLSocketFactory> factoryHolder = new AtomicReference<>();
+ static SSLSocketFactory defaultSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
+
+ // @Test
+ // Alternative test
+ // Check KeepAliveCache#get(URL url, Object obj)
+ public void testSingleConnection() throws InterruptedException, IOException {
+ Client client = ClientBuilder.newClient();
+
+ for (int i = 0; i < 3; i++) {
+ try (Response response = client.target("https://www.spiegel.de")
+ .request()
+ .get()) {
+
+ response.readEntity(String.class);
+ System.out.println(String.format("response = %s", response));
+ Thread.sleep(1000);
+ }
+ }
+
+ System.in.read();
+ }
+
+ @Test
+ public void testSslContextFactoryOnClientIsSameForConsecutiveRequests() throws IOException, URISyntaxException {
+ int firstRequestFactory, secondRequestFactory = 0;
+ Client client = ClientBuilder.newClient();
+ HttpUrlConnectorProvider.ConnectionFactory connectionFactory = (url) -> (HttpURLConnection) url.openConnection();
+ SSLSocketFactoryConnector connector = (SSLSocketFactoryConnector) new SSlSocketFactoryUrlConnectorProvider()
+ .createHttpUrlConnector(client, connectionFactory, 4096, true, false);
+ URL url = new URL("https://somewhere.whereever:8080");
+ URLConnection urlConnection = url.openConnection();
+
+ // First Request
+ connector.setSslContextFactory(client, new ClientRequest(url.toURI(),
+ (ClientConfig) client.getConfiguration(), new MapPropertiesDelegate()));
+ connector.secureConnection((JerseyClient) client, (HttpURLConnection) urlConnection);
+ firstRequestFactory = factoryHolder.get().hashCode();
+
+ // reset to the default socketFactory
+ ((HttpsURLConnection) urlConnection).setSSLSocketFactory(defaultSocketFactory);
+
+ // Second Request
+ connector.setSslContextFactory(client, new ClientRequest(url.toURI(),
+ (ClientConfig) client.getConfiguration(), new MapPropertiesDelegate()));
+ connector.secureConnection((JerseyClient) client, (HttpURLConnection) urlConnection);
+ secondRequestFactory = factoryHolder.get().hashCode();
+
+ MatcherAssert.assertThat(firstRequestFactory, Matchers.equalTo(secondRequestFactory));
+ }
+
+ @Test
+ public void testSslContextFactoryOnRequestIsSameForConsecutiveRequests() throws IOException, URISyntaxException {
+ SSLSocketFactory firstRequestFactory, secondRequestFactory = null;
+ Client client = ClientBuilder.newClient();
+ SSLContext sslContext = new SslContextClientBuilder().build();
+ HttpUrlConnectorProvider.ConnectionFactory connectionFactory = (url) -> (HttpURLConnection) url.openConnection();
+ SSLSocketFactoryConnector connector = (SSLSocketFactoryConnector) new SSlSocketFactoryUrlConnectorProvider()
+ .createHttpUrlConnector(client, connectionFactory, 4096, true, false);
+ URL url = new URL("https://somewhere.whereever:8080");
+ URLConnection urlConnection = url.openConnection();
+ PropertiesDelegate propertiesDelegate = new MapPropertiesDelegate();
+ propertiesDelegate.setProperty(ClientProperties.SSL_CONTEXT_SUPPLIER, (Supplier<SSLContext>) () -> sslContext);
+
+ // First Request
+ connector.setSslContextFactory(client, new ClientRequest(url.toURI(),
+ (ClientConfig) client.getConfiguration(), propertiesDelegate));
+ connector.secureConnection((JerseyClient) client, (HttpURLConnection) urlConnection);
+ firstRequestFactory = factoryHolder.get();
+
+ // reset to the default socketFactory
+ ((HttpsURLConnection) urlConnection).setSSLSocketFactory(defaultSocketFactory);
+
+ // Second Request
+ connector.setSslContextFactory(client, new ClientRequest(url.toURI(),
+ (ClientConfig) client.getConfiguration(), propertiesDelegate));
+ connector.secureConnection((JerseyClient) client, (HttpURLConnection) urlConnection);
+ secondRequestFactory = factoryHolder.get();
+
+ MatcherAssert.assertThat(firstRequestFactory, Matchers.equalTo(secondRequestFactory));
+ }
+
+ private static class SSLSocketFactoryConnector extends HttpUrlConnector {
+ public SSLSocketFactoryConnector(Client client, HttpUrlConnectorProvider.ConnectionFactory connectionFactory,
+ int chunkSize, boolean fixLengthStreaming, boolean setMethodWorkaround) {
+ super(client, connectionFactory, chunkSize, fixLengthStreaming, setMethodWorkaround);
+ }
+
+ @Override
+ protected void secureConnection(JerseyClient client, HttpURLConnection uc) {
+ super.secureConnection(client, uc);
+ if (HttpsURLConnection.class.isInstance(uc)) {
+ SSLSocketFactory factory = ((HttpsURLConnection) uc).getSSLSocketFactory();
+ factoryHolder.set(factory);
+ }
+ }
+
+ @Override
+ protected void setSslContextFactory(Client client, ClientRequest request) {
+ super.setSslContextFactory(client, request);
+ }
+ }
+
+ private static class SSlSocketFactoryUrlConnectorProvider extends HttpUrlConnectorProvider {
+ @Override
+ protected Connector createHttpUrlConnector(Client client, ConnectionFactory connectionFactory, int chunkSize,
+ boolean fixLengthStreaming, boolean setMethodWorkaround) {
+ return new SSLSocketFactoryConnector(
+ client,
+ connectionFactory,
+ chunkSize,
+ fixLengthStreaming,
+ setMethodWorkaround);
+ }
+ }
+}
diff --git a/core-common/pom.xml b/core-common/pom.xml
index 56f0d05..46315aa 100644
--- a/core-common/pom.xml
+++ b/core-common/pom.xml
@@ -674,7 +674,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
- <version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java b/core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java
new file mode 100644
index 0000000..c2109fe
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2024 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.innate.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Generic wrapper template for InputStream.
+ */
+public abstract class InputStreamWrapper extends InputStream {
+
+ /**
+ * Return the wrapped stream
+ * @return
+ */
+ protected abstract InputStream getWrapped();
+
+ /**
+ * Get wrapped stream that can throw {@link IOException}
+ * @return the wrapped InputStream.
+ * @throws IOException
+ */
+ protected InputStream getWrappedIOE() throws IOException {
+ return getWrapped();
+ }
+
+ @Override
+ public int read() throws IOException {
+ return getWrappedIOE().read();
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return getWrappedIOE().read(b);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return getWrappedIOE().read(b, off, len);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return getWrappedIOE().skip(n);
+ }
+
+ @Override
+ public int available() throws IOException {
+ return getWrappedIOE().available();
+ }
+
+ @Override
+ public void close() throws IOException {
+ getWrappedIOE().close();
+ }
+
+ @Override
+ public void mark(int readlimit) {
+ getWrapped().mark(readlimit);
+ }
+
+ @Override
+ public void reset() throws IOException {
+ getWrappedIOE().reset();
+ }
+
+ @Override
+ public boolean markSupported() {
+ return getWrapped().markSupported();
+ }
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/io/package-info.java b/core-common/src/main/java/org/glassfish/jersey/innate/io/package-info.java
new file mode 100644
index 0000000..e569f79
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/io/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 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
+ */
+
+/**
+ * Jersey innate io related packages. The innate packages will not be opened by JPMS outside of Jersey.
+ * Not for public use.
+ */
+package org.glassfish.jersey.innate.io;
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderInterceptorExecutor.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderInterceptorExecutor.java
index 91738c1..a0e5dfc 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderInterceptorExecutor.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderInterceptorExecutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -38,6 +38,7 @@
import jakarta.ws.rs.ext.ReaderInterceptor;
import jakarta.ws.rs.ext.ReaderInterceptorContext;
+import org.glassfish.jersey.innate.io.InputStreamWrapper;
import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.PropertiesDelegate;
import org.glassfish.jersey.internal.inject.InjectionManager;
@@ -248,7 +249,7 @@
* {@link jakarta.ws.rs.ext.MessageBodyReader}s should not close the given {@link java.io.InputStream stream}. This input
* stream makes sure that the stream is not closed even if MBR tries to do it.
*/
- private static class UnCloseableInputStream extends InputStream {
+ private static class UnCloseableInputStream extends InputStreamWrapper {
private final InputStream original;
private final MessageBodyReader reader;
@@ -259,43 +260,8 @@
}
@Override
- public int read() throws IOException {
- return original.read();
- }
-
- @Override
- public int read(final byte[] b) throws IOException {
- return original.read(b);
- }
-
- @Override
- public int read(final byte[] b, final int off, final int len) throws IOException {
- return original.read(b, off, len);
- }
-
- @Override
- public long skip(final long l) throws IOException {
- return original.skip(l);
- }
-
- @Override
- public int available() throws IOException {
- return original.available();
- }
-
- @Override
- public synchronized void mark(final int i) {
- original.mark(i);
- }
-
- @Override
- public synchronized void reset() throws IOException {
- original.reset();
- }
-
- @Override
- public boolean markSupported() {
- return original.markSupported();
+ protected InputStream getWrapped() {
+ return original;
}
@Override
@@ -304,10 +270,6 @@
LOGGER.log(Level.FINE, LocalizationMessages.MBR_TRYING_TO_CLOSE_STREAM(reader.getClass()));
}
}
-
- private InputStream unwrap() {
- return original;
- }
}
/**
@@ -320,7 +282,7 @@
*/
public static InputStream closeableInputStream(InputStream inputStream) {
if (inputStream instanceof UnCloseableInputStream) {
- return ((UnCloseableInputStream) inputStream).unwrap();
+ return ((UnCloseableInputStream) inputStream).getWrapped();
} else {
return inputStream;
}
diff --git a/core-server/pom.xml b/core-server/pom.xml
index f0af2e8..263ab48 100644
--- a/core-server/pom.xml
+++ b/core-server/pom.xml
@@ -233,7 +233,13 @@
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jboss-vfs</artifactId>
- <version>3.2.6.Final</version>
+ <version>${jboss.vfs.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <version>${jboss.logging.version}</version>
<scope>test</scope>
</dependency>
@@ -247,6 +253,16 @@
<profiles>
<profile>
+ <id>jdk8</id>
+ <activation>
+ <jdk>1.8</jdk>
+ </activation>
+ <properties>
+ <jboss.vfs.version>${jboss.vfs.jdk8.version}</jboss.vfs.version>
+ <jboss.logging.version>${jboss.logging.8.version}</jboss.logging.version>
+ </properties>
+ </profile>
+ <profile>
<id>securityOff</id>
<properties>
<surefire.security.argline />
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java
index 14e86e3..8c116ca 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -24,6 +24,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.glassfish.jersey.innate.io.InputStreamWrapper;
import org.glassfish.jersey.server.internal.AbstractResourceFinderAdapter;
import org.glassfish.jersey.server.internal.LocalizationMessages;
@@ -109,52 +110,17 @@
@Override
public InputStream open() {
//noinspection NullableProblems
- return new InputStream() {
+ return new InputStreamWrapper() {
@Override
- public int read() throws IOException {
- return jarInputStream.read();
- }
-
- @Override
- public int read(final byte[] bytes) throws IOException {
- return jarInputStream.read(bytes);
- }
-
- @Override
- public int read(final byte[] bytes, final int i, final int i2) throws IOException {
- return jarInputStream.read(bytes, i, i2);
- }
-
- @Override
- public long skip(final long l) throws IOException {
- return jarInputStream.skip(l);
- }
-
- @Override
- public int available() throws IOException {
- return jarInputStream.available();
+ protected InputStream getWrapped() {
+ return jarInputStream;
}
@Override
public void close() throws IOException {
jarInputStream.closeEntry();
}
-
- @Override
- public synchronized void mark(final int i) {
- jarInputStream.mark(i);
- }
-
- @Override
- public synchronized void reset() throws IOException {
- jarInputStream.reset();
- }
-
- @Override
- public boolean markSupported() {
- return jarInputStream.markSupported();
- }
};
}
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlResource.java b/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlResource.java
index 5a7188a..9867681 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlResource.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 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
@@ -21,6 +21,7 @@
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.Locale;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@@ -62,7 +63,7 @@
public WadlResource() {
- this.lastModified = new SimpleDateFormat(HTTPDATEFORMAT).format(new Date());
+ this.lastModified = new SimpleDateFormat(HTTPDATEFORMAT, Locale.US).format(new Date());
}
private boolean isCached(UriInfo uriInfo, boolean detailedWadl) {
@@ -81,7 +82,7 @@
if ((wadlXmlRepresentation == null) || (!isCached(uriInfo, detailedWadl))) {
this.lastBaseUri = uriInfo.getBaseUri();
lastDetailedWadl = detailedWadl;
- this.lastModified = new SimpleDateFormat(HTTPDATEFORMAT).format(new Date());
+ this.lastModified = new SimpleDateFormat(HTTPDATEFORMAT, Locale.US).format(new Date());
ApplicationDescription applicationDescription = wadlContext.getApplication(uriInfo,
detailedWadl);
diff --git a/examples/NOTICE.md b/examples/NOTICE.md
index e982511..034205c 100644
--- a/examples/NOTICE.md
+++ b/examples/NOTICE.md
@@ -71,7 +71,7 @@
* Project: http://www.javassist.org/
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
-Jackson JAX-RS Providers Version 2.17.0
+Jackson JAX-RS Providers Version 2.17.1
* License: Apache License, 2.0
* Project: https://github.com/FasterXML/jackson-jaxrs-providers
* Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated.
diff --git a/examples/extended-wadl-webapp/pom.xml b/examples/extended-wadl-webapp/pom.xml
index 3feed37..0b5f9f2 100644
--- a/examples/extended-wadl-webapp/pom.xml
+++ b/examples/extended-wadl-webapp/pom.xml
@@ -109,7 +109,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
- <version>1.6.4</version>
+ <version>2.0.13</version>
<scope>test</scope>
</dependency>
diff --git a/examples/groovy/pom.xml b/examples/groovy/pom.xml
index 8d7a370..0252257 100644
--- a/examples/groovy/pom.xml
+++ b/examples/groovy/pom.xml
@@ -140,7 +140,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
- <version>3.0.0</version>
+ <version>${buildhelper.mvn.plugin.version}</version>
<executions>
<execution>
<id>3</id>
diff --git a/examples/jaxb/pom.xml b/examples/jaxb/pom.xml
index f8e72a7..4430309 100644
--- a/examples/jaxb/pom.xml
+++ b/examples/jaxb/pom.xml
@@ -41,7 +41,7 @@
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
- <version>4.1.2</version>
+ <version>4.4.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
diff --git a/examples/osgi-http-service/functional-test/pom.xml b/examples/osgi-http-service/functional-test/pom.xml
index 5ec3b1c..05b2447 100644
--- a/examples/osgi-http-service/functional-test/pom.xml
+++ b/examples/osgi-http-service/functional-test/pom.xml
@@ -145,7 +145,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
- <version>1.6.4</version>
+ <version>2.0.13</version>
<scope>test</scope>
</dependency>
diff --git a/examples/pom.xml b/examples/pom.xml
index 1798d4f..8d25b08 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -182,7 +182,7 @@
<plugin>
<groupId>org.commonjava.maven.plugins</groupId>
<artifactId>directory-maven-plugin</artifactId>
- <version>0.3.1</version>
+ <version>1.0</version>
<executions>
<execution>
<id>directories</id>
@@ -199,7 +199,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
- <version>2.6</version>
+ <version>${resources.mvn.plugin.version}</version>
<!-- Add legal information, NOTICE.md and LINCENSE.md to jars -->
<executions>
<execution>
diff --git a/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/JerseyKeyValues.java b/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/JerseyKeyValues.java
index 66cdaf7..8b6d9b3 100644
--- a/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/JerseyKeyValues.java
+++ b/ext/micrometer/src/main/java/org/glassfish/jersey/micrometer/server/JerseyKeyValues.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 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
@@ -23,6 +23,9 @@
import org.glassfish.jersey.server.ExtendedUriInfo;
import org.glassfish.jersey.server.monitoring.RequestEvent;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Response;
+
/**
* Factory methods for {@link KeyValue KeyValues} associated with a request-response
* exchange that is handled by Jersey server.
@@ -38,6 +41,9 @@
private static final KeyValue URI_ROOT = JerseyObservationDocumentation.JerseyLegacyLowCardinalityTags.URI
.withValue("root");
+ private static final KeyValue URI_UNKNOWN = JerseyObservationDocumentation.JerseyLegacyLowCardinalityTags.URI
+ .withValue("UNKNOWN");
+
private static final KeyValue EXCEPTION_NONE = JerseyObservationDocumentation.JerseyLegacyLowCardinalityTags.EXCEPTION
.withValue("None");
@@ -82,17 +88,30 @@
* @return the uri KeyValue derived from the request event
*/
static KeyValue uri(RequestEvent event) {
- ContainerResponse response = event.getContainerResponse();
- if (response != null) {
- int status = response.getStatus();
+ int status = 0;
+ if (event.getContainerResponse() != null) {
+ status = event.getContainerResponse().getStatus();
+ } else if (WebApplicationException.class.isInstance(event.getException())) {
+ Response webAppResponse = ((WebApplicationException) event.getException()).getResponse();
+ if (webAppResponse != null) {
+ status = webAppResponse.getStatus();
+ }
+ }
+ if (status != 0) {
if (JerseyTags.isRedirection(status) && event.getUriInfo().getMatchedResourceMethod() == null) {
return URI_REDIRECTION;
}
if (status == 404 && event.getUriInfo().getMatchedResourceMethod() == null) {
return URI_NOT_FOUND;
}
+ if (status >= 500 && status <= 599) {
+ return STATUS_SERVER_ERROR;
+ }
}
String matchingPattern = JerseyTags.getMatchingPattern(event);
+ if (matchingPattern == null) {
+ return URI_UNKNOWN;
+ }
if (matchingPattern.equals("/")) {
return URI_ROOT;
}
diff --git a/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/exception/JerseyKeyValuesTest.java b/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/exception/JerseyKeyValuesTest.java
new file mode 100644
index 0000000..99bad31
--- /dev/null
+++ b/ext/micrometer/src/test/java/org/glassfish/jersey/micrometer/server/exception/JerseyKeyValuesTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2024 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.micrometer.server.exception;
+
+import io.micrometer.common.KeyValue;
+import io.micrometer.common.KeyValues;
+import org.glassfish.jersey.micrometer.server.DefaultJerseyObservationConvention;
+import org.glassfish.jersey.micrometer.server.JerseyContext;
+import org.glassfish.jersey.server.ExtendedUriInfo;
+import org.glassfish.jersey.server.internal.monitoring.RequestEventImpl;
+import org.glassfish.jersey.server.monitoring.RequestEvent;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.NotFoundException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collections;
+import java.util.Optional;
+
+public class JerseyKeyValuesTest {
+ @Test
+ public void testOnException() {
+ ExtendedUriInfo uriInfo = (ExtendedUriInfo) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class[]{ExtendedUriInfo.class},
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ switch (method.getName()) {
+ case "getMatchedTemplates":
+ return Collections.emptyList();
+ }
+ return null;
+ }
+ });
+ RequestEventImpl event = new RequestEventImpl.Builder()
+ .setExtendedUriInfo(uriInfo)
+ .setException(new NotFoundException(), RequestEvent.ExceptionCause.ORIGINAL)
+ .build(RequestEvent.Type.ON_EXCEPTION);
+ JerseyContext context = new JerseyContext(event);
+ DefaultJerseyObservationConvention convention = new DefaultJerseyObservationConvention("Test-Metric");
+ KeyValues values = convention.getLowCardinalityKeyValues(context);
+ Optional<KeyValue> kv = values.stream().filter(p -> p.getValue().equals("NOT_FOUND")).findFirst();
+ MatcherAssert.assertThat(kv.isPresent(), Matchers.equalTo(true));
+ }
+}
diff --git a/incubator/declarative-linking/pom.xml b/incubator/declarative-linking/pom.xml
index 181bb67..cdb5680 100644
--- a/incubator/declarative-linking/pom.xml
+++ b/incubator/declarative-linking/pom.xml
@@ -88,7 +88,7 @@
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
- <version>1.4.0</version>
+ <version>1.5.1</version>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/media/jaxb/pom.xml b/media/jaxb/pom.xml
index 75a49a0..6586b38 100644
--- a/media/jaxb/pom.xml
+++ b/media/jaxb/pom.xml
@@ -83,21 +83,6 @@
<inherited>true</inherited>
</plugin>
<plugin>
- <groupId>de.jflex</groupId>
- <artifactId>maven-jflex-plugin</artifactId>
- <version>1.4.3</version>
- <executions>
- <execution>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <outputDirectory>${project.build.directory}/generated-sources/rsrc-gen</outputDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<inherited>true</inherited>
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/cfg/MapperConfiguratorBase.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/cfg/MapperConfiguratorBase.java
index 75bc66e..bc280cc 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/cfg/MapperConfiguratorBase.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/cfg/MapperConfiguratorBase.java
@@ -13,8 +13,8 @@
* well as accessing it.
*/
public abstract class MapperConfiguratorBase<IMPL extends MapperConfiguratorBase<IMPL,MAPPER>,
- MAPPER extends ObjectMapper
->
+ MAPPER extends ObjectMapper
+ >
{
/**
* Mapper provider was constructed with if any, or that was constructed
@@ -22,7 +22,7 @@
* If defined (explicitly or implicitly) it will be used, instead
* of using provider-based lookup.
*/
- protected MAPPER _mapper;
+ protected volatile MAPPER _mapper;
/**
* If no mapper was specified when constructed, and no configuration
@@ -30,14 +30,14 @@
* between default mapper and regular one is that default mapper
* is only used if no mapper is found via provider lookup.
*/
- protected MAPPER _defaultMapper;
+ protected volatile MAPPER _defaultMapper;
/**
* Annotations set to use by default; overridden by explicit call
- * to {@link #setAnnotationsToUse}
+ * to {@link #setAnnotationsToUse}. Marked final in v2.17.1.
*/
- protected Annotations[] _defaultAnnotationsToUse;
-
+ protected final Annotations[] _defaultAnnotationsToUse;
+
/**
* To support optional dependency to Jackson JAXB annotations module
* (needed iff JAXB annotations are used for configuration)
@@ -49,7 +49,7 @@
/* Construction
/**********************************************************
*/
-
+
public MapperConfiguratorBase(MAPPER mapper, Annotations[] defaultAnnotations)
{
_mapper = mapper;
@@ -61,7 +61,7 @@
/* Abstract methods to implement
/***********************************************************
*/
-
+
/**
* Method that locates, configures and returns {@link ObjectMapper} to use
*/
@@ -84,27 +84,27 @@
/***********************************************************
*/
- public synchronized final void setMapper(MAPPER m) {
+ public final void setMapper(MAPPER m) {
_mapper = m;
}
- public synchronized final void setAnnotationsToUse(Annotations[] annotationsToUse) {
+ public final void setAnnotationsToUse(Annotations[] annotationsToUse) {
_setAnnotations(mapper(), annotationsToUse);
}
- public synchronized final void configure(DeserializationFeature f, boolean state) {
+ public final void configure(DeserializationFeature f, boolean state) {
mapper().configure(f, state);
}
- public synchronized final void configure(SerializationFeature f, boolean state) {
+ public final void configure(SerializationFeature f, boolean state) {
mapper().configure(f, state);
}
- public synchronized final void configure(JsonParser.Feature f, boolean state) {
+ public final void configure(JsonParser.Feature f, boolean state) {
mapper().configure(f, state);
}
- public synchronized final void configure(JsonGenerator.Feature f, boolean state) {
+ public final void configure(JsonGenerator.Feature f, boolean state) {
mapper().configure(f, state);
}
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JsonMapperConfigurator.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JsonMapperConfigurator.java
index 3e9c770..8e8091a 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JsonMapperConfigurator.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JsonMapperConfigurator.java
@@ -1,6 +1,7 @@
package org.glassfish.jersey.jackson.internal.jackson.jaxrs.json;
import java.util.ArrayList;
+import java.util.concurrent.locks.ReentrantLock;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.Annotations;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.MapperConfiguratorBase;
@@ -16,14 +17,17 @@
* well as accessing it.
*/
public class JsonMapperConfigurator
- extends MapperConfiguratorBase<JsonMapperConfigurator, ObjectMapper>
+ extends MapperConfiguratorBase<JsonMapperConfigurator, ObjectMapper>
{
+ // @since 2.17.1
+ private final ReentrantLock _lock = new ReentrantLock();
+
/*
/**********************************************************
/* Construction
/**********************************************************
*/
-
+
public JsonMapperConfigurator(ObjectMapper mapper, Annotations[] defAnnotations)
{
super(mapper, defAnnotations);
@@ -33,18 +37,24 @@
* Method that locates, configures and returns {@link ObjectMapper} to use
*/
@Override
- public synchronized ObjectMapper getConfiguredMapper() {
- /* important: should NOT call mapper(); needs to return null
- * if no instance has been passed or constructed
- */
+ public ObjectMapper getConfiguredMapper() {
+ // important: should NOT call mapper(); needs to return null
+ // if no instance has been passed or constructed
return _mapper;
}
@Override
- public synchronized ObjectMapper getDefaultMapper() {
+ public ObjectMapper getDefaultMapper() {
if (_defaultMapper == null) {
- _defaultMapper = new ObjectMapper();
- _setAnnotations(_defaultMapper, _defaultAnnotationsToUse);
+ _lock.lock();
+ try {
+ if (_defaultMapper == null) {
+ _defaultMapper = new ObjectMapper();
+ _setAnnotations(_defaultMapper, _defaultAnnotationsToUse);
+ }
+ } finally {
+ _lock.unlock();
+ }
}
return _defaultMapper;
}
@@ -64,8 +74,15 @@
protected ObjectMapper mapper()
{
if (_mapper == null) {
- _mapper = new ObjectMapper();
- _setAnnotations(_mapper, _defaultAnnotationsToUse);
+ _lock.lock();
+ try {
+ if (_mapper == null) {
+ _mapper = new ObjectMapper();
+ _setAnnotations(_mapper, _defaultAnnotationsToUse);
+ }
+ } finally {
+ _lock.unlock();
+ }
}
return _mapper;
}
@@ -100,22 +117,22 @@
protected AnnotationIntrospector _resolveIntrospector(Annotations ann)
{
switch (ann) {
- case JACKSON:
- return new JacksonAnnotationIntrospector();
- case JAXB:
- /* For this, need to use indirection just so that error occurs
- * when we get here, and not when this class is being loaded
- */
- try {
- if (_jaxbIntrospectorClass == null) {
- _jaxbIntrospectorClass = JaxbAnnotationIntrospector.class;
+ case JACKSON:
+ return new JacksonAnnotationIntrospector();
+ case JAXB:
+ /* For this, need to use indirection just so that error occurs
+ * when we get here, and not when this class is being loaded
+ */
+ try {
+ if (_jaxbIntrospectorClass == null) {
+ _jaxbIntrospectorClass = JaxbAnnotationIntrospector.class;
+ }
+ return _jaxbIntrospectorClass.newInstance();
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to instantiate JaxbAnnotationIntrospector: "+e.getMessage(), e);
}
- return _jaxbIntrospectorClass.newInstance();
- } catch (Exception e) {
- throw new IllegalStateException("Failed to instantiate JaxbAnnotationIntrospector: "+e.getMessage(), e);
- }
- default:
- throw new IllegalStateException();
+ default:
+ throw new IllegalStateException();
}
}
}
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
index 88e3168..5d328da 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
@@ -11,7 +11,7 @@
*/
public final class PackageVersion implements Versioned {
public final static Version VERSION = VersionUtil.parseVersion(
- "2.17.0", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider");
+ "2.17.1", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider");
@Override
public Version version() {
diff --git a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
index 6034c04..4edecfc 100644
--- a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
+++ b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
@@ -31,7 +31,7 @@
## Third-party Content
-Jackson JAX-RS Providers version 2.17.0
+Jackson JAX-RS Providers version 2.17.1
* License: Apache License, 2.0
* Project: https://github.com/FasterXML/jackson-jaxrs-providers
* Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated.
diff --git a/media/moxy/pom.xml b/media/moxy/pom.xml
index 335f80e..5ae722e 100644
--- a/media/moxy/pom.xml
+++ b/media/moxy/pom.xml
@@ -62,21 +62,6 @@
</configuration>
</plugin>
- <plugin>
- <groupId>de.jflex</groupId>
- <artifactId>maven-jflex-plugin</artifactId>
- <version>1.4.3</version>
- <executions>
- <execution>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <outputDirectory>${project.build.directory}/generated-sources/rsrc-gen</outputDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
diff --git a/pom.xml b/pom.xml
index 980af5d..b37f5c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2234,7 +2234,7 @@
<microprofile.config.version>3.0.3</microprofile.config.version>
<microprofile.rest.client.version>3.0.1</microprofile.rest.client.version>
<helidon.config.version>3.2.6</helidon.config.version>
- <helidon.jersey.connector.version>3.2.6</helidon.jersey.connector.version>
+ <helidon.connector.version>3.2.8</helidon.connector.version>
<helidon.config.11.version>1.4.14</helidon.config.11.version> <!-- JDK 11- support -->
<smallrye.config.version>3.7.1</smallrye.config.version>
@@ -2245,13 +2245,15 @@
<hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[2.5,4)"</hk2.jvnet.osgi.version>
<httpclient.version>4.5.14</httpclient.version>
<httpclient5.version>5.3.1</httpclient5.version>
- <jackson.version>2.17.0</jackson.version>
+ <jackson.version>2.17.1</jackson.version>
<javassist.version>3.30.2-GA</javassist.version>
- <jboss.logging.version>3.5.3.Final</jboss.logging.version>
<jboss.logging.8.version>3.4.3.Final</jboss.logging.8.version>
<jersey1.version>1.19.3</jersey1.version>
<jersey1.last.final.version>${jersey1.version}</jersey1.last.final.version>
<jettison.version>1.3.7</jettison.version> <!-- TODO: 1.3.8 doesn't work; AbstractJsonTest complexBeanWithAttributes -->
+ <jboss.vfs.version>3.3.2.Final</jboss.vfs.version>
+ <jboss.vfs.jdk8.version>3.2.17.Final</jboss.vfs.jdk8.version>
+ <jboss.logging.version>3.6.0.Final</jboss.logging.version>
<jmh.version>1.37</jmh.version>
<jmockit.version>1.49</jmockit.version>
<junit4.version>4.13.2</junit4.version>
@@ -2321,7 +2323,7 @@
<jaxrs.api.spec.version>3.0</jaxrs.api.spec.version>
<jaxrs.api.impl.version>3.0.0</jaxrs.api.impl.version>
<jetty.osgi.version>org.eclipse.jetty.*;version="[11,15)"</jetty.osgi.version>
- <jetty.version>11.0.20</jetty.version>
+ <jetty.version>11.0.22</jetty.version>
<jetty.tracing.version>11.0.15</jetty.tracing.version> <!-- special version for tracing support tests, applied before JDK 21-->
<jetty9.version>9.4.54.v20240208</jetty9.version>
<jetty.plugin.version>11.0.20</jetty.plugin.version>
diff --git a/tests/e2e-client/pom.xml b/tests/e2e-client/pom.xml
index e0a036b..a8e9f41 100644
--- a/tests/e2e-client/pom.xml
+++ b/tests/e2e-client/pom.xml
@@ -237,6 +237,7 @@
<configuration>
<testExcludes>
<testExclude>org/glassfish/jersey/tests/e2e/client/connector/proxy/Proxy*Test.java</testExclude>
+ <testExclude>org/glassfish/jersey/tests/e2e/client/connector/NoContentLengthTest.java</testExclude>
<testExclude>org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java</testExclude>
</testExcludes>
</configuration>
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/ResponseReadAndBufferEntityTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/ResponseReadAndBufferEntityTest.java
index 8b54346..951de51 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/ResponseReadAndBufferEntityTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/ResponseReadAndBufferEntityTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -35,6 +35,7 @@
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
+import org.glassfish.jersey.innate.io.InputStreamWrapper;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
@@ -57,7 +58,7 @@
private static final Logger LOGGER = Logger.getLogger(ResponseReadAndBufferEntityTest.class.getName());
- public static class CorruptableInputStream extends InputStream {
+ public static class CorruptableInputStream extends InputStreamWrapper {
private final AtomicInteger closeCounter = new AtomicInteger(0);
@@ -71,53 +72,16 @@
}
@Override
- public synchronized int read() throws IOException {
+ protected InputStream getWrapped() {
+ return delegate;
+ }
+
+ @Override
+ protected InputStream getWrappedIOE() throws IOException {
if (corruptRead) {
corrupt();
}
- return delegate.read();
- }
-
- @Override
- public int read(final byte[] b) throws IOException {
- if (corruptRead) {
- corrupt();
- }
- return delegate.read(b);
- }
-
- @Override
- public int read(final byte[] b, final int off, final int len) throws IOException {
- if (corruptRead) {
- corrupt();
- }
- return delegate.read(b, off, len);
- }
-
- @Override
- public long skip(final long n) throws IOException {
- if (corruptRead) {
- corrupt();
- }
- return delegate.skip(n);
- }
-
- @Override
- public int available() throws IOException {
- if (corruptRead) {
- corrupt();
- }
- return delegate.available();
- }
-
- @Override
- public boolean markSupported() {
- return delegate.markSupported();
- }
-
- @Override
- public void mark(final int readAheadLimit) {
- delegate.mark(readAheadLimit);
+ return delegate;
}
@Override
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java
index 3cb45b9..55376fa 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 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,12 +16,18 @@
package org.glassfish.jersey.tests.e2e.client.connector;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
+import org.glassfish.jersey.client.RequestEntityProcessing;
import org.glassfish.jersey.client.spi.ConnectorProvider;
import org.glassfish.jersey.internal.util.JdkVersion;
import org.glassfish.jersey.jdk.connector.JdkConnectorProvider;
import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
+import org.glassfish.jersey.media.multipart.FormDataBodyPart;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.media.multipart.BodyPart;
@@ -33,6 +39,8 @@
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.glassfish.jersey.test.spi.TestHelper;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.Test;
@@ -41,18 +49,26 @@
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.Provider;
+import jakarta.ws.rs.ext.WriterInterceptor;
+import jakarta.ws.rs.ext.WriterInterceptorContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.logging.Handler;
import java.util.logging.Level;
+import java.util.logging.LogManager;
import java.util.logging.Logger;
-import java.util.stream.Stream;
public class MultiPartTest {
@@ -132,5 +148,72 @@
}
}
}
+
+ @Test
+ public void testNettyBufferedMultipart() {
+// setDebugLevel(Level.FINEST);
+ ClientConfig config = new ClientConfig();
+
+ config.connectorProvider(new NettyConnectorProvider());
+ config.property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.BUFFERED);
+ config.register(org.glassfish.jersey.media.multipart.MultiPartFeature.class);
+ config.register(new LoggingHandler(LogLevel.DEBUG));
+ config.register(new LoggingInterceptor());
+ config.property(ClientProperties.ASYNC_THREADPOOL_SIZE, 10);
+ config.property("jersey.config.client.logging.verbosity", LoggingFeature.Verbosity.PAYLOAD_TEXT);
+ config.property("jersey.config.client.logging.logger.level", Level.FINEST.toString());
+
+ Client client = ClientBuilder.newClient(config);
+
+ FormDataMultiPart formData = new FormDataMultiPart();
+ FormDataBodyPart bodyPart1 = new FormDataBodyPart("hello1", "{\"first\":\"firstLine\",\"second\":\"secondLine\"}",
+ MediaType.APPLICATION_JSON_TYPE);
+ formData.bodyPart(bodyPart1);
+ formData.bodyPart(new FormDataBodyPart("hello2",
+ "{\"first\":\"firstLine\",\"second\":\"secondLine\",\"third\":\"thirdLine\"}",
+ MediaType.APPLICATION_JSON_TYPE));
+ formData.bodyPart(new FormDataBodyPart("hello3",
+ "{\"first\":\"firstLine\",\"second\":\"secondLine\",\""
+ + "second\":\"secondLine\",\"second\":\"secondLine\",\"second\":\"secondLine\"}",
+ MediaType.APPLICATION_JSON_TYPE));
+ formData.bodyPart(new FormDataBodyPart("plaintext", "hello"));
+
+ Response response1 = client.target(target().getUri()).path("upload")
+ .request()
+ .post(Entity.entity(formData, formData.getMediaType()));
+
+ MatcherAssert.assertThat(response1.getStatus(), Matchers.is(200));
+ MatcherAssert.assertThat(response1.readEntity(String.class),
+ Matchers.stringContainsInOrder("first", "firstLine", "second", "secondLine"));
+ response1.close();
+ client.close();
+ }
+
+ public static void setDebugLevel(Level newLvl) {
+ Logger rootLogger = LogManager.getLogManager().getLogger("");
+ Handler[] handlers = rootLogger.getHandlers();
+ rootLogger.setLevel(newLvl);
+ for (Handler h : handlers) {
+ h.setLevel(Level.ALL);
+ }
+ Logger nettyLogger = Logger.getLogger("io.netty");
+ nettyLogger.setLevel(Level.FINEST);
+ }
+
+ @Provider
+ public class LoggingInterceptor implements WriterInterceptor {
+
+ @Override
+ public void aroundWriteTo(WriterInterceptorContext context)
+ throws IOException, WebApplicationException {
+ try {
+ MultivaluedMap<String, Object> headers = context.getHeaders();
+ headers.forEach((key, val) -> System.out.println(key + ":" + val));
+ context.proceed();
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+ }
}
}
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/NoContentLengthTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/NoContentLengthTest.java
new file mode 100644
index 0000000..e3c3caf
--- /dev/null
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/NoContentLengthTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2024 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.client.connector;
+
+import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
+import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.HttpUrlConnectorProvider;
+import org.glassfish.jersey.client.spi.ConnectorProvider;
+import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider;
+import org.glassfish.jersey.jdk.connector.JdkConnectorProvider;
+import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
+import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.Response;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class NoContentLengthTest {
+
+ private static final String MSG = "12345678901234567890123456789012345678901234567890";
+
+ private static int port;
+ private static AtomicBoolean running = new AtomicBoolean(false);
+
+ @BeforeEach
+ void beforeEach() {
+ while (!running.compareAndSet(false, true)) {
+ try {
+ Thread.sleep(1000L);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ String _port = System.getProperty("jersey.config.test.container.port");
+ port = Integer.parseInt(_port == null || _port.isEmpty() ? "8080" : _port);
+ ServerSocket serverSocket = new ServerSocket(port);
+ System.err.println("Starting server on port : " + port);
+
+ Socket clientSocket = serverSocket.accept();
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+ BufferedWriter out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
+
+ String s;
+ while ((s = in.readLine()) != null) {
+ // System.out.println(s);
+ if (s.isEmpty()) {
+ break;
+ }
+ }
+
+ out.write("HTTP/1.0 200 OK\r\n");
+ out.write("Content-Type: text/plain\r\n");
+ out.write("\r\n");
+ out.write(MSG);
+
+ out.close();
+ in.close();
+ clientSocket.close();
+ serverSocket.close();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } finally {
+ running.set(false);
+ }
+ }
+ };
+ Thread newThread = new Thread(runnable);
+ newThread.start();
+ }
+
+ public static List<ConnectorProvider> providers() {
+ return Arrays.asList(
+ new ApacheConnectorProvider(),
+ new Apache5ConnectorProvider(),
+ new HttpUrlConnectorProvider(),
+ new NettyConnectorProvider(),
+ new JettyConnectorProvider(),
+ new GrizzlyConnectorProvider(),
+ new JdkConnectorProvider()
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("providers")
+ public void testNoContentLength(ConnectorProvider connectorProvider) {
+ try (Response r = target(connectorProvider).request().get()) {
+ MatcherAssert.assertThat(r.getStatus(), Matchers.is(200));
+ MatcherAssert.assertThat(r.getHeaderString(HttpHeaders.CONTENT_LENGTH), Matchers.nullValue());
+ MatcherAssert.assertThat(r.hasEntity(), Matchers.is(true));
+ MatcherAssert.assertThat(r.readEntity(String.class), Matchers.is(MSG));
+ }
+ }
+
+ private WebTarget target(ConnectorProvider connectorProvider) {
+ ClientConfig config = new ClientConfig();
+ config.connectorProvider(connectorProvider);
+ return ClientBuilder.newClient(config).target("http://localhost:" + port);
+ }
+}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
index 6c4907f..f342c5f 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 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
@@ -30,6 +30,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
@@ -108,6 +109,7 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -400,6 +402,20 @@
}
@Test
+ public void testLastModifiedGETOnJPLocale() {
+ Locale defaultLocale = Locale.getDefault();
+ try {
+ Locale.setDefault(new Locale("ja", "JP"));
+ final WebTarget target = target("/application.wadl");
+
+ final Response r = target.queryParam(WadlUtils.DETAILED_WADL_QUERY_PARAM, "true").request().get(Response.class);
+ assertDoesNotThrow(() -> r.getLastModified());
+ } finally {
+ Locale.setDefault(defaultLocale);
+ }
+ }
+
+ @Test
public void testLastModifiedOPTIONS() {
final WebTarget target = target("/widgets/3/verbose");
diff --git a/tests/e2e-tls/pom.xml b/tests/e2e-tls/pom.xml
index a7a98de..3f2bf1a 100644
--- a/tests/e2e-tls/pom.xml
+++ b/tests/e2e-tls/pom.xml
@@ -96,7 +96,7 @@
<dependency>
<groupId>io.specto</groupId>
<artifactId>hoverfly-java-junit5</artifactId>
- <version>0.14.0</version>
+ <version>0.18.1</version>
<scope>test</scope>
</dependency>
diff --git a/tests/integration/jersey-2776/pom.xml b/tests/integration/jersey-2776/pom.xml
index c9fdda3..82b05bb 100644
--- a/tests/integration/jersey-2776/pom.xml
+++ b/tests/integration/jersey-2776/pom.xml
@@ -42,7 +42,7 @@
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
- <version>3.0.3</version>
+ <version>3.5.8</version>
<scope>test</scope>
</dependency>
diff --git a/tests/performance/runners/jersey-grizzly-runner/pom.xml b/tests/performance/runners/jersey-grizzly-runner/pom.xml
index 1d26c29..03f7645 100644
--- a/tests/performance/runners/jersey-grizzly-runner/pom.xml
+++ b/tests/performance/runners/jersey-grizzly-runner/pom.xml
@@ -49,7 +49,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.4</version>
+ <version>${jar.mvn.plugin.version}</version>
<configuration>
<archive>
<index>true</index>
diff --git a/tests/performance/test-cases/monitoring/pom.xml b/tests/performance/test-cases/monitoring/pom.xml
index c4076c2..d5b84bd 100644
--- a/tests/performance/test-cases/monitoring/pom.xml
+++ b/tests/performance/test-cases/monitoring/pom.xml
@@ -37,13 +37,13 @@
<dependency>
<groupId>com.yammer.metrics</groupId>
<artifactId>metrics-core</artifactId>
- <version>2.1.2</version>
+ <version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
- <version>5.9.1</version>
+ <version>5.10.2</version>
<scope>test</scope>
</dependency>
@@ -56,13 +56,13 @@
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
- <version>1.5</version>
+ <version>1.17.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
- <version>1.6.1</version>
+ <version>2.0.13</version>
</dependency>
<dependency>
@@ -97,11 +97,11 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.1</version>
+ <version>3.13.0</version>
<inherited>true</inherited>
<configuration>
- <source>1.7</source>
- <target>1.7</target>
+ <source>1.8</source>
+ <target>1.8</target>
<showWarnings>false</showWarnings>
<fork>false</fork>
</configuration>
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java
index 743d609..8a97941 100644
--- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java
+++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 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
@@ -27,7 +27,14 @@
class ClassVersionChecker {
static TestResult checkClassVersion(JarFile jar, JarEntry entry, Properties properties) throws IOException {
final String jerseyVersion = MavenUtil.getJerseyVersion(properties);
- final int minVersion = jerseyVersion.startsWith("3.1") ? 11 : 8;
+ final int minVersion;
+ if (jerseyVersion.startsWith("4")) {
+ minVersion = 17;
+ } else if (jerseyVersion.startsWith("3.1")) {
+ minVersion = 11;
+ } else {
+ minVersion = 8;
+ }
return checkClassVersion(jar.getInputStream(entry), jar.getName() + File.separator + entry.getName(), minVersion);
}
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java
index b1a7ee3..eeea982 100644
--- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java
+++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 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
@@ -42,4 +42,28 @@
request.setRepositories(remoteRepos);
return repoSystem.resolveArtifact(repoSession, request).getArtifact();
}
+
+ static Artifact resolveSource(org.apache.maven.model.Dependency d, List<RemoteRepository> remoteRepos,
+ RepositorySystem repoSystem, RepositorySystemSession repoSession)
+ throws ArtifactResolutionException {
+ DefaultArtifact artifact = new DefaultArtifact(
+ d.getGroupId(), d.getArtifactId(), "sources", d.getType(), d.getVersion()
+ );
+ ArtifactRequest request = new ArtifactRequest();
+ request.setArtifact(artifact);
+ request.setRepositories(remoteRepos);
+ return repoSystem.resolveArtifact(repoSession, request).getArtifact();
+ }
+
+ static Artifact resolveJavadoc(org.apache.maven.model.Dependency d, List<RemoteRepository> remoteRepos,
+ RepositorySystem repoSystem, RepositorySystemSession repoSession)
+ throws ArtifactResolutionException {
+ DefaultArtifact artifact = new DefaultArtifact(
+ d.getGroupId(), d.getArtifactId(), "javadoc", d.getType(), d.getVersion()
+ );
+ ArtifactRequest request = new ArtifactRequest();
+ request.setArtifact(artifact);
+ request.setRepositories(remoteRepos);
+ return repoSystem.resolveArtifact(repoSession, request).getArtifact();
+ }
}
\ No newline at end of file
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java
index 20e7737..98d4616 100644
--- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java
+++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -29,6 +29,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Properties;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class MavenUtil {
@@ -37,7 +38,7 @@
private static final String PROJECT_VERSION = "project.version";
static File getArtifactJar(File repositoryRoot, Dependency dependency, Properties properties) {
- return getArtifactFile(repositoryRoot, dependency, properties, "jar");
+ return getArtifactFile(repositoryRoot, dependency, properties, dependency.getType());
}
private static File getArtifactFile(File repositoryRoot, Dependency dependency, Properties properties, String extension) {
@@ -52,7 +53,11 @@
}
String version = MavenUtil.getDependencyVersion(dependency, properties);
fileSuffix.append(version).append(File.separator);
- fileSuffix.append(dependency.getArtifactId()).append('-').append(version).append(".").append(extension);
+ fileSuffix.append(dependency.getArtifactId()).append('-').append(version);
+ if (dependency.getClassifier() != null) {
+ fileSuffix.append('-').append(dependency.getClassifier());
+ }
+ fileSuffix.append(".").append(extension);
return new File(repositoryRoot, fileSuffix.toString());
}
@@ -103,7 +108,16 @@
static Stream<Dependency> streamJerseyJars() throws IOException, XmlPullParserException {
Model model = getModelFromFile("pom.xml");
List<Dependency> deps = getBomPomDependencies(model);
+ return streamJerseyJars(deps);
+ }
+ static Stream<Dependency> streamJerseySources() throws IOException, XmlPullParserException {
+ Model model = getModelFromFile("pom.xml");
+ List<Dependency> deps = getBomPomSources(model);
+ return streamJerseyJars(deps);
+ }
+
+ private static Stream<Dependency> streamJerseyJars(List<Dependency> deps) throws IOException, XmlPullParserException {
return deps.stream()
.filter(dep -> dep.getGroupId().startsWith("org.glassfish.jersey"))
.filter(dep -> dep.getType().equals("jar"));
@@ -139,6 +153,15 @@
return bomPomModel.getDependencyManagement().getDependencies();
}
+ private static List<Dependency> getBomPomSources(Model model) throws XmlPullParserException, IOException {
+ return getBomPomDependencies(model).stream()
+ .map(dependency -> {
+ dependency.setClassifier("sources");
+ return dependency;
+ })
+ .collect(Collectors.toList());
+ }
+
static String getJerseyVersion(Properties properties) {
String property = properties.getProperty(JERSEY_VERSION); // when it is in the pom.file
if (property == null || property.startsWith("${")) {
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ArchetypesTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ArchetypesTest.java
index b42830b..5be312c 100644
--- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ArchetypesTest.java
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ArchetypesTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 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
@@ -52,16 +52,21 @@
continue;
}
// Update the names with the ones in Jersey
- Map.Entry<Object, Object> updatedEntry = updateEntry(pomEntry);
// Check the properties are there
- if (properties.getProperty(updatedEntry.getKey().toString()) == null) {
+ final String key = pomEntry.getKey().toString();
+
+ if (properties.getProperty(key) == null) {
testResult.ok().append("Property ")
.append(pomEntry.getKey().toString())
.append(" from ").append(pom).println(" not in Jersey");
failed = true;
}
// check the values
- else if (!properties.getProperty(updatedEntry.getKey().toString()).equals(updatedEntry.getValue())) {
+ else if (
+ //archetype property value can be a variable from the main pom.xml - check and exclude if so
+ !(properties.containsKey(key) && pomEntry.getValue().toString().contains(key))
+ && !properties.getProperty(key).equals(pomEntry.getValue())
+ ) {
testResult.exception().append("The property ")
.append(pomEntry.getKey().toString())
.append(" in archetype pom ")
@@ -81,25 +86,4 @@
}
}
- private Map.Entry<Object, Object> updateEntry(Map.Entry<Object, Object> pomEntry) {
- if (pomEntry.getKey().equals("junit-jupiter.version")) {
- return new Map.Entry<Object, Object>() {
- @Override
- public Object getKey() {
- return "junit5.version";
- }
-
- @Override
- public Object getValue() {
- return pomEntry.getValue();
- }
-
- @Override
- public Object setValue(Object value) {
- return value;
- }
- };
- }
- return pomEntry;
- }
}
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java
index 99c94ee..6a74f07 100644
--- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 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
@@ -58,6 +58,12 @@
Artifact m = mavenEnvironment.resolveArtifact(member);
System.out.append("Resolved ").append(member.getGroupId()).append(":").append(member.getArtifactId()).append(":")
.append(member.getVersion()).append(" to ").println(m.getFile().getName());
+ m = mavenEnvironment.resolveSource(member);
+ System.out.append("Resolved sources ").append(member.getGroupId()).append(":").append(member.getArtifactId())
+ .append(":").append(member.getVersion()).append(" to ").println(m.getFile().getName());
+ m = mavenEnvironment.resolveJavadoc(member);
+ System.out.append("Resolved javadoc ").append(member.getGroupId()).append(":").append(member.getArtifactId())
+ .append(":").append(member.getVersion()).append(" to ").println(m.getFile().getName());
}
}
@@ -74,6 +80,14 @@
System.out.append("Resolved ").append(dependency.getGroupId()).append(":")
.append(dependency.getArtifactId()).append(":")
.append(dependency.getVersion()).append(" to ").println(m.getFile().getName());
+ m = mavenEnvironment.resolveSource(dependency);
+ System.out.append("Resolved source ").append(dependency.getGroupId()).append(":")
+ .append(dependency.getArtifactId()).append(":")
+ .append(dependency.getVersion()).append(" to ").println(m.getFile().getName());
+ m = mavenEnvironment.resolveJavadoc(dependency);
+ System.out.append("Resolved javadoc ").append(dependency.getGroupId()).append(":")
+ .append(dependency.getArtifactId()).append(":")
+ .append(dependency.getVersion()).append(" to ").println(m.getFile().getName());
}
}
@@ -102,6 +116,16 @@
return DependencyResolver.resolveArtifact(dependency, remoteRepos, repositorySystem, repoSession);
}
+ Artifact resolveSource(Dependency dependency) throws ArtifactResolutionException {
+ dependency.setVersion(jerseyVersion);
+ return DependencyResolver.resolveSource(dependency, remoteRepos, repositorySystem, repoSession);
+ }
+
+ Artifact resolveJavadoc(Dependency dependency) throws ArtifactResolutionException {
+ dependency.setVersion(jerseyVersion);
+ return DependencyResolver.resolveJavadoc(dependency, remoteRepos, repositorySystem, repoSession);
+ }
+
private List<RemoteRepository> getRemoteRepositories() throws Exception {
MavenProject project = getMavenProjectForResourceFile("/release-test-pom.xml");
List<RemoteRepository> remoteArtifactRepositories = project.getRemoteProjectRepositories();
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/LegalDocsIncludedTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/LegalDocsIncludedTest.java
index 74e0281..8c784af 100644
--- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/LegalDocsIncludedTest.java
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/LegalDocsIncludedTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 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
@@ -41,7 +41,15 @@
List<File> jars = MavenUtil.streamJerseyJars()
.map(dependency -> MavenUtil.getArtifactJar(localRepository, dependency, properties))
.collect(Collectors.toList());
+ testLegalFiles(jars, testResult);
+ jars = MavenUtil.streamJerseySources()
+ .map(dependency -> MavenUtil.getArtifactJar(localRepository, dependency, properties))
+ .collect(Collectors.toList());
+ testLegalFiles(jars, testResult);
+ }
+
+ private void testLegalFiles(List<File> jars, TestResult testResult) throws IOException {
for (File jar : jars) {
for (String filename : new String[]{LICENSE_FILE, NOTICE_FILE}) {
JarFile jarFile = new JarFile(jar);
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java
index 0c77d69..a520868 100644
--- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 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
@@ -25,6 +25,7 @@
import java.util.Properties;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
public class ManifestTest {
private static final File localRepository = MavenUtil.getLocalMavenRepository();
@@ -63,6 +64,25 @@
}
}
+ for (File jar : jars) {
+ JarFile jarFile = new JarFile(jar);
+ String value = jarFile.getManifest().getMainAttributes().getValue("Multi-Release");
+// System.out.append("Accessing META-INF/versions").append(" of ").println(jar.getName());
+ ZipEntry versions = jarFile.getEntry("META-INF/versions/");
+ if (versions != null) {
+ if (!"true".equals(value)) {
+ testResult.exception().append("'Multi-Release: true' not set for ").println(jar.getName());
+ } else {
+ testResult.ok().append("'Multi-Release: true' set for ").println(jar.getName());
+ }
+ } else {
+ if ("true".equals(value)) {
+ testResult.exception().append("'Multi-Release: true' SET for ").println(jar.getName());
+ }
+ }
+
+ }
+
//Assertions.assertTrue(testResult.result(), "Some error occurred, see previous messages");
Assert.assertTrue("Some error occurred, see previous messages", testResult.result());
}
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java
index 288932a..317118d 100644
--- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 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
@@ -40,12 +40,14 @@
private static final DependencyPair[] jdk11multiRelease = jdk11multiRelease(properties);
private static final DependencyPair[] jdk12multiRelease = jdk12multiRelease(properties);
private static final DependencyPair[] jdk17multiRelease = jdk17multiRelease(properties);
+ private static final DependencyPair[] jdk21multiRelease = jdk21multiRelease(properties);
@Test
public void testIsJdkMultiRelease() throws IOException, XmlPullParserException {
TestResult result = testJdkVersions("11", jdk11multiRelease);
result.append(testJdkVersions("12", jdk12multiRelease));
result.append(testJdkVersions("17", jdk17multiRelease));
+ result.append(testJdkVersions("21", jdk21multiRelease));
//Assertions.assertTrue(result.result(), "Some error occurred, see previous messages");
Assert.assertTrue("Some error occurred, see previous messages", result.result());
}
@@ -54,6 +56,7 @@
throws XmlPullParserException, IOException {
final TestResult result = new TestResult();
if (dependencies == null || dependencies.length == 0) {
+ System.out.append("No dependencies found for jdk ").println(version);
return result;
}
@@ -81,6 +84,7 @@
result.exception().append("Not a multirelease jar ").append(jar.getName()).println("!");
}
ZipEntry versions = jarFile.getEntry("META-INF/versions/" + version);
+ System.out.append("Accessing META-INF/versions/").append(version).append(" of ").println(jar.getName());
if (versions == null) {
result.exception().append("No classes for JDK ").append(version).append(" for ").println(jar.getName());
}
@@ -95,6 +99,26 @@
result.append(ClassVersionChecker.checkClassVersion(jarFile, jarEntry, properties));
}
+ // Verify that number of multirelease jars matches the expected dependencies
+ StringBuilder multi = new StringBuilder();
+ int multiCnt = 0;
+ List<File> allFiles = MavenUtil.streamJerseyJars()
+ .map(dependency -> MavenUtil.getArtifactJar(localRepository, dependency, properties))
+ .collect(Collectors.toList());
+ for (File jar : files) {
+ JarFile jarFile = new JarFile(jar);
+ if (jarFile.isMultiRelease()) {
+ multiCnt++;
+ multi.append("Multirelease jar ").append(jar.getName()).append('\n');
+ }
+ }
+ if (files.size() == multiCnt) {
+ result.ok().println("There is expected number of multirelease jars");
+ } else {
+ result.exception().println("There is unexpected number of multirelease jars:");
+ result.exception().append(multi).println("");
+ }
+
return result;
}
@@ -136,12 +160,38 @@
private static DependencyPair[] jdk17multiRelease(Properties properties) {
String jerseyVersion = MavenUtil.getJerseyVersion(properties);
- if (jerseyVersion.startsWith("3")) {
+ if (jerseyVersion.startsWith("3.0")) {
return new DependencyPair[] {
new DependencyPair("org.glassfish.jersey.connectors", "jersey-helidon-connector"),
new DependencyPair("org.glassfish.jersey.ext", "jersey-spring6")
};
+ } else if (jerseyVersion.startsWith("3")) {
+ return new DependencyPair[] {
+ new DependencyPair("org.glassfish.jersey.connectors", "jersey-helidon-connector"),
+ new DependencyPair("org.glassfish.jersey.connectors", "jersey-jetty-connector"),
+ new DependencyPair("org.glassfish.jersey.connectors", "jersey-jetty-http2-connector"),
+ new DependencyPair("org.glassfish.jersey.containers", "jersey-container-jetty-http"),
+ new DependencyPair("org.glassfish.jersey.containers", "jersey-container-jetty-http2"),
+ new DependencyPair("org.glassfish.jersey.test-framework.providers", "jersey-test-framework-provider-jetty"),
+ new DependencyPair("org.glassfish.jersey.test-framework.providers",
+ "jersey-test-framework-provider-jetty-http2"),
+ new DependencyPair("org.glassfish.jersey.ext", "jersey-spring6")
+ };
}
return new DependencyPair[]{};
}
+
+ private static DependencyPair[] jdk21multiRelease(Properties properties) {
+ String jerseyVersion = MavenUtil.getJerseyVersion(properties);
+ if (jerseyVersion.startsWith("4")) {
+ return new DependencyPair[]{
+ new DependencyPair("org.glassfish.jersey.core", "jersey-common")
+ };
+ } else {
+ return new DependencyPair[]{
+ new DependencyPair("org.glassfish.jersey.bundles", "jaxrs-ri"),
+ new DependencyPair("org.glassfish.jersey.core", "jersey-common")
+ };
+ }
+ }
}