Merge pull request #4451 from senivam/jakartified.master

Jakartified.master - rebasing master on top of 3.x jakartification
diff --git a/.travis.yml b/.travis.yml
index 7ab7480..66cdd26 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,7 +10,7 @@
 jdk:
   - oraclejdk8
   - openjdk11
-  - openjdk13
+  - openjdk15
 
 cache:
   directories:
diff --git a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
index 4502bd4..9e31fd3 100644
--- a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
+++ b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
@@ -301,7 +301,7 @@
         request.method(clientRequest.getMethod());
 
         request.followRedirects(clientRequest.resolveProperty(ClientProperties.FOLLOW_REDIRECTS, true));
-        final Object readTimeout = clientRequest.getConfiguration().getProperties().get(ClientProperties.READ_TIMEOUT);
+        final Object readTimeout = clientRequest.resolveProperty(ClientProperties.READ_TIMEOUT, -1);
         if (readTimeout != null && readTimeout instanceof Integer && (Integer) readTimeout > 0) {
             request.timeout((Integer) readTimeout, TimeUnit.MILLISECONDS);
         }
diff --git a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java
index 2ad68eb..5922920 100644
--- a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java
+++ b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/TimeoutTest.java
@@ -89,7 +89,7 @@
     @Test
     public void testSlow() {
         final URI u = target().getUri();
-        ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1000);
+        ClientConfig config = new ClientConfig().property(ClientProperties.READ_TIMEOUT, 1_000);
         config.connectorProvider(new JettyConnectorProvider());
         Client c = ClientBuilder.newClient(config);
         WebTarget t = c.target(u);
@@ -103,4 +103,22 @@
             c.close();
         }
     }
+
+    @Test
+    public void testTimeoutInRequest() {
+        final URI u = target().getUri();
+        ClientConfig config = new ClientConfig();
+        config.connectorProvider(new JettyConnectorProvider());
+        Client c = ClientBuilder.newClient(config);
+        WebTarget t = c.target(u);
+        try {
+            t.path("test/timeout").request().property(ClientProperties.READ_TIMEOUT, 1_000).get();
+            fail("Timeout expected.");
+        } catch (ProcessingException e) {
+            assertThat("Unexpected processing exception cause",
+                    e.getCause(), instanceOf(TimeoutException.class));
+        } finally {
+            c.close();
+        }
+    }
 }
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 3b583e1..1745e28 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
@@ -99,8 +99,7 @@
         try {
             CompletableFuture<ClientResponse> resultFuture = execute(jerseyRequest);
 
-            Integer timeout = ClientProperties.getValue(jerseyRequest.getConfiguration().getProperties(),
-                                                        ClientProperties.READ_TIMEOUT, 0);
+            Integer timeout = jerseyRequest.resolveProperty(ClientProperties.READ_TIMEOUT, 0);
 
             return (timeout != null && timeout > 0) ? resultFuture.get(timeout, TimeUnit.MILLISECONDS)
                                                     : resultFuture.get();
@@ -183,8 +182,7 @@
                 });
 
                // connect timeout
-               Integer connectTimeout = ClientProperties.getValue(jerseyRequest.getConfiguration().getProperties(),
-                                                                  ClientProperties.CONNECT_TIMEOUT, 0);
+               Integer connectTimeout = jerseyRequest.resolveProperty(ClientProperties.CONNECT_TIMEOUT, 0);
                if (connectTimeout > 0) {
                    b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout);
                }
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/TimeoutTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/TimeoutTest.java
index 07d5110..e2e86a8 100644
--- a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/TimeoutTest.java
+++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/TimeoutTest.java
@@ -64,7 +64,6 @@
 
     @Override
     protected void configureClient(ClientConfig config) {
-        config.property(ClientProperties.READ_TIMEOUT, 1000);
         config.connectorProvider(new NettyConnectorProvider());
     }
 
@@ -78,11 +77,22 @@
     @Test
     public void testSlow() {
         try {
-            target("test/timeout").request().get();
+            target("test/timeout").property(ClientProperties.READ_TIMEOUT, 1_000).request().get();
             fail("Timeout expected.");
         } catch (ProcessingException e) {
             assertThat("Unexpected processing exception cause",
                        e.getCause(), instanceOf(TimeoutException.class));
         }
     }
+
+    @Test
+    public void testTimeoutInRequest() {
+        try {
+            target("test/timeout").request().property(ClientProperties.READ_TIMEOUT, 1_000).get();
+            fail("Timeout expected.");
+        } catch (ProcessingException e) {
+            assertThat("Unexpected processing exception cause",
+                    e.getCause(), instanceOf(TimeoutException.class));
+        }
+    }
 }
diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
index 6b7282f..5a57c72 100644
--- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
+++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
@@ -18,6 +18,8 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -323,7 +325,7 @@
         @Override
         public void commit() {
             try {
-                response.closeOutput();
+                closeOutput(response);
             } catch (final IOException e) {
                 LOGGER.log(Level.WARNING, LocalizationMessages.UNABLE_TO_CLOSE_RESPONSE(), e);
             } finally {
@@ -334,6 +336,22 @@
             }
         }
 
+        private void closeOutput(Response response) throws IOException {
+            try {
+                response.completeOutput();
+            } catch (final IOException e) {
+                throw e;
+            } catch (NoSuchMethodError e) {
+                // try older Jetty Response#closeOutput
+                try {
+                    Method method = response.getClass().getMethod("closeOutput");
+                    method.invoke(response);
+                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
+                    throw new IOException(ex);
+                }
+            }
+        }
+
         @Override
         public void failure(final Throwable error) {
             try {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java b/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java
index 248fcb9..6c2c1cb 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java
@@ -451,12 +451,19 @@
 
         @Override
         public CompletionStageRxInvoker rx() {
-            return new JerseyCompletionStageRxInvoker(this);
+            return rx(JerseyCompletionStageRxInvoker.class);
         }
 
         @Override
         public <T extends RxInvoker> T rx(Class<T> clazz) {
             if (clazz == JerseyCompletionStageRxInvoker.class) {
+                final ExecutorService configured = request().getClientConfig().getExecutorService();
+                if (configured == null) {
+                    final ExecutorService provided = executorService();
+                    if (provided != null) {
+                        request().getClientConfig().executorService(provided);
+                    }
+                }
                 return (T) new JerseyCompletionStageRxInvoker(this);
             }
             return createRxInvoker(clazz, executorService());
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java b/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java
index 04191b4..c2ab1f2 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java
@@ -16,28 +16,35 @@
 
 package org.glassfish.jersey.client;
 
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
 
 import jakarta.ws.rs.client.Client;
 import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.ClientRequestFilter;
 import jakarta.ws.rs.client.Entity;
 import jakarta.ws.rs.client.Invocation;
 import jakarta.ws.rs.client.RxInvokerProvider;
 import jakarta.ws.rs.client.SyncInvoker;
 import jakarta.ws.rs.client.WebTarget;
 import jakarta.ws.rs.core.GenericType;
+import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.ext.Provider;
 
 import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder;
 
+import org.glassfish.jersey.spi.ExecutorServiceProvider;
 import org.hamcrest.core.AllOf;
 import org.hamcrest.core.StringContains;
 import org.junit.After;
-import org.junit.Ignore;
+import org.junit.AfterClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -55,18 +62,21 @@
 
     public ClientRxTest() {
         CLIENT = ClientBuilder.newClient();
-
-        // TODO JAX-RS 2.1
-        // CLIENT_WITH_EXECUTOR = ClientBuilder.newBuilder().executorService(EXECUTOR_SERVICE).build();
-        CLIENT_WITH_EXECUTOR = null;
+        CLIENT_WITH_EXECUTOR = ClientBuilder.newBuilder().executorService(EXECUTOR_SERVICE).build();
     }
 
     @Rule
     public ExpectedException thrown = ExpectedException.none();
 
     @After
-    public void afterClass() {
+    public void afterTest() {
         CLIENT.close();
+        CLIENT_WITH_EXECUTOR.close();
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        EXECUTOR_SERVICE.shutdownNow();
     }
 
     @Test
@@ -80,20 +90,58 @@
     }
 
     @Test
-    @Ignore("TODO JAX-RS 2.1")
     public void testRxInvokerWithExecutor() {
         // implicit register (not saying that the contract is RxInvokerProvider).
-        CLIENT.register(TestRxInvokerProvider.class);
-
-        ExecutorService executorService = Executors
-                .newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("rxTest-%d").build());
-        String s = target(CLIENT_WITH_EXECUTOR).request().rx(TestRxInvoker.class).get();
+        String s = target(CLIENT_WITH_EXECUTOR).register(TestRxInvokerProvider.class).request().rx(TestRxInvoker.class).get();
 
         assertTrue("Provided RxInvoker was not used.", s.startsWith("rxTestInvoker"));
         assertTrue("Executor Service was not passed to RxInvoker", s.contains("rxTest-"));
     }
 
     @Test
+    public void testDefaultRxInvokerWithExecutor() throws ExecutionException, InterruptedException {
+        AtomicReference<String> threadName = new AtomicReference<>();
+        ClientRequestFilter threadFilter = (f) -> { threadName.set(Thread.currentThread().getName()); };
+        ClientRequestFilter abortFilter = (f) -> { f.abortWith(Response.ok().build()); };
+        try (Response r = target(CLIENT_WITH_EXECUTOR)
+                .register(threadFilter, 100)
+                .register(abortFilter, 200)
+                .request().rx().get().toCompletableFuture().get()) {
+
+            assertEquals(200, r.getStatus());
+            assertTrue("Executor Service was not passed to RxInvoker", threadName.get().contains("rxTest-"));
+        }
+    }
+
+    @Test
+    public void testRxInvokerWithExecutorServiceProvider() {
+        AtomicReference<String> threadName = new AtomicReference<>();
+        String s = target(CLIENT)
+                .register(TestRxInvokerProvider.class, 200)
+                .register(TestExecutorServiceProvider.class)
+                .request().rx(TestRxInvoker.class).get();
+
+        assertTrue("Provided RxInvoker was not used.", s.startsWith("rxTestInvoker"));
+        assertTrue("Executor Service was not passed to RxInvoker", s.contains("rxTest-"));
+    }
+
+    @Test
+    public void testDefaultRxInvokerWithExecutorServiceProvider() throws ExecutionException, InterruptedException {
+        AtomicReference<String> threadName = new AtomicReference<>();
+        ClientRequestFilter threadFilter = (f) -> { threadName.set(Thread.currentThread().getName()); };
+        ClientRequestFilter abortFilter = (f) -> { f.abortWith(Response.ok().build()); };
+        try (Response r = target(CLIENT)
+                .register(threadFilter, 100)
+                .register(abortFilter, 200)
+                .register(TestExecutorServiceProvider.class)
+                .request().rx().get().toCompletableFuture().get()) {
+
+            assertEquals(200, r.getStatus());
+            assertTrue("Executor Service was not passed to RxInvoker", threadName.get().contains("rxTest-"));
+        }
+    }
+
+    @Test
     public void testRxInvokerInvalid() {
         Invocation.Builder request = target(CLIENT).request();
         thrown.expect(IllegalArgumentException.class);
@@ -146,4 +194,17 @@
             return "rxTestInvoker" + (getExecutorService() == null ? "" : " rxTest-");
         }
     }
+
+    private static class TestExecutorServiceProvider implements ExecutorServiceProvider {
+
+        @Override
+        public ExecutorService getExecutorService() {
+            return EXECUTOR_SERVICE;
+        }
+
+        @Override
+        public void dispose(ExecutorService executorService) {
+            //@After
+        }
+    }
 }
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
index eefff1c..0f874ae 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
@@ -54,6 +54,7 @@
 
 import org.glassfish.jersey.internal.LocalizationMessages;
 import org.glassfish.jersey.internal.PropertiesDelegate;
+import org.glassfish.jersey.internal.RuntimeDelegateDecorator;
 import org.glassfish.jersey.message.MessageBodyWorkers;
 
 /**
@@ -331,7 +332,7 @@
         }
 
         try {
-            return converter.apply(HeaderUtils.asString(value, null));
+            return converter.apply(HeaderUtils.asString(value, configuration));
         } catch (ProcessingException ex) {
             throw exception(name, value, ex);
         }
@@ -450,7 +451,9 @@
             @Override
             public MediaType apply(String input) {
                 try {
-                    return MediaType.valueOf(input);
+                    return RuntimeDelegateDecorator.configured(configuration)
+                            .createHeaderDelegate(MediaType.class)
+                            .fromString(input);
                 } catch (IllegalArgumentException iae) {
                     throw new ProcessingException(iae);
                 }
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
index efa30aa..3a7748c 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
@@ -267,7 +267,8 @@
      * message entity).
      */
     public MediaType getMediaType() {
-        return singleHeader(HttpHeaders.CONTENT_TYPE, MediaType.class, MediaType::valueOf, false);
+        return singleHeader(HttpHeaders.CONTENT_TYPE, MediaType.class, RuntimeDelegateDecorator.configured(configuration)
+                .createHeaderDelegate(MediaType.class)::fromString, false);
     }
 
     /**
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java
index 9bb9e92..0bab02e 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java
@@ -68,9 +68,17 @@
    *     calls. May be {@literal null}.
    */
   public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
-    if (api != Opcodes.ASM7 && api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4) {
+    if (api != Opcodes.ASM8
+        && api != Opcodes.ASM7
+        && api != Opcodes.ASM6
+        && api != Opcodes.ASM5
+        && api != Opcodes.ASM4
+        && api != Opcodes.ASM9_EXPERIMENTAL) {
       throw new IllegalArgumentException("Unsupported api " + api);
     }
+    if (api == Opcodes.ASM9_EXPERIMENTAL) {
+      Constants.checkAsmExperimental(this);
+    }
     this.api = api;
     this.av = annotationVisitor;
   }
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationWriter.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationWriter.java
index 79a13fc..69beb1b 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationWriter.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationWriter.java
@@ -112,7 +112,7 @@
       final boolean useNamedValues,
       final ByteVector annotation,
       final AnnotationWriter previousAnnotation) {
-    super(Opcodes.ASM7);
+    super(/* latest api = */ Opcodes.ASM8);
     this.symbolTable = symbolTable;
     this.useNamedValues = useNamedValues;
     this.annotation = annotation;
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java
index 84ec8c5..66181ae 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java
@@ -30,7 +30,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.logging.Logger;
 
 /**
  * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java
@@ -44,8 +43,6 @@
  */
 public class ClassReader {
 
-  private static final Logger LOGGER = Logger.getLogger(ClassReader.class.getName());
-
   /**
    * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed
    * nor visited.
@@ -53,10 +50,11 @@
   public static final int SKIP_CODE = 1;
 
   /**
-   * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable
-   * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor
-   * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and
-   * {@link MethodVisitor#visitLineNumber} are not called).
+   * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable,
+   * LocalVariableTypeTable, LineNumberTable and MethodParameters attributes. If this flag is set
+   * these attributes are neither parsed nor visited (i.e. {@link ClassVisitor#visitSource}, {@link
+   * MethodVisitor#visitLocalVariable}, {@link MethodVisitor#visitLineNumber} and {@link
+   * MethodVisitor#visitParameter} are not called).
    */
   public static final int SKIP_DEBUG = 2;
 
@@ -193,9 +191,6 @@
     this.b = classFileBuffer;
     // Check the class' major_version. This field is after the magic and minor_version fields, which
     // use 4 and 2 bytes respectively.
-    if (checkClassVersion && readShort(classFileOffset + 6) == Opcodes.V15) {
-      LOGGER.warning("Unsupported class file major version " + readShort(classFileOffset + 6));
-    }
     if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V15) {
       throw new IllegalArgumentException(
           "Unsupported class file major version " + readShort(classFileOffset + 6));
@@ -472,6 +467,10 @@
     String nestHostClass = null;
     // - The offset of the NestMembers attribute, or 0.
     int nestMembersOffset = 0;
+    // - The offset of the PermittedSubtypes attribute, or 0
+    int permittedSubtypesOffset = 0;
+    // - The offset of the Record attribute, or 0.
+    int recordOffset = 0;
     // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
     //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
     Attribute attributes = null;
@@ -494,6 +493,8 @@
         nestHostClass = readClass(currentAttributeOffset, charBuffer);
       } else if (Constants.NEST_MEMBERS.equals(attributeName)) {
         nestMembersOffset = currentAttributeOffset;
+      } else if (Constants.PERMITTED_SUBTYPES.equals(attributeName)) {
+        permittedSubtypesOffset = currentAttributeOffset;
       } else if (Constants.SIGNATURE.equals(attributeName)) {
         signature = readUTF8(currentAttributeOffset, charBuffer);
       } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
@@ -511,6 +512,8 @@
         runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
       } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
         runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset;
+      } else if (Constants.RECORD.equals(attributeName)) {
+        recordOffset = currentAttributeOffset;
       } else if (Constants.MODULE.equals(attributeName)) {
         moduleOffset = currentAttributeOffset;
       } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) {
@@ -668,6 +671,17 @@
       }
     }
 
+    // Visit the PermittedSubtypes attribute.
+    if (permittedSubtypesOffset != 0) {
+      int numberOfPermittedSubtypes = readUnsignedShort(permittedSubtypesOffset);
+      int currentPermittedSubtypeOffset = permittedSubtypesOffset + 2;
+      while (numberOfPermittedSubtypes-- > 0) {
+        classVisitor.visitPermittedSubtypeExperimental(
+            readClass(currentPermittedSubtypeOffset, charBuffer));
+        currentPermittedSubtypeOffset += 2;
+      }
+    }
+
     // Visit the InnerClasses attribute.
     if (innerClassesOffset != 0) {
       int numberOfClasses = readUnsignedShort(innerClassesOffset);
@@ -682,6 +696,15 @@
       }
     }
 
+    // Visit Record components.
+    if (recordOffset != 0) {
+      int recordComponentsCount = readUnsignedShort(recordOffset);
+      recordOffset += 2;
+      while (recordComponentsCount-- > 0) {
+        recordOffset = readRecordComponent(classVisitor, context, recordOffset);
+      }
+    }
+
     // Visit the fields and methods.
     int fieldsCount = readUnsignedShort(currentOffset);
     currentOffset += 2;
@@ -830,6 +853,180 @@
   }
 
   /**
+   * Reads a record component and visit it.
+   *
+   * @param classVisitor the current class visitor
+   * @param context information about the class being parsed.
+   * @param recordComponentOffset the offset of the current record component.
+   * @return the offset of the first byte following the record component.
+   */
+  private int readRecordComponent(
+      final ClassVisitor classVisitor, final Context context, final int recordComponentOffset) {
+    char[] charBuffer = context.charBuffer;
+
+    int currentOffset = recordComponentOffset;
+    String name = readUTF8(currentOffset, charBuffer);
+    String descriptor = readUTF8(currentOffset + 2, charBuffer);
+    currentOffset += 4;
+
+    // Read the record component attributes (the variables are ordered as in Section 4.7 of the
+    // JVMS).
+
+    // Attribute offsets exclude the attribute_name_index and attribute_length fields.
+    // - The string corresponding to the Signature attribute, or null.
+    String signature = null;
+    // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
+    int runtimeVisibleAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
+    int runtimeInvisibleAnnotationsOffset = 0;
+    // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
+    int runtimeVisibleTypeAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
+    int runtimeInvisibleTypeAnnotationsOffset = 0;
+    // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
+    //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
+    Attribute attributes = null;
+
+    int attributesCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (attributesCount-- > 0) {
+      // Read the attribute_info's attribute_name and attribute_length fields.
+      String attributeName = readUTF8(currentOffset, charBuffer);
+      int attributeLength = readInt(currentOffset + 2);
+      currentOffset += 6;
+      // The tests are sorted in decreasing frequency order (based on frequencies observed on
+      // typical classes).
+      if (Constants.SIGNATURE.equals(attributeName)) {
+        signature = readUTF8(currentOffset, charBuffer);
+      } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleTypeAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleTypeAnnotationsOffset = currentOffset;
+      } else {
+        Attribute attribute =
+            readAttribute(
+                context.attributePrototypes,
+                attributeName,
+                currentOffset,
+                attributeLength,
+                charBuffer,
+                -1,
+                null);
+        attribute.nextAttribute = attributes;
+        attributes = attribute;
+      }
+      currentOffset += attributeLength;
+    }
+
+    RecordComponentVisitor recordComponentVisitor =
+        classVisitor.visitRecordComponent(name, descriptor, signature);
+    if (recordComponentVisitor == null) {
+      return currentOffset;
+    }
+
+    // Visit the RuntimeVisibleAnnotations attribute.
+    if (runtimeVisibleAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
+      int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                recordComponentVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeInvisibleAnnotations attribute.
+    if (runtimeInvisibleAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
+      int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                recordComponentVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeVisibleTypeAnnotations attribute.
+    if (runtimeVisibleTypeAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
+      int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the target_type, target_info and target_path fields.
+        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                recordComponentVisitor.visitTypeAnnotation(
+                    context.currentTypeAnnotationTarget,
+                    context.currentTypeAnnotationTargetPath,
+                    annotationDescriptor,
+                    /* visible = */ true),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeInvisibleTypeAnnotations attribute.
+    if (runtimeInvisibleTypeAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
+      int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the target_type, target_info and target_path fields.
+        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                recordComponentVisitor.visitTypeAnnotation(
+                    context.currentTypeAnnotationTarget,
+                    context.currentTypeAnnotationTargetPath,
+                    annotationDescriptor,
+                    /* visible = */ false),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the non standard attributes.
+    while (attributes != null) {
+      // Copy and reset the nextAttribute field so that it can also be used in FieldWriter.
+      Attribute nextAttribute = attributes.nextAttribute;
+      attributes.nextAttribute = null;
+      recordComponentVisitor.visitAttribute(attributes);
+      attributes = nextAttribute;
+    }
+
+    // Visit the end of the field.
+    recordComponentVisitor.visitEnd();
+    return currentOffset;
+  }
+
+  /**
    * Reads a JVMS field_info structure and makes the given visitor visit it.
    *
    * @param classVisitor the visitor that must visit the field.
@@ -1155,7 +1352,7 @@
     }
 
     // Visit the MethodParameters attribute.
-    if (methodParametersOffset != 0) {
+    if (methodParametersOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) {
       int parametersCount = readByte(methodParametersOffset);
       int currentParameterOffset = methodParametersOffset + 1;
       while (parametersCount-- > 0) {
@@ -1327,113 +1524,113 @@
       final int bytecodeOffset = currentOffset - bytecodeStartOffset;
       final int opcode = classBuffer[currentOffset] & 0xFF;
       switch (opcode) {
-        case Constants.NOP:
-        case Constants.ACONST_NULL:
-        case Constants.ICONST_M1:
-        case Constants.ICONST_0:
-        case Constants.ICONST_1:
-        case Constants.ICONST_2:
-        case Constants.ICONST_3:
-        case Constants.ICONST_4:
-        case Constants.ICONST_5:
-        case Constants.LCONST_0:
-        case Constants.LCONST_1:
-        case Constants.FCONST_0:
-        case Constants.FCONST_1:
-        case Constants.FCONST_2:
-        case Constants.DCONST_0:
-        case Constants.DCONST_1:
-        case Constants.IALOAD:
-        case Constants.LALOAD:
-        case Constants.FALOAD:
-        case Constants.DALOAD:
-        case Constants.AALOAD:
-        case Constants.BALOAD:
-        case Constants.CALOAD:
-        case Constants.SALOAD:
-        case Constants.IASTORE:
-        case Constants.LASTORE:
-        case Constants.FASTORE:
-        case Constants.DASTORE:
-        case Constants.AASTORE:
-        case Constants.BASTORE:
-        case Constants.CASTORE:
-        case Constants.SASTORE:
-        case Constants.POP:
-        case Constants.POP2:
-        case Constants.DUP:
-        case Constants.DUP_X1:
-        case Constants.DUP_X2:
-        case Constants.DUP2:
-        case Constants.DUP2_X1:
-        case Constants.DUP2_X2:
-        case Constants.SWAP:
-        case Constants.IADD:
-        case Constants.LADD:
-        case Constants.FADD:
-        case Constants.DADD:
-        case Constants.ISUB:
-        case Constants.LSUB:
-        case Constants.FSUB:
-        case Constants.DSUB:
-        case Constants.IMUL:
-        case Constants.LMUL:
-        case Constants.FMUL:
-        case Constants.DMUL:
-        case Constants.IDIV:
-        case Constants.LDIV:
-        case Constants.FDIV:
-        case Constants.DDIV:
-        case Constants.IREM:
-        case Constants.LREM:
-        case Constants.FREM:
-        case Constants.DREM:
-        case Constants.INEG:
-        case Constants.LNEG:
-        case Constants.FNEG:
-        case Constants.DNEG:
-        case Constants.ISHL:
-        case Constants.LSHL:
-        case Constants.ISHR:
-        case Constants.LSHR:
-        case Constants.IUSHR:
-        case Constants.LUSHR:
-        case Constants.IAND:
-        case Constants.LAND:
-        case Constants.IOR:
-        case Constants.LOR:
-        case Constants.IXOR:
-        case Constants.LXOR:
-        case Constants.I2L:
-        case Constants.I2F:
-        case Constants.I2D:
-        case Constants.L2I:
-        case Constants.L2F:
-        case Constants.L2D:
-        case Constants.F2I:
-        case Constants.F2L:
-        case Constants.F2D:
-        case Constants.D2I:
-        case Constants.D2L:
-        case Constants.D2F:
-        case Constants.I2B:
-        case Constants.I2C:
-        case Constants.I2S:
-        case Constants.LCMP:
-        case Constants.FCMPL:
-        case Constants.FCMPG:
-        case Constants.DCMPL:
-        case Constants.DCMPG:
-        case Constants.IRETURN:
-        case Constants.LRETURN:
-        case Constants.FRETURN:
-        case Constants.DRETURN:
-        case Constants.ARETURN:
-        case Constants.RETURN:
-        case Constants.ARRAYLENGTH:
-        case Constants.ATHROW:
-        case Constants.MONITORENTER:
-        case Constants.MONITOREXIT:
+        case Opcodes.NOP:
+        case Opcodes.ACONST_NULL:
+        case Opcodes.ICONST_M1:
+        case Opcodes.ICONST_0:
+        case Opcodes.ICONST_1:
+        case Opcodes.ICONST_2:
+        case Opcodes.ICONST_3:
+        case Opcodes.ICONST_4:
+        case Opcodes.ICONST_5:
+        case Opcodes.LCONST_0:
+        case Opcodes.LCONST_1:
+        case Opcodes.FCONST_0:
+        case Opcodes.FCONST_1:
+        case Opcodes.FCONST_2:
+        case Opcodes.DCONST_0:
+        case Opcodes.DCONST_1:
+        case Opcodes.IALOAD:
+        case Opcodes.LALOAD:
+        case Opcodes.FALOAD:
+        case Opcodes.DALOAD:
+        case Opcodes.AALOAD:
+        case Opcodes.BALOAD:
+        case Opcodes.CALOAD:
+        case Opcodes.SALOAD:
+        case Opcodes.IASTORE:
+        case Opcodes.LASTORE:
+        case Opcodes.FASTORE:
+        case Opcodes.DASTORE:
+        case Opcodes.AASTORE:
+        case Opcodes.BASTORE:
+        case Opcodes.CASTORE:
+        case Opcodes.SASTORE:
+        case Opcodes.POP:
+        case Opcodes.POP2:
+        case Opcodes.DUP:
+        case Opcodes.DUP_X1:
+        case Opcodes.DUP_X2:
+        case Opcodes.DUP2:
+        case Opcodes.DUP2_X1:
+        case Opcodes.DUP2_X2:
+        case Opcodes.SWAP:
+        case Opcodes.IADD:
+        case Opcodes.LADD:
+        case Opcodes.FADD:
+        case Opcodes.DADD:
+        case Opcodes.ISUB:
+        case Opcodes.LSUB:
+        case Opcodes.FSUB:
+        case Opcodes.DSUB:
+        case Opcodes.IMUL:
+        case Opcodes.LMUL:
+        case Opcodes.FMUL:
+        case Opcodes.DMUL:
+        case Opcodes.IDIV:
+        case Opcodes.LDIV:
+        case Opcodes.FDIV:
+        case Opcodes.DDIV:
+        case Opcodes.IREM:
+        case Opcodes.LREM:
+        case Opcodes.FREM:
+        case Opcodes.DREM:
+        case Opcodes.INEG:
+        case Opcodes.LNEG:
+        case Opcodes.FNEG:
+        case Opcodes.DNEG:
+        case Opcodes.ISHL:
+        case Opcodes.LSHL:
+        case Opcodes.ISHR:
+        case Opcodes.LSHR:
+        case Opcodes.IUSHR:
+        case Opcodes.LUSHR:
+        case Opcodes.IAND:
+        case Opcodes.LAND:
+        case Opcodes.IOR:
+        case Opcodes.LOR:
+        case Opcodes.IXOR:
+        case Opcodes.LXOR:
+        case Opcodes.I2L:
+        case Opcodes.I2F:
+        case Opcodes.I2D:
+        case Opcodes.L2I:
+        case Opcodes.L2F:
+        case Opcodes.L2D:
+        case Opcodes.F2I:
+        case Opcodes.F2L:
+        case Opcodes.F2D:
+        case Opcodes.D2I:
+        case Opcodes.D2L:
+        case Opcodes.D2F:
+        case Opcodes.I2B:
+        case Opcodes.I2C:
+        case Opcodes.I2S:
+        case Opcodes.LCMP:
+        case Opcodes.FCMPL:
+        case Opcodes.FCMPG:
+        case Opcodes.DCMPL:
+        case Opcodes.DCMPG:
+        case Opcodes.IRETURN:
+        case Opcodes.LRETURN:
+        case Opcodes.FRETURN:
+        case Opcodes.DRETURN:
+        case Opcodes.ARETURN:
+        case Opcodes.RETURN:
+        case Opcodes.ARRAYLENGTH:
+        case Opcodes.ATHROW:
+        case Opcodes.MONITORENTER:
+        case Opcodes.MONITOREXIT:
         case Constants.ILOAD_0:
         case Constants.ILOAD_1:
         case Constants.ILOAD_2:
@@ -1476,24 +1673,24 @@
         case Constants.ASTORE_3:
           currentOffset += 1;
           break;
-        case Constants.IFEQ:
-        case Constants.IFNE:
-        case Constants.IFLT:
-        case Constants.IFGE:
-        case Constants.IFGT:
-        case Constants.IFLE:
-        case Constants.IF_ICMPEQ:
-        case Constants.IF_ICMPNE:
-        case Constants.IF_ICMPLT:
-        case Constants.IF_ICMPGE:
-        case Constants.IF_ICMPGT:
-        case Constants.IF_ICMPLE:
-        case Constants.IF_ACMPEQ:
-        case Constants.IF_ACMPNE:
-        case Constants.GOTO:
-        case Constants.JSR:
-        case Constants.IFNULL:
-        case Constants.IFNONNULL:
+        case Opcodes.IFEQ:
+        case Opcodes.IFNE:
+        case Opcodes.IFLT:
+        case Opcodes.IFGE:
+        case Opcodes.IFGT:
+        case Opcodes.IFLE:
+        case Opcodes.IF_ICMPEQ:
+        case Opcodes.IF_ICMPNE:
+        case Opcodes.IF_ICMPLT:
+        case Opcodes.IF_ICMPGE:
+        case Opcodes.IF_ICMPGT:
+        case Opcodes.IF_ICMPLE:
+        case Opcodes.IF_ACMPEQ:
+        case Opcodes.IF_ACMPNE:
+        case Opcodes.GOTO:
+        case Opcodes.JSR:
+        case Opcodes.IFNULL:
+        case Opcodes.IFNONNULL:
           createLabel(bytecodeOffset + readShort(currentOffset + 1), labels);
           currentOffset += 3;
           break;
@@ -1526,27 +1723,27 @@
           break;
         case Constants.WIDE:
           switch (classBuffer[currentOffset + 1] & 0xFF) {
-            case Constants.ILOAD:
-            case Constants.FLOAD:
-            case Constants.ALOAD:
-            case Constants.LLOAD:
-            case Constants.DLOAD:
-            case Constants.ISTORE:
-            case Constants.FSTORE:
-            case Constants.ASTORE:
-            case Constants.LSTORE:
-            case Constants.DSTORE:
-            case Constants.RET:
+            case Opcodes.ILOAD:
+            case Opcodes.FLOAD:
+            case Opcodes.ALOAD:
+            case Opcodes.LLOAD:
+            case Opcodes.DLOAD:
+            case Opcodes.ISTORE:
+            case Opcodes.FSTORE:
+            case Opcodes.ASTORE:
+            case Opcodes.LSTORE:
+            case Opcodes.DSTORE:
+            case Opcodes.RET:
               currentOffset += 4;
               break;
-            case Constants.IINC:
+            case Opcodes.IINC:
               currentOffset += 6;
               break;
             default:
               throw new IllegalArgumentException();
           }
           break;
-        case Constants.TABLESWITCH:
+        case Opcodes.TABLESWITCH:
           // Skip 0 to 3 padding bytes.
           currentOffset += 4 - (bytecodeOffset & 3);
           // Read the default label and the number of table entries.
@@ -1559,7 +1756,7 @@
             currentOffset += 4;
           }
           break;
-        case Constants.LOOKUPSWITCH:
+        case Opcodes.LOOKUPSWITCH:
           // Skip 0 to 3 padding bytes.
           currentOffset += 4 - (bytecodeOffset & 3);
           // Read the default label and the number of switch cases.
@@ -1572,44 +1769,44 @@
             currentOffset += 8;
           }
           break;
-        case Constants.ILOAD:
-        case Constants.LLOAD:
-        case Constants.FLOAD:
-        case Constants.DLOAD:
-        case Constants.ALOAD:
-        case Constants.ISTORE:
-        case Constants.LSTORE:
-        case Constants.FSTORE:
-        case Constants.DSTORE:
-        case Constants.ASTORE:
-        case Constants.RET:
-        case Constants.BIPUSH:
-        case Constants.NEWARRAY:
-        case Constants.LDC:
+        case Opcodes.ILOAD:
+        case Opcodes.LLOAD:
+        case Opcodes.FLOAD:
+        case Opcodes.DLOAD:
+        case Opcodes.ALOAD:
+        case Opcodes.ISTORE:
+        case Opcodes.LSTORE:
+        case Opcodes.FSTORE:
+        case Opcodes.DSTORE:
+        case Opcodes.ASTORE:
+        case Opcodes.RET:
+        case Opcodes.BIPUSH:
+        case Opcodes.NEWARRAY:
+        case Opcodes.LDC:
           currentOffset += 2;
           break;
-        case Constants.SIPUSH:
+        case Opcodes.SIPUSH:
         case Constants.LDC_W:
         case Constants.LDC2_W:
-        case Constants.GETSTATIC:
-        case Constants.PUTSTATIC:
-        case Constants.GETFIELD:
-        case Constants.PUTFIELD:
-        case Constants.INVOKEVIRTUAL:
-        case Constants.INVOKESPECIAL:
-        case Constants.INVOKESTATIC:
-        case Constants.NEW:
-        case Constants.ANEWARRAY:
-        case Constants.CHECKCAST:
-        case Constants.INSTANCEOF:
-        case Constants.IINC:
+        case Opcodes.GETSTATIC:
+        case Opcodes.PUTSTATIC:
+        case Opcodes.GETFIELD:
+        case Opcodes.PUTFIELD:
+        case Opcodes.INVOKEVIRTUAL:
+        case Opcodes.INVOKESPECIAL:
+        case Opcodes.INVOKESTATIC:
+        case Opcodes.NEW:
+        case Opcodes.ANEWARRAY:
+        case Opcodes.CHECKCAST:
+        case Opcodes.INSTANCEOF:
+        case Opcodes.IINC:
           currentOffset += 3;
           break;
-        case Constants.INVOKEINTERFACE:
-        case Constants.INVOKEDYNAMIC:
+        case Opcodes.INVOKEINTERFACE:
+        case Opcodes.INVOKEDYNAMIC:
           currentOffset += 5;
           break;
-        case Constants.MULTIANEWARRAY:
+        case Opcodes.MULTIANEWARRAY:
           currentOffset += 4;
           break;
         default:
@@ -1876,113 +2073,113 @@
       // Visit the instruction at this bytecode offset.
       int opcode = classBuffer[currentOffset] & 0xFF;
       switch (opcode) {
-        case Constants.NOP:
-        case Constants.ACONST_NULL:
-        case Constants.ICONST_M1:
-        case Constants.ICONST_0:
-        case Constants.ICONST_1:
-        case Constants.ICONST_2:
-        case Constants.ICONST_3:
-        case Constants.ICONST_4:
-        case Constants.ICONST_5:
-        case Constants.LCONST_0:
-        case Constants.LCONST_1:
-        case Constants.FCONST_0:
-        case Constants.FCONST_1:
-        case Constants.FCONST_2:
-        case Constants.DCONST_0:
-        case Constants.DCONST_1:
-        case Constants.IALOAD:
-        case Constants.LALOAD:
-        case Constants.FALOAD:
-        case Constants.DALOAD:
-        case Constants.AALOAD:
-        case Constants.BALOAD:
-        case Constants.CALOAD:
-        case Constants.SALOAD:
-        case Constants.IASTORE:
-        case Constants.LASTORE:
-        case Constants.FASTORE:
-        case Constants.DASTORE:
-        case Constants.AASTORE:
-        case Constants.BASTORE:
-        case Constants.CASTORE:
-        case Constants.SASTORE:
-        case Constants.POP:
-        case Constants.POP2:
-        case Constants.DUP:
-        case Constants.DUP_X1:
-        case Constants.DUP_X2:
-        case Constants.DUP2:
-        case Constants.DUP2_X1:
-        case Constants.DUP2_X2:
-        case Constants.SWAP:
-        case Constants.IADD:
-        case Constants.LADD:
-        case Constants.FADD:
-        case Constants.DADD:
-        case Constants.ISUB:
-        case Constants.LSUB:
-        case Constants.FSUB:
-        case Constants.DSUB:
-        case Constants.IMUL:
-        case Constants.LMUL:
-        case Constants.FMUL:
-        case Constants.DMUL:
-        case Constants.IDIV:
-        case Constants.LDIV:
-        case Constants.FDIV:
-        case Constants.DDIV:
-        case Constants.IREM:
-        case Constants.LREM:
-        case Constants.FREM:
-        case Constants.DREM:
-        case Constants.INEG:
-        case Constants.LNEG:
-        case Constants.FNEG:
-        case Constants.DNEG:
-        case Constants.ISHL:
-        case Constants.LSHL:
-        case Constants.ISHR:
-        case Constants.LSHR:
-        case Constants.IUSHR:
-        case Constants.LUSHR:
-        case Constants.IAND:
-        case Constants.LAND:
-        case Constants.IOR:
-        case Constants.LOR:
-        case Constants.IXOR:
-        case Constants.LXOR:
-        case Constants.I2L:
-        case Constants.I2F:
-        case Constants.I2D:
-        case Constants.L2I:
-        case Constants.L2F:
-        case Constants.L2D:
-        case Constants.F2I:
-        case Constants.F2L:
-        case Constants.F2D:
-        case Constants.D2I:
-        case Constants.D2L:
-        case Constants.D2F:
-        case Constants.I2B:
-        case Constants.I2C:
-        case Constants.I2S:
-        case Constants.LCMP:
-        case Constants.FCMPL:
-        case Constants.FCMPG:
-        case Constants.DCMPL:
-        case Constants.DCMPG:
-        case Constants.IRETURN:
-        case Constants.LRETURN:
-        case Constants.FRETURN:
-        case Constants.DRETURN:
-        case Constants.ARETURN:
-        case Constants.RETURN:
-        case Constants.ARRAYLENGTH:
-        case Constants.ATHROW:
-        case Constants.MONITORENTER:
-        case Constants.MONITOREXIT:
+        case Opcodes.NOP:
+        case Opcodes.ACONST_NULL:
+        case Opcodes.ICONST_M1:
+        case Opcodes.ICONST_0:
+        case Opcodes.ICONST_1:
+        case Opcodes.ICONST_2:
+        case Opcodes.ICONST_3:
+        case Opcodes.ICONST_4:
+        case Opcodes.ICONST_5:
+        case Opcodes.LCONST_0:
+        case Opcodes.LCONST_1:
+        case Opcodes.FCONST_0:
+        case Opcodes.FCONST_1:
+        case Opcodes.FCONST_2:
+        case Opcodes.DCONST_0:
+        case Opcodes.DCONST_1:
+        case Opcodes.IALOAD:
+        case Opcodes.LALOAD:
+        case Opcodes.FALOAD:
+        case Opcodes.DALOAD:
+        case Opcodes.AALOAD:
+        case Opcodes.BALOAD:
+        case Opcodes.CALOAD:
+        case Opcodes.SALOAD:
+        case Opcodes.IASTORE:
+        case Opcodes.LASTORE:
+        case Opcodes.FASTORE:
+        case Opcodes.DASTORE:
+        case Opcodes.AASTORE:
+        case Opcodes.BASTORE:
+        case Opcodes.CASTORE:
+        case Opcodes.SASTORE:
+        case Opcodes.POP:
+        case Opcodes.POP2:
+        case Opcodes.DUP:
+        case Opcodes.DUP_X1:
+        case Opcodes.DUP_X2:
+        case Opcodes.DUP2:
+        case Opcodes.DUP2_X1:
+        case Opcodes.DUP2_X2:
+        case Opcodes.SWAP:
+        case Opcodes.IADD:
+        case Opcodes.LADD:
+        case Opcodes.FADD:
+        case Opcodes.DADD:
+        case Opcodes.ISUB:
+        case Opcodes.LSUB:
+        case Opcodes.FSUB:
+        case Opcodes.DSUB:
+        case Opcodes.IMUL:
+        case Opcodes.LMUL:
+        case Opcodes.FMUL:
+        case Opcodes.DMUL:
+        case Opcodes.IDIV:
+        case Opcodes.LDIV:
+        case Opcodes.FDIV:
+        case Opcodes.DDIV:
+        case Opcodes.IREM:
+        case Opcodes.LREM:
+        case Opcodes.FREM:
+        case Opcodes.DREM:
+        case Opcodes.INEG:
+        case Opcodes.LNEG:
+        case Opcodes.FNEG:
+        case Opcodes.DNEG:
+        case Opcodes.ISHL:
+        case Opcodes.LSHL:
+        case Opcodes.ISHR:
+        case Opcodes.LSHR:
+        case Opcodes.IUSHR:
+        case Opcodes.LUSHR:
+        case Opcodes.IAND:
+        case Opcodes.LAND:
+        case Opcodes.IOR:
+        case Opcodes.LOR:
+        case Opcodes.IXOR:
+        case Opcodes.LXOR:
+        case Opcodes.I2L:
+        case Opcodes.I2F:
+        case Opcodes.I2D:
+        case Opcodes.L2I:
+        case Opcodes.L2F:
+        case Opcodes.L2D:
+        case Opcodes.F2I:
+        case Opcodes.F2L:
+        case Opcodes.F2D:
+        case Opcodes.D2I:
+        case Opcodes.D2L:
+        case Opcodes.D2F:
+        case Opcodes.I2B:
+        case Opcodes.I2C:
+        case Opcodes.I2S:
+        case Opcodes.LCMP:
+        case Opcodes.FCMPL:
+        case Opcodes.FCMPG:
+        case Opcodes.DCMPL:
+        case Opcodes.DCMPG:
+        case Opcodes.IRETURN:
+        case Opcodes.LRETURN:
+        case Opcodes.FRETURN:
+        case Opcodes.DRETURN:
+        case Opcodes.ARETURN:
+        case Opcodes.RETURN:
+        case Opcodes.ARRAYLENGTH:
+        case Opcodes.ATHROW:
+        case Opcodes.MONITORENTER:
+        case Opcodes.MONITOREXIT:
           methodVisitor.visitInsn(opcode);
           currentOffset += 1;
           break;
@@ -2034,24 +2231,24 @@
           methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3);
           currentOffset += 1;
           break;
-        case Constants.IFEQ:
-        case Constants.IFNE:
-        case Constants.IFLT:
-        case Constants.IFGE:
-        case Constants.IFGT:
-        case Constants.IFLE:
-        case Constants.IF_ICMPEQ:
-        case Constants.IF_ICMPNE:
-        case Constants.IF_ICMPLT:
-        case Constants.IF_ICMPGE:
-        case Constants.IF_ICMPGT:
-        case Constants.IF_ICMPLE:
-        case Constants.IF_ACMPEQ:
-        case Constants.IF_ACMPNE:
-        case Constants.GOTO:
-        case Constants.JSR:
-        case Constants.IFNULL:
-        case Constants.IFNONNULL:
+        case Opcodes.IFEQ:
+        case Opcodes.IFNE:
+        case Opcodes.IFLT:
+        case Opcodes.IFGE:
+        case Opcodes.IFGT:
+        case Opcodes.IFLE:
+        case Opcodes.IF_ICMPEQ:
+        case Opcodes.IF_ICMPNE:
+        case Opcodes.IF_ICMPLT:
+        case Opcodes.IF_ICMPGE:
+        case Opcodes.IF_ICMPGT:
+        case Opcodes.IF_ICMPLE:
+        case Opcodes.IF_ACMPEQ:
+        case Opcodes.IF_ACMPNE:
+        case Opcodes.GOTO:
+        case Opcodes.JSR:
+        case Opcodes.IFNULL:
+        case Opcodes.IFNONNULL:
           methodVisitor.visitJumpInsn(
               opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]);
           currentOffset += 3;
@@ -2132,7 +2329,7 @@
             currentOffset += 4;
           }
           break;
-        case Constants.TABLESWITCH:
+        case Opcodes.TABLESWITCH:
           {
             // Skip 0 to 3 padding bytes.
             currentOffset += 4 - (currentBytecodeOffset & 3);
@@ -2149,7 +2346,7 @@
             methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table);
             break;
           }
-        case Constants.LOOKUPSWITCH:
+        case Opcodes.LOOKUPSWITCH:
           {
             // Skip 0 to 3 padding bytes.
             currentOffset += 4 - (currentBytecodeOffset & 3);
@@ -2167,30 +2364,30 @@
             methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values);
             break;
           }
-        case Constants.ILOAD:
-        case Constants.LLOAD:
-        case Constants.FLOAD:
-        case Constants.DLOAD:
-        case Constants.ALOAD:
-        case Constants.ISTORE:
-        case Constants.LSTORE:
-        case Constants.FSTORE:
-        case Constants.DSTORE:
-        case Constants.ASTORE:
-        case Constants.RET:
+        case Opcodes.ILOAD:
+        case Opcodes.LLOAD:
+        case Opcodes.FLOAD:
+        case Opcodes.DLOAD:
+        case Opcodes.ALOAD:
+        case Opcodes.ISTORE:
+        case Opcodes.LSTORE:
+        case Opcodes.FSTORE:
+        case Opcodes.DSTORE:
+        case Opcodes.ASTORE:
+        case Opcodes.RET:
           methodVisitor.visitVarInsn(opcode, classBuffer[currentOffset + 1] & 0xFF);
           currentOffset += 2;
           break;
-        case Constants.BIPUSH:
-        case Constants.NEWARRAY:
+        case Opcodes.BIPUSH:
+        case Opcodes.NEWARRAY:
           methodVisitor.visitIntInsn(opcode, classBuffer[currentOffset + 1]);
           currentOffset += 2;
           break;
-        case Constants.SIPUSH:
+        case Opcodes.SIPUSH:
           methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1));
           currentOffset += 3;
           break;
-        case Constants.LDC:
+        case Opcodes.LDC:
           methodVisitor.visitLdcInsn(readConst(classBuffer[currentOffset + 1] & 0xFF, charBuffer));
           currentOffset += 2;
           break;
@@ -2199,14 +2396,14 @@
           methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer));
           currentOffset += 3;
           break;
-        case Constants.GETSTATIC:
-        case Constants.PUTSTATIC:
-        case Constants.GETFIELD:
-        case Constants.PUTFIELD:
-        case Constants.INVOKEVIRTUAL:
-        case Constants.INVOKESPECIAL:
-        case Constants.INVOKESTATIC:
-        case Constants.INVOKEINTERFACE:
+        case Opcodes.GETSTATIC:
+        case Opcodes.PUTSTATIC:
+        case Opcodes.GETFIELD:
+        case Opcodes.PUTFIELD:
+        case Opcodes.INVOKEVIRTUAL:
+        case Opcodes.INVOKESPECIAL:
+        case Opcodes.INVOKESTATIC:
+        case Opcodes.INVOKEINTERFACE:
           {
             int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)];
             int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
@@ -2227,7 +2424,7 @@
             }
             break;
           }
-        case Constants.INVOKEDYNAMIC:
+        case Opcodes.INVOKEDYNAMIC:
           {
             int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)];
             int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
@@ -2249,19 +2446,19 @@
             currentOffset += 5;
             break;
           }
-        case Constants.NEW:
-        case Constants.ANEWARRAY:
-        case Constants.CHECKCAST:
-        case Constants.INSTANCEOF:
+        case Opcodes.NEW:
+        case Opcodes.ANEWARRAY:
+        case Opcodes.CHECKCAST:
+        case Opcodes.INSTANCEOF:
           methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer));
           currentOffset += 3;
           break;
-        case Constants.IINC:
+        case Opcodes.IINC:
           methodVisitor.visitIincInsn(
               classBuffer[currentOffset + 1] & 0xFF, classBuffer[currentOffset + 2]);
           currentOffset += 3;
           break;
-        case Constants.MULTIANEWARRAY:
+        case Opcodes.MULTIANEWARRAY:
           methodVisitor.visitMultiANewArrayInsn(
               readClass(currentOffset + 1, charBuffer), classBuffer[currentOffset + 3] & 0xFF);
           currentOffset += 4;
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassVisitor.java
index 7f97d47..3c384de 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassVisitor.java
@@ -30,9 +30,9 @@
 /**
  * A visitor to visit a Java class. The methods of this class must be called in the following order:
  * {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
- * visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
- * visitAttribute} )* ( {@code visitNestMember} | {@code visitInnerClass} | {@code visitField} |
- * {@code visitMethod} )* {@code visitEnd}.
+ * visitPermittedSubtype} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
+ * visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
+ * visitInnerClass} | {@code visitField} | {@code visitMethod} )* {@code visitEnd}.
  *
  * @author Eric Bruneton
  */
@@ -61,14 +61,23 @@
    * Constructs a new {@link ClassVisitor}.
    *
    * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
+   *     Opcodes#ASM8}.
    * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
    *     null.
    */
   public ClassVisitor(final int api, final ClassVisitor classVisitor) {
-    if (api != Opcodes.ASM7 && api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4) {
+    if (api != Opcodes.ASM8
+        && api != Opcodes.ASM7
+        && api != Opcodes.ASM6
+        && api != Opcodes.ASM5
+        && api != Opcodes.ASM4
+        && api != Opcodes.ASM9_EXPERIMENTAL) {
       throw new IllegalArgumentException("Unsupported api " + api);
     }
+    if (api == Opcodes.ASM9_EXPERIMENTAL) {
+      Constants.checkAsmExperimental(this);
+    }
     this.api = api;
     this.cv = classVisitor;
   }
@@ -241,6 +250,24 @@
   }
 
   /**
+   * <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
+   * will break existing code using it</b>. Visits a permitted subtypes. A permitted subtypes is one
+   * of the allowed subtypes of the current class.
+   *
+   * @param permittedSubtype the internal name of a permitted subtype.
+   * @deprecated this API is experimental.
+   */
+  @Deprecated
+  public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
+    if (api != Opcodes.ASM9_EXPERIMENTAL) {
+      throw new UnsupportedOperationException("This feature requires ASM9_EXPERIMENTAL");
+    }
+    if (cv != null) {
+      cv.visitPermittedSubtypeExperimental(permittedSubtype);
+    }
+  }
+
+  /**
    * Visits information about an inner class. This inner class is not necessarily a member of the
    * class being visited.
    *
@@ -260,6 +287,27 @@
   }
 
   /**
+   * Visits a record component of the class.
+   *
+   * @param name the record component name.
+   * @param descriptor the record component descriptor (see {@link Type}).
+   * @param signature the record component signature. May be {@literal null} if the record component
+   *     type does not use generic types.
+   * @return a visitor to visit this record component annotations and attributes, or {@literal null}
+   *     if this class visitor is not interested in visiting these annotations and attributes.
+   */
+  public RecordComponentVisitor visitRecordComponent(
+      final String name, final String descriptor, final String signature) {
+    if (api < Opcodes.ASM8) {
+      throw new UnsupportedOperationException("This feature requires ASM8");
+    }
+    if (cv != null) {
+      return cv.visitRecordComponent(name, descriptor, signature);
+    }
+    return null;
+  }
+
+  /**
    * Visits a field of the class.
    *
    * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassWriter.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassWriter.java
index 5bdf68c..3e6f763 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassWriter.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassWriter.java
@@ -177,6 +177,26 @@
   /** The 'classes' array of the NestMembers attribute, or {@literal null}. */
   private ByteVector nestMemberClasses;
 
+  /** The number_of_classes field of the PermittedSubtypes attribute, or 0. */
+  private int numberOfPermittedSubtypeClasses;
+
+  /** The 'classes' array of the PermittedSubtypes attribute, or {@literal null}. */
+  private ByteVector permittedSubtypeClasses;
+
+  /**
+   * The record components of this class, stored in a linked list of {@link RecordComponentWriter}
+   * linked via their {@link RecordComponentWriter#delegate} field. This field stores the first
+   * element of this list.
+   */
+  private RecordComponentWriter firstRecordComponent;
+
+  /**
+   * The record components of this class, stored in a linked list of {@link RecordComponentWriter}
+   * linked via their {@link RecordComponentWriter#delegate} field. This field stores the last
+   * element of this list.
+   */
+  private RecordComponentWriter lastRecordComponent;
+
   /**
    * The first non standard attribute of this class. The next ones can be accessed with the {@link
    * Attribute#nextAttribute} field. May be {@literal null}.
@@ -234,7 +254,7 @@
    *     maximum stack size nor the stack frames will be computed for these methods</i>.
    */
   public ClassWriter(final ClassReader classReader, final int flags) {
-    super(Opcodes.ASM7);
+    super(/* latest api = */ Opcodes.ASM8);
     symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
     if ((flags & COMPUTE_FRAMES) != 0) {
       this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
@@ -352,6 +372,22 @@
     nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index);
   }
 
+  /**
+   * <b>Experimental, use at your own risk.</b>
+   *
+   * @param permittedSubtype the internal name of a permitted subtype.
+   * @deprecated this API is experimental.
+   */
+  @Override
+  @Deprecated
+  public final void visitPermittedSubtypeExperimental(final String permittedSubtype) {
+    if (permittedSubtypeClasses == null) {
+      permittedSubtypeClasses = new ByteVector();
+    }
+    ++numberOfPermittedSubtypeClasses;
+    permittedSubtypeClasses.putShort(symbolTable.addConstantClass(permittedSubtype).index);
+  }
+
   @Override
   public final void visitInnerClass(
       final String name, final String outerName, final String innerName, final int access) {
@@ -378,6 +414,19 @@
   }
 
   @Override
+  public final RecordComponentVisitor visitRecordComponent(
+      final String name, final String descriptor, final String signature) {
+    RecordComponentWriter recordComponentWriter =
+        new RecordComponentWriter(symbolTable, name, descriptor, signature);
+    if (firstRecordComponent == null) {
+      firstRecordComponent = recordComponentWriter;
+    } else {
+      lastRecordComponent.delegate = recordComponentWriter;
+    }
+    return lastRecordComponent = recordComponentWriter;
+  }
+
+  @Override
   public final FieldVisitor visitField(
       final int access,
       final String name,
@@ -447,6 +496,7 @@
       size += methodWriter.computeMethodInfoSize();
       methodWriter = (MethodWriter) methodWriter.mv;
     }
+
     // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
     int attributesCount = 0;
     if (innerClasses != null) {
@@ -526,6 +576,24 @@
       size += 8 + nestMemberClasses.length;
       symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
     }
+    if (permittedSubtypeClasses != null) {
+      ++attributesCount;
+      size += 8 + permittedSubtypeClasses.length;
+      symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES);
+    }
+    int recordComponentCount = 0;
+    int recordSize = 0;
+    if (firstRecordComponent != null) {
+      RecordComponentWriter recordComponentWriter = firstRecordComponent;
+      while (recordComponentWriter != null) {
+        ++recordComponentCount;
+        recordSize += recordComponentWriter.computeRecordComponentInfoSize();
+        recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
+      }
+      ++attributesCount;
+      size += 8 + recordSize;
+      symbolTable.addConstantUtf8(Constants.RECORD);
+    }
     if (firstAttribute != null) {
       attributesCount += firstAttribute.getAttributeCount();
       size += firstAttribute.computeAttributesSize(symbolTable);
@@ -630,6 +698,24 @@
           .putShort(numberOfNestMemberClasses)
           .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
     }
+    if (permittedSubtypeClasses != null) {
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES))
+          .putInt(permittedSubtypeClasses.length + 2)
+          .putShort(numberOfPermittedSubtypeClasses)
+          .putByteArray(permittedSubtypeClasses.data, 0, permittedSubtypeClasses.length);
+    }
+    if (firstRecordComponent != null) {
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.RECORD))
+          .putInt(recordSize + 2)
+          .putShort(recordComponentCount);
+      RecordComponentWriter recordComponentWriter = firstRecordComponent;
+      while (recordComponentWriter != null) {
+        recordComponentWriter.putRecordComponentInfo(result);
+        recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
+      }
+    }
     if (firstAttribute != null) {
       firstAttribute.putAttributes(symbolTable, result);
     }
@@ -666,6 +752,10 @@
     nestHostClassIndex = 0;
     numberOfNestMemberClasses = 0;
     nestMemberClasses = null;
+    numberOfPermittedSubtypeClasses = 0;
+    permittedSubtypeClasses = null;
+    firstRecordComponent = null;
+    lastRecordComponent = null;
     firstAttribute = null;
     compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
     new ClassReader(classFile, 0, /* checkClassVersion = */ false)
@@ -694,6 +784,11 @@
       methodWriter.collectAttributePrototypes(attributePrototypes);
       methodWriter = (MethodWriter) methodWriter.mv;
     }
+    RecordComponentWriter recordComponentWriter = firstRecordComponent;
+    while (recordComponentWriter != null) {
+      recordComponentWriter.collectAttributePrototypes(attributePrototypes);
+      recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
+    }
     return attributePrototypes.toArray();
   }
 
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Constants.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Constants.java
index 6cbbf42..89330ef 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Constants.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Constants.java
@@ -26,6 +26,10 @@
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 // THE POSSIBILITY OF SUCH DAMAGE.
 package jersey.repackaged.org.objectweb.asm;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.regex.Pattern;
 
 /**
  * Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
@@ -34,7 +38,7 @@
  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
  * @author Eric Bruneton
  */
-final class Constants implements Opcodes {
+final class Constants {
 
   // The ClassFile attribute names, in the order they are defined in
   // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
@@ -68,6 +72,8 @@
   static final String MODULE_MAIN_CLASS = "ModuleMainClass";
   static final String NEST_HOST = "NestHost";
   static final String NEST_MEMBERS = "NestMembers";
+  static final String PERMITTED_SUBTYPES = "PermittedSubtypes";
+  static final String RECORD = "Record";
 
   // ASM specific access flags.
   // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
@@ -140,7 +146,7 @@
   // Constants to convert between normal and wide jump instructions.
 
   // The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP.
-  static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO;
+  static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - Opcodes.GOTO;
 
   // Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.
 
@@ -153,25 +159,62 @@
 
   // ASM specific opcodes, used for long forward jump instructions.
 
-  static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA;
-  static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA;
-  static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA;
-  static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA;
-  static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA;
-  static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA;
-  static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA;
-  static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA;
-  static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA;
-  static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA;
-  static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA;
-  static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA;
-  static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA;
-  static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA;
-  static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA;
-  static final int ASM_JSR = JSR + ASM_OPCODE_DELTA;
-  static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA;
-  static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
+  static final int ASM_IFEQ = Opcodes.IFEQ + ASM_OPCODE_DELTA;
+  static final int ASM_IFNE = Opcodes.IFNE + ASM_OPCODE_DELTA;
+  static final int ASM_IFLT = Opcodes.IFLT + ASM_OPCODE_DELTA;
+  static final int ASM_IFGE = Opcodes.IFGE + ASM_OPCODE_DELTA;
+  static final int ASM_IFGT = Opcodes.IFGT + ASM_OPCODE_DELTA;
+  static final int ASM_IFLE = Opcodes.IFLE + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPEQ = Opcodes.IF_ICMPEQ + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPNE = Opcodes.IF_ICMPNE + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPLT = Opcodes.IF_ICMPLT + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPGE = Opcodes.IF_ICMPGE + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPGT = Opcodes.IF_ICMPGT + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPLE = Opcodes.IF_ICMPLE + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ACMPEQ = Opcodes.IF_ACMPEQ + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ACMPNE = Opcodes.IF_ACMPNE + ASM_OPCODE_DELTA;
+  static final int ASM_GOTO = Opcodes.GOTO + ASM_OPCODE_DELTA;
+  static final int ASM_JSR = Opcodes.JSR + ASM_OPCODE_DELTA;
+  static final int ASM_IFNULL = Opcodes.IFNULL + ASM_IFNULL_OPCODE_DELTA;
+  static final int ASM_IFNONNULL = Opcodes.IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
   static final int ASM_GOTO_W = 220;
 
   private Constants() {}
+
+  static void checkAsmExperimental(final Object caller) {
+    Class<?> callerClass = caller.getClass();
+    String internalName = callerClass.getName().replace('.', '/');
+    if (!isWhitelisted(internalName)) {
+      checkIsPreview(callerClass.getClassLoader().getResourceAsStream(internalName + ".class"));
+    }
+  }
+
+  static boolean isWhitelisted(final String internalName) {
+    if (!internalName.startsWith("org/objectweb/asm/")) {
+      return false;
+    }
+    String member = "(Annotation|Class|Field|Method|Module|RecordComponent|Signature)";
+    return internalName.contains("Test$")
+        || Pattern.matches(
+            "org/objectweb/asm/util/Trace" + member + "Visitor(\\$.*)?", internalName)
+        || Pattern.matches(
+            "org/objectweb/asm/util/Check" + member + "Adapter(\\$.*)?", internalName);
+  }
+
+  static void checkIsPreview(final InputStream classInputStream) {
+    if (classInputStream == null) {
+      throw new IllegalStateException("Bytecode not available, can't check class version");
+    }
+    int minorVersion;
+    try (DataInputStream callerClassStream = new DataInputStream(classInputStream); ) {
+      callerClassStream.readInt();
+      minorVersion = callerClassStream.readUnsignedShort();
+    } catch (IOException ioe) {
+      throw new IllegalStateException("I/O error, can't check class version", ioe);
+    }
+    if (minorVersion != 0xFFFF) {
+      throw new IllegalStateException(
+          "ASM9_EXPERIMENTAL can only be used by classes compiled with --enable-preview");
+    }
+  }
 }
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldVisitor.java
index 64d39d3..eb531cf 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldVisitor.java
@@ -38,7 +38,8 @@
 
   /**
    * The ASM API version implemented by this visitor. The value of this field must be one of {@link
-   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
+   * Opcodes#ASM8}.
    */
   protected final int api;
 
@@ -49,7 +50,8 @@
    * Constructs a new {@link FieldVisitor}.
    *
    * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
+   *     Opcodes#ASM8}.
    */
   public FieldVisitor(final int api) {
     this(api, null);
@@ -59,14 +61,23 @@
    * Constructs a new {@link FieldVisitor}.
    *
    * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
+   *     Opcodes#ASM8}.
    * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
    *     null.
    */
   public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
-    if (api != Opcodes.ASM7 && api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4) {
+    if (api != Opcodes.ASM8
+        && api != Opcodes.ASM7
+        && api != Opcodes.ASM6
+        && api != Opcodes.ASM5
+        && api != Opcodes.ASM4
+        && api != Opcodes.ASM9_EXPERIMENTAL) {
       throw new IllegalArgumentException("Unsupported api " + api);
     }
+    if (api == Opcodes.ASM9_EXPERIMENTAL) {
+      Constants.checkAsmExperimental(this);
+    }
     this.api = api;
     this.fv = fieldVisitor;
   }
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldWriter.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldWriter.java
index 93f4802..95617fb 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldWriter.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldWriter.java
@@ -124,7 +124,7 @@
       final String descriptor,
       final String signature,
       final Object constantValue) {
-    super(Opcodes.ASM7);
+    super(/* latest api = */ Opcodes.ASM8);
     this.symbolTable = symbolTable;
     this.accessFlags = access;
     this.nameIndex = symbolTable.addConstantUtf8(name);
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodVisitor.java
index e88b6bf..b59be69 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodVisitor.java
@@ -80,9 +80,17 @@
    *     be null.
    */
   public MethodVisitor(final int api, final MethodVisitor methodVisitor) {
-    if (api != Opcodes.ASM7 && api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4) {
+    if (api != Opcodes.ASM8
+        && api != Opcodes.ASM7
+        && api != Opcodes.ASM6
+        && api != Opcodes.ASM5
+        && api != Opcodes.ASM4
+        && api != Opcodes.ASM9_EXPERIMENTAL) {
       throw new IllegalArgumentException("Unsupported api " + api);
     }
+    if (api == Opcodes.ASM9_EXPERIMENTAL) {
+      Constants.checkAsmExperimental(this);
+    }
     this.api = api;
     this.mv = methodVisitor;
   }
@@ -534,7 +542,7 @@
             || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
       throw new UnsupportedOperationException(REQUIRES_ASM5);
     }
-    if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
+    if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) {
       throw new UnsupportedOperationException("This feature requires ASM7");
     }
     if (mv != null) {
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodWriter.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodWriter.java
index ecded66..9231c56 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodWriter.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodWriter.java
@@ -592,7 +592,7 @@
       final String signature,
       final String[] exceptions,
       final int compute) {
-    super(Opcodes.ASM7);
+    super(/* latest api = */ Opcodes.ASM8);
     this.symbolTable = symbolTable;
     this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
     this.nameIndex = symbolTable.addConstantUtf8(name);
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleVisitor.java
index ff5062b..3285b09 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleVisitor.java
@@ -66,9 +66,17 @@
    *     be null.
    */
   public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
-    if (api != Opcodes.ASM7 && api != Opcodes.ASM6) {
+    if (api != Opcodes.ASM8
+        && api != Opcodes.ASM7
+        && api != Opcodes.ASM6
+        && api != Opcodes.ASM5
+        && api != Opcodes.ASM4
+        && api != Opcodes.ASM9_EXPERIMENTAL) {
       throw new IllegalArgumentException("Unsupported api " + api);
     }
+    if (api == Opcodes.ASM9_EXPERIMENTAL) {
+      Constants.checkAsmExperimental(this);
+    }
     this.api = api;
     this.mv = moduleVisitor;
   }
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleWriter.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleWriter.java
index 9877ceb..1932905 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleWriter.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleWriter.java
@@ -94,7 +94,7 @@
   private int mainClassIndex;
 
   ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) {
-    super(Opcodes.ASM7);
+    super(/* latest api = */ Opcodes.ASM8);
     this.symbolTable = symbolTable;
     this.moduleNameIndex = name;
     this.moduleFlags = access;
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java
index 6a1019f..9e26c7b 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java
@@ -47,6 +47,15 @@
   int ASM5 = 5 << 16 | 0 << 8;
   int ASM6 = 6 << 16 | 0 << 8;
   int ASM7 = 7 << 16 | 0 << 8;
+  int ASM8 = 8 << 16 | 0 << 8;
+
+  /**
+   * <i>Experimental, use at your own risk. This field will be renamed when it becomes stable, this
+   * will break existing code using it. Only code compiled with --enable-preview can use this.</i>
+   *
+   * @deprecated This API is experimental.
+   */
+  @Deprecated int ASM9_EXPERIMENTAL = 1 << 24 | 9 << 16 | 0 << 8;
 
   /*
    * Internal flags used to redirect calls to deprecated methods. For instance, if a visitOldStuff
@@ -307,7 +316,7 @@
   int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
   int ACC_ANNOTATION = 0x2000; // class
   int ACC_ENUM = 0x4000; // class(?) field inner
-  int ACC_MANDATED = 0x8000; // parameter, module, module *
+  int ACC_MANDATED = 0x8000; // field, method, parameter, module, module *
   int ACC_MODULE = 0x8000; // class
 
   // ASM specific access flags.
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentVisitor.java
new file mode 100644
index 0000000..f361d2f
--- /dev/null
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentVisitor.java
@@ -0,0 +1,150 @@
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+package jersey.repackaged.org.objectweb.asm;
+
+/**
+ * A visitor to visit a record component. The methods of this class must be called in the following
+ * order: ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code visitAttribute} )* {@code
+ * visitEnd}.
+ *
+ * @author Remi Forax
+ * @author Eric Bruneton
+ */
+public abstract class RecordComponentVisitor {
+  /**
+   * The ASM API version implemented by this visitor. The value of this field must be {@link
+   * Opcodes#ASM8}.
+   */
+  protected final int api;
+
+  /**
+   * The record visitor to which this visitor must delegate method calls. May be {@literal null}.
+   */
+  /*package-private*/ RecordComponentVisitor delegate;
+
+  /**
+   * Constructs a new {@link RecordComponentVisitor}.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM8}.
+   */
+  public RecordComponentVisitor(final int api) {
+    this(api, null);
+  }
+
+  /**
+   * Constructs a new {@link RecordComponentVisitor}.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM8}.
+   * @param recordComponentVisitor the record component visitor to which this visitor must delegate
+   *     method calls. May be null.
+   */
+  public RecordComponentVisitor(
+      final int api, final RecordComponentVisitor recordComponentVisitor) {
+    if (api != Opcodes.ASM8
+        && api != Opcodes.ASM7
+        && api != Opcodes.ASM6
+        && api != Opcodes.ASM5
+        && api != Opcodes.ASM4
+        && api != Opcodes.ASM9_EXPERIMENTAL) {
+      throw new IllegalArgumentException("Unsupported api " + api);
+    }
+    if (api == Opcodes.ASM9_EXPERIMENTAL) {
+      Constants.checkAsmExperimental(this);
+    }
+    this.api = api;
+    this.delegate = recordComponentVisitor;
+  }
+
+  /**
+   * The record visitor to which this visitor must delegate method calls. May be {@literal null}.
+   *
+   * @return the record visitor to which this visitor must delegate method calls or {@literal null}.
+   */
+  public RecordComponentVisitor getDelegate() {
+    return delegate;
+  }
+
+  /**
+   * Visits an annotation of the record component.
+   *
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    if (delegate != null) {
+      return delegate.visitAnnotation(descriptor, visible);
+    }
+    return null;
+  }
+
+  /**
+   * Visits an annotation on a type in the record component signature.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
+   *     TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
+   *     {@link TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    if (delegate != null) {
+      return delegate.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+    }
+    return null;
+  }
+
+  /**
+   * Visits a non standard attribute of the record component.
+   *
+   * @param attribute an attribute.
+   */
+  public void visitAttribute(final Attribute attribute) {
+    if (delegate != null) {
+      delegate.visitAttribute(attribute);
+    }
+  }
+
+  /**
+   * Visits the end of the record component. This method, which is the last one to be called, is
+   * used to inform the visitor that everything have been visited.
+   */
+  public void visitEnd() {
+    if (delegate != null) {
+      delegate.visitEnd();
+    }
+  }
+}
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentWriter.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentWriter.java
new file mode 100644
index 0000000..8248170
--- /dev/null
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentWriter.java
@@ -0,0 +1,225 @@
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+package jersey.repackaged.org.objectweb.asm;
+
+final class RecordComponentWriter extends RecordComponentVisitor {
+  /** Where the constants used in this RecordComponentWriter must be stored. */
+  private final SymbolTable symbolTable;
+
+  // Note: fields are ordered as in the record_component_info structure, and those related to
+  // attributes are ordered as in Section 4.7 of the JVMS.
+
+  /** The name_index field of the Record attribute. */
+  private final int nameIndex;
+
+  /** The descriptor_index field of the the Record attribute. */
+  private final int descriptorIndex;
+
+  /**
+   * The signature_index field of the Signature attribute of this record component, or 0 if there is
+   * no Signature attribute.
+   */
+  private int signatureIndex;
+
+  /**
+   * The last runtime visible annotation of this record component. The previous ones can be accessed
+   * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeVisibleAnnotation;
+
+  /**
+   * The last runtime invisible annotation of this record component. The previous ones can be
+   * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeInvisibleAnnotation;
+
+  /**
+   * The last runtime visible type annotation of this record component. The previous ones can be
+   * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
+
+  /**
+   * The last runtime invisible type annotation of this record component. The previous ones can be
+   * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
+
+  /**
+   * The first non standard attribute of this record component. The next ones can be accessed with
+   * the {@link Attribute#nextAttribute} field. May be {@literal null}.
+   *
+   * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
+   * firstAttribute is actually the last attribute visited in {@link #visitAttribute(Attribute)}.
+   * The {@link #putRecordComponentInfo(ByteVector)} method writes the attributes in the order
+   * defined by this list, i.e. in the reverse order specified by the user.
+   */
+  private Attribute firstAttribute;
+
+  /**
+   * Constructs a new {@link RecordComponentWriter}.
+   *
+   * @param symbolTable where the constants used in this RecordComponentWriter must be stored.
+   * @param name the record component name.
+   * @param descriptor the record component descriptor (see {@link Type}).
+   * @param signature the record component signature. May be {@literal null}.
+   */
+  RecordComponentWriter(
+      final SymbolTable symbolTable,
+      final String name,
+      final String descriptor,
+      final String signature) {
+    super(/* latest api = */ Opcodes.ASM8);
+    this.symbolTable = symbolTable;
+    this.nameIndex = symbolTable.addConstantUtf8(name);
+    this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
+    if (signature != null) {
+      this.signatureIndex = symbolTable.addConstantUtf8(signature);
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the FieldVisitor abstract class
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    if (visible) {
+      return lastRuntimeVisibleAnnotation =
+          AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
+    } else {
+      return lastRuntimeInvisibleAnnotation =
+          AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
+    }
+  }
+
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    if (visible) {
+      return lastRuntimeVisibleTypeAnnotation =
+          AnnotationWriter.create(
+              symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
+    } else {
+      return lastRuntimeInvisibleTypeAnnotation =
+          AnnotationWriter.create(
+              symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
+    }
+  }
+
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    // Store the attributes in the <i>reverse</i> order of their visit by this method.
+    attribute.nextAttribute = firstAttribute;
+    firstAttribute = attribute;
+  }
+
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the size of the record component JVMS structure generated by this
+   * RecordComponentWriter. Also adds the names of the attributes of this record component in the
+   * constant pool.
+   *
+   * @return the size in bytes of the record_component_info of the Record attribute.
+   */
+  int computeRecordComponentInfoSize() {
+    // name_index, descriptor_index and attributes_count fields use 6 bytes.
+    int size = 6;
+    size += Attribute.computeAttributesSize(symbolTable, 0, signatureIndex);
+    size +=
+        AnnotationWriter.computeAnnotationsSize(
+            lastRuntimeVisibleAnnotation,
+            lastRuntimeInvisibleAnnotation,
+            lastRuntimeVisibleTypeAnnotation,
+            lastRuntimeInvisibleTypeAnnotation);
+    if (firstAttribute != null) {
+      size += firstAttribute.computeAttributesSize(symbolTable);
+    }
+    return size;
+  }
+
+  /**
+   * Puts the content of the record component generated by this RecordComponentWriter into the given
+   * ByteVector.
+   *
+   * @param output where the record_component_info structure must be put.
+   */
+  void putRecordComponentInfo(final ByteVector output) {
+    output.putShort(nameIndex).putShort(descriptorIndex);
+    // Compute and put the attributes_count field.
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    int attributesCount = 0;
+    if (signatureIndex != 0) {
+      ++attributesCount;
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      ++attributesCount;
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      ++attributesCount;
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      ++attributesCount;
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      ++attributesCount;
+    }
+    if (firstAttribute != null) {
+      attributesCount += firstAttribute.getAttributeCount();
+    }
+    output.putShort(attributesCount);
+    Attribute.putAttributes(symbolTable, 0, signatureIndex, output);
+    AnnotationWriter.putAnnotations(
+        symbolTable,
+        lastRuntimeVisibleAnnotation,
+        lastRuntimeInvisibleAnnotation,
+        lastRuntimeVisibleTypeAnnotation,
+        lastRuntimeInvisibleTypeAnnotation,
+        output);
+    if (firstAttribute != null) {
+      firstAttribute.putAttributes(symbolTable, output);
+    }
+  }
+
+  /**
+   * Collects the attributes of this record component into the given set of attribute prototypes.
+   *
+   * @param attributePrototypes a set of attribute prototypes.
+   */
+  final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
+    attributePrototypes.addAttributes(firstAttribute);
+  }
+}
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/SymbolTable.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/SymbolTable.java
index 31bf0bf..e52af51 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/SymbolTable.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/SymbolTable.java
@@ -31,11 +31,11 @@
  * The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
  * table entries of a class.
  *
+ * @author Eric Bruneton
  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS
  *     4.4</a>
  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
  *     4.7.23</a>
- * @author Eric Bruneton
  */
 final class SymbolTable {
 
@@ -1046,8 +1046,10 @@
     // bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool
     // and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified
     // while adding the given bootstrap method to it, in the rest of this method.
-    for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
-      addConstant(bootstrapMethodArgument);
+    int numBootstrapArguments = bootstrapMethodArguments.length;
+    int[] bootstrapMethodArgumentIndexes = new int[numBootstrapArguments];
+    for (int i = 0; i < numBootstrapArguments; i++) {
+      bootstrapMethodArgumentIndexes[i] = addConstant(bootstrapMethodArguments[i]).index;
     }
 
     // Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to
@@ -1062,10 +1064,10 @@
                 bootstrapMethodHandle.getDesc(),
                 bootstrapMethodHandle.isInterface())
             .index);
-    int numBootstrapArguments = bootstrapMethodArguments.length;
+
     bootstrapMethodsAttribute.putShort(numBootstrapArguments);
-    for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
-      bootstrapMethodsAttribute.putShort(addConstant(bootstrapMethodArgument).index);
+    for (int i = 0; i < numBootstrapArguments; i++) {
+      bootstrapMethodsAttribute.putShort(bootstrapMethodArgumentIndexes[i]);
     }
 
     // Compute the length and the hash code of the bootstrap method.
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
index d73e368..a43e3ba 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
@@ -16,6 +16,7 @@
 
 package org.glassfish.jersey.server.internal.scanning;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.annotation.Annotation;
@@ -24,10 +25,12 @@
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.Set;
+import java.util.logging.Logger;
 
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.ext.Provider;
 
+import jersey.repackaged.org.objectweb.asm.RecordComponentVisitor;
 import org.glassfish.jersey.internal.OsgiRegistry;
 import org.glassfish.jersey.internal.util.ReflectionHelper;
 import org.glassfish.jersey.server.internal.LocalizationMessages;
@@ -145,7 +148,7 @@
     }
 
     public void process(final String name, final InputStream in) throws IOException {
-        new ClassReader(in).accept(classVisitor, 0);
+        new ClassReaderWrapper(in).accept(classVisitor, 0);
     }
 
     //
@@ -166,9 +169,10 @@
         private boolean isAnnotated;
 
         private AnnotatedClassVisitor() {
-            super(Opcodes.ASM7);
+            super(Opcodes.ASM8);
         }
 
+        @Override
         public void visit(final int version, final int access, final String name,
                           final String signature, final String superName, final String[] interfaces) {
             className = name;
@@ -176,11 +180,13 @@
             isAnnotated = false;
         }
 
+        @Override
         public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
             isAnnotated |= annotations.contains(desc);
             return null;
         }
 
+        @Override
         public void visitInnerClass(final String name, final String outerName,
                                     final String innerName, final int access) {
             // If the name of the class that was visited is equal
@@ -195,6 +201,7 @@
             }
         }
 
+        @Override
         public void visitEnd() {
             if (isScoped && isAnnotated) {
                 // Correctly scoped and annotated
@@ -203,11 +210,13 @@
             }
         }
 
+        @Override
         public void visitOuterClass(final String string, final String string0,
                                     final String string1) {
             // Do nothing
         }
 
+        @Override
         public FieldVisitor visitField(final int i, final String string,
                                        final String string0, final String string1,
                                        final Object object) {
@@ -215,14 +224,17 @@
             return null;
         }
 
+        @Override
         public void visitSource(final String string, final String string0) {
             // Do nothing
         }
 
+        @Override
         public void visitAttribute(final Attribute attribute) {
             // Do nothing
         }
 
+        @Override
         public MethodVisitor visitMethod(final int i, final String string,
                                          final String string0, final String string1,
                                          final String[] string2) {
@@ -230,19 +242,34 @@
             return null;
         }
 
+        @Override
         public ModuleVisitor visitModule(final String name, final int access, final String version) {
             // Do nothing
             return null;
         }
 
+        @Override
         public void visitNestHost(final String nestHost) {
             // do nothing
         }
 
+        @Override
         public void visitNestMember(final String nestMember) {
             // do nothing
         }
 
+        @Override
+        public void visitPermittedSubtypeExperimental(String permittedSubtype) {
+            // do nothing
+        }
+
+        @Override
+        public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) {
+            // do nothing
+            return null;
+        }
+
+        @Override
         public AnnotationVisitor visitTypeAnnotation(
                 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
             //do nothing
@@ -273,4 +300,80 @@
         }
 
     }
+
+    private static class ClassReaderWrapper {
+        private static final Logger LOGGER = Logger.getLogger(ClassReader.class.getName());
+        private static final int WARN_VERSION = Opcodes.V15;
+        private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
+
+        private final byte[] b;
+        private ClassReaderWrapper(InputStream inputStream) throws IOException {
+            this.b = readStream(inputStream);
+        }
+
+        private void accept(final ClassVisitor classVisitor, final int parsingOptions) {
+            final int originalVersion = getMajorVersion(b);
+            if (originalVersion == WARN_VERSION + 1) {
+                // temporarily downgrade version to bypass check in ASM
+                setMajorVersion(WARN_VERSION, b);
+                LOGGER.warning("Unsupported class file major version " + originalVersion);
+            }
+            final ClassReader classReader = new ClassReader(b);
+            setMajorVersion(originalVersion, b);
+            classReader.accept(classVisitor, parsingOptions);
+        }
+
+        /**
+         * Sets major version number in given bytes of class (unsigned two bytes at
+         * offset 6).
+         *
+         * @param majorVersion
+         *            major version of bytecode to set
+         * @param b
+         *            bytes of class
+         * @see #getMajorVersion(byte[])
+         */
+        private static void setMajorVersion(final int majorVersion, final byte[] b) {
+            b[6] = (byte) (majorVersion >>> 8);
+            b[7] = (byte) majorVersion;
+        }
+
+        /**
+         * Gets major version number from given bytes of class (unsigned two bytes
+         * at offset 6).
+         *
+         * @param b
+         *            bytes of class
+         * @return major version of bytecode
+         * @see <a href=
+         *      "https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.1">JVMS 4.1 - The class File Format</a>
+         */
+        private static int getMajorVersion(final byte[] b) {
+            return ((b[6] & 0xFF) << 8) | (b[7] & 0xFF);
+        }
+
+        /**
+         * Reads the given input stream and returns its content as a byte array.
+         *
+         * @param inputStream an input stream.
+         * @return the content of the given input stream.
+         * @throws IOException if a problem occurs during reading.
+         */
+        private static byte[] readStream(final InputStream inputStream) throws IOException {
+            if (inputStream == null) {
+                throw new IOException("Class not found");
+            }
+            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+                byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
+                int bytesRead;
+                while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
+                    outputStream.write(data, 0, bytesRead);
+                }
+                outputStream.flush();
+                return outputStream.toByteArray();
+            } finally {
+                inputStream.close();
+            }
+        }
+    }
 }
diff --git a/docs/src/main/docbook/async.xml b/docs/src/main/docbook/async.xml
index 824f095..6d7d082 100644
--- a/docs/src/main/docbook/async.xml
+++ b/docs/src/main/docbook/async.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2012, 2020 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
@@ -224,7 +224,7 @@
                 multiple callbacks using varags.
             </para>
             <para>
-                As some async requests may take long time to process the client may decide to terminate it's connection to the
+                As some async requests may take long time to process the client may decide to terminate its connection to the
                 server before the response has been resumed or before it has been fully written to the client. To deal with these
                 use cases a &lit.jaxrs.container.ConnectionCallback; can be used. This callback will be executed only if the
                 connection was prematurely terminated or lost while the response is being written to the back client. Note that
diff --git a/docs/src/main/docbook/bean-validation.xml b/docs/src/main/docbook/bean-validation.xml
index 2436d92..e12fe3c 100644
--- a/docs/src/main/docbook/bean-validation.xml
+++ b/docs/src/main/docbook/bean-validation.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2013, 2020 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
@@ -84,8 +84,8 @@
 
         <para>
             As stated in <xref linkend="deployment.autodiscoverable"/>, Jersey Bean Validation is one of the modules where you
-            don't need to explicitly register it's &lit.jaxrs.core.Feature;s (&jersey.ext.ValidationFeature;) on the
-            server as it's features are automatically discovered and registered when you add the
+            don't need to explicitly register its &lit.jaxrs.core.Feature;s (&jersey.ext.ValidationFeature;) on the
+            server as its features are automatically discovered and registered when you add the
             &lit.jersey-bean-validation; module to your classpath.
             There are three Jersey specific properties that could disable automatic discovery and registration of Jersey Bean
             Validation integration module:
diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml
index 4a8d6a8..e0b01cb 100644
--- a/docs/src/main/docbook/client.xml
+++ b/docs/src/main/docbook/client.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2010, 2020 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
@@ -233,7 +233,7 @@
             </title>
 
             <para>
-                JAX-RS Client API is a designed to allow fluent programming model. This means, a construction of a
+                JAX-RS Client API is designed to allow fluent programming model. This means, a construction of a
                 &lit.jaxrs.client.Client; instance, from which a &lit.jaxrs.client.WebTarget; is created, from which a
                 request &jaxrs.client.Invocation; is built and invoked can be chained in a single "flow" of invocations.
                 The individual steps of the flow will be shown in the following sections.
@@ -345,7 +345,7 @@
 webTarget.register(FilterForExampleCom.class);</programlisting>
 
                 The configuration principles used in JAX-RS client API apply to &lit.jaxrs.client.WebTarget; as well. Each
-                &lit.jaxrs.client.WebTarget; instance inherits a configuration from it's parent (either a client or another
+                &lit.jaxrs.client.WebTarget; instance inherits a configuration from its parent (either a client or another
                 web target) and can be further custom-configured without affecting the configuration of the parent component.
                 In this case, the <literal>FilterForExampleCom</literal> will be registered only in the
                 <literal>webTarget</literal> and not in <literal>client</literal>. So, the <literal>client</literal>
@@ -739,7 +739,7 @@
 clientConfig.connectorProvider(new GrizzlyConnectorProvider());
 Client client = ClientBuilder.newClient(clientConfig);</programlisting>
 
-            &lit.jaxrs.client.Client; accepts as as a constructor argument a &lit.jaxrs.core.Configurable; instance. Jersey
+            &lit.jaxrs.client.Client; accepts as a constructor argument a &lit.jaxrs.core.Configurable; instance. Jersey
             implementation of the &lit.jaxrs.core.Configurable; provider for the client is &lit.jersey.client.ClientConfig;.
             By using the Jersey &lit.jersey.client.ClientConfig; you can configure the custom
             &lit.jersey.client.ConnectorProvider;
@@ -965,7 +965,7 @@
                         <emphasis>UNIVERSAL:</emphasis> Combination of basic and digest authentication. The feature works in non-preemptive
                           mode which means that it sends requests without authentication information. If <literal>401</literal> status
                           code is returned, the request is repeated and an appropriate authentication is used based on the
-                          authentication requested in the response (defined in <literal>WWW-Authenticate</literal> HTTP header. The feature
+                          authentication requested in the response (defined in <literal>WWW-Authenticate</literal> HTTP header). The feature
                           remembers which authentication requests were successful for given URI and next time tries to preemptively
                           authenticate against this URI with latest successful authentication method.
                     </para>
@@ -999,4 +999,135 @@
 
 
     </section>
+
+    <section>
+        <title>InvocationInterceptors</title>
+        <para>
+            Suppose a case that the start of the request is to be logged and even measured.
+            This can be done by <literal>ClientRequestFilter</literal>, which is usually invoked before the request is wired on the network.
+            However, the filter may be called as a last of the filters in the chain. Sure, it can have the highest priority,
+            but the other filters can have the very same priority! Some long-running operations can be performed before the
+            measuring can actually start. Even worse, the filter may even be skipped from the chain by the previous
+            <literal>#abortWith</literal>!
+        </para>
+        <section>
+            <title>PreInvocationInterceptor</title>
+            <para>
+                For this, <literal>PreInvocationInterceptor</literal>, the code that executes before the <literal>ClientRequestFilters</literal>
+                are invoked, has been added to the client request chain. Jersey ensures all the interceptors are invoked with each request.
+                The interceptor contains a single <literal>#beforeRequest</literal> method, which corresponds to <literal>ClientRequestFilter</literal>:
+            </para>
+            <programlisting language="java">
+                /**
+                * The method invoked before the request starts.
+                * @param requestContext the request context shared with
+                * ClientRequestFilter.
+                */
+                void beforeRequest(ClientRequestContext requestContext);
+            </programlisting>
+            <para>
+                Note that only a single <literal>#abortWith</literal> is allowed in all <literal>PreInvocationInterceptors</literal>,
+                otherwise an <literal>IllegalStateException</literal> is thrown.
+                All the exceptions accumulated in <literal>PreInvocationInterceptors</literal> are thrown in a single Exception,
+                available through <literal>#getSuppressed()</literal>.
+            </para>
+        </section>
+        <section>
+            <title>PostInvocationInterceptor</title>
+            <para>
+                Similarly, <literal>ClientResponseFilter</literal> seems to be a good place where the total time of the HTTP request can be measured,
+                but similarly to <literal>ClientRequestFilter</literal>, the response filter may not be invoked at all.
+                For this, <literal>PostInvocationInterceptor</literal> has been introduced. Jersey runtime ensures that every
+                <literal>PostInvocationInterceptor</literal> is called. Since an exception can occur during the HTTP request,
+                <literal>PostInvocationInterceptor</literal> comes with two methods:
+            </para>
+            <programlisting language="java">
+                /**
+                * The method is invoked after a request when no
+                * is thrown, or the Throwables are resolved
+                * by previous PostInvocationInterceptor.
+                *
+                * @param requestContext the request context.
+                * @param responseContext the response context
+                * of the original Response or response context
+                * defined by the new resolving Response.
+                */
+                void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext);
+
+                /**
+                * The method is invoked after a Throwable is caught
+                * during the client request chain processing.
+                *
+                * @param requestContext the request context.
+                * @param exceptionContext the context available to handle the
+                * caught Throwables.
+                */
+                void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext);
+            </programlisting>
+            <para>
+                The <literal>#afterRequest</literal> method is executed when no exception has been thrown during the HTTP request,
+                <literal>#onException</literal> method is executed if the exception has been thrown during the request.
+                It is possible to set a response in <literal>#onException</literal>, and the consecutive <literal>PostInvocationInterceptor</literal> will
+                execute its <literal>#afterRequest</literal> method.
+
+                The measuring example can looks as follows, then:
+            </para>
+            <programlisting language="java" linenumbering="numbered">
+                String response = ClientBuilder.newClient().target("path")
+                    .register(new PreInvocationInterceptor() {
+                        @Override
+                        public void beforeRequest(ClientRequestContext requestContext) {
+                            startTime = System.currentTimeMillis();
+                        }
+                    })
+                    .register(new PostInvocationInterceptor() {
+                        @Override
+                        public void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext) {
+                            logDuration(System.currentTimeMillis() - startTime);
+                        }
+                        @Override
+                        public void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext) {
+                            logDuration(System.currentTimeMillis() - startTime);
+                        }
+                    })
+                    .request().get().readEntity(String.class);
+            </programlisting>
+        </section>
+    </section>
+    <section>
+        <title>InvocationBuilderListener</title>
+        <para>
+            InvocationBuilderListener is an interface that is inspired by Microprofile REST Client <literal>RestClientBuilderListener</literal>
+            and it contains a single method:
+        </para>
+        <programlisting language="java">
+            /**
+            * Whenever an Invocation.Builder is created, (i.e. when
+            * WebTarget#request() is called, this method would be invoked.
+            *
+            * @param context the updated InvocationBuilderContext.
+            */
+            void onNewBuilder(InvocationBuilderContext context);
+        </programlisting>
+        <para>
+            <literal>InvocationBuilderContext</literal> a subset of methods of the <literal>Invocation.Builder</literal>. It can be used to call the default
+            values of the <literal>Invocation.Builder</literal>. Since it is invoked at the time <literal>Invocation.Builder</literal> is instantiated, any consequent
+            calls of the <literal>Invocation.Builder</literal>‘s methods will replace the defaults set by the <literal>InvocationBuilderListener</literal>.
+
+            For instance, if all the HTTP requests should contain a custom HTTP header,
+            there can be created a feature that would be registered on the client:
+        </para>
+        <programlisting language="java" linenumbering="numbered">
+            public static class MyFeature implements Feature {
+                @Override
+                public boolean configure(FeatureContext context) {
+                    context.register(
+                        (InvocationBuilderListener)(l)-&gt;
+                        l.getHeaders().add("MY_HEADER", "MY_VALUE")
+                    );
+                    return true;
+                }
+            }
+        </programlisting>
+    </section>
 </chapter>
diff --git a/docs/src/main/docbook/custom-di.xml b/docs/src/main/docbook/custom-di.xml
index a6bc2d2..4229553 100644
--- a/docs/src/main/docbook/custom-di.xml
+++ b/docs/src/main/docbook/custom-di.xml
@@ -37,7 +37,7 @@
     </para>
 
     <para>
-        Jersey user guide can by no means supply an exhaustive documentation of HK2 API in it's entire scope.
+        Jersey user guide can by no means supply an exhaustive documentation of HK2 API in its entire scope.
         This chapter only points out the most common scenarios related
         to dependency injection in Jersey and suggests possible options to implement these scenarios.
         It is highly recommended to check out the &hk2.link; website and read HK2 documentation in order to get
@@ -65,8 +65,8 @@
         as a good example that will help me demonstrate implementation of the use cases described above.
         The following examples should work on top of Jersey Servlet integration module. The approach that will be
         demonstrated could be further generalized.
-        Bellow i will show how to make actual Servlet &jee6.servlet.HttpSession; injectable into JAX-RS components
-        and how to make this injection work with a custom inject annotation type. Finally, i will demonstrate
+        Below we will show how to make actual Servlet &jee6.servlet.HttpSession; injectable into JAX-RS components
+        and how to make this injection work with a custom inject annotation type. Finally, we will demonstrate
         how you can write &lit.jee6.servlet.HttpSession;-scoped JAX-RS resources.
     </para>
 
@@ -487,7 +487,7 @@
             The first and very important aspect of writing your own &lit.jersey.server.spi.ComponentProvider;
             in Jersey is to store the actual HK2 &hk2.ServiceLocator; instance that will be passed to you as
             the only argument of the provider <literal>initialize</literal> method.
-            Your component provider instance will not get injected at all so this is more less your only chance
+            Your component provider instance will not get injected at all so this is more or less your only chance
             to get access to the HK2 runtime of your application. Please bear in mind, that at the time when
             your component provider methods get invoked, the &lit.hk2.ServiceLocator; is not fully configured yet.
             This limitation applies to all component provider methods, as the main goal of any component provider
@@ -513,7 +513,7 @@
         </para>
 
         <para>
-            The implementation of the <literal>PerSessionFactory</literal> is is also included above.
+            The implementation of the <literal>PerSessionFactory</literal> is also included above.
             Please note that as opposed to a component provider implementation that should never itself rely
             on an injection support, the factory bound by our component provider would get injected just fine,
             since it is only instantiated later, once the Jersey runtime for the application is fully
diff --git a/docs/src/main/docbook/declarative-linking.xml b/docs/src/main/docbook/declarative-linking.xml
index 0f4286c..54786c5 100644
--- a/docs/src/main/docbook/declarative-linking.xml
+++ b/docs/src/main/docbook/declarative-linking.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2010, 2020 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
@@ -98,7 +98,7 @@
 }</programlisting>
 
         <para>
-            After a call to<literal>WidgetsResource#get</literal>, the Jersey runtime will inject the value
+            After a call to <literal>WidgetsResource#get</literal>, the Jersey runtime will inject the value
             <literal>"/context/widgets"</literal>
             <footnote>
                 <para>
@@ -143,7 +143,7 @@
         <para>
             The <literal>@ProvideLink</literal> annotation can be repeated to add links to different entities using different
             options. Entities are defined via the <literal>value</literal> property. If the entities are similar in structure they
-            can also declared as an array. <literal>@ProvideLink</literal> also works with class hierarchies, e.g., contributions
+            can also be declared as an array. <literal>@ProvideLink</literal> also works with class hierarchies, e.g., contributions
             defined for a superclass will also be injected into the derived classes (interfaces are not supported).
 
             <programlisting language="java">@ProvideLink(value = Order.class,rel = "self",
diff --git a/docs/src/main/docbook/deployment.xml b/docs/src/main/docbook/deployment.xml
index 062b454..9318428 100644
--- a/docs/src/main/docbook/deployment.xml
+++ b/docs/src/main/docbook/deployment.xml
@@ -73,7 +73,7 @@
         <para>
             Compared to &lit.jaxrs.core.Application;, the &lit.jersey.server.ResourceConfig; provides advanced capabilities
             to simplify registration of JAX-RS components, such as scanning for root resource and provider classes in a provided
-            classpath or a in a set of package names etc. All JAX-RS component classes that are either manually registered or
+            classpath or a set of package names etc. All JAX-RS component classes that are either manually registered or
             found during scanning are automatically added to the set of classes that are returned by
             <literal>getClasses</literal>. For example, the following application class that extends from
             &lit.jersey.server.ResourceConfig; scans during deployment for JAX-RS components in packages
@@ -1101,7 +1101,7 @@
                 <para>
                     As explained in <link linkend="servlet-app-glassfish">2.3.1</link> , you don't need to add any specific
                     dependencies on GlassFish, Jersey is already packaged within GlassFish. You only need to add the
-                    <literal>provided</literal>-scoped dependencies to you project to be able to compile it. At runtime,
+                    <literal>provided</literal>-scoped dependencies to your project to be able to compile it. At runtime,
                     GlassFish will make sure that your application has access to the Jersey libraries.
                 </para>
 
diff --git a/docs/src/main/docbook/entity-filtering.xml b/docs/src/main/docbook/entity-filtering.xml
index 0acc5e0..7bf2570 100644
--- a/docs/src/main/docbook/entity-filtering.xml
+++ b/docs/src/main/docbook/entity-filtering.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2013, 2020 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
@@ -217,7 +217,7 @@
 
         <para>
             In the next section the entity-filtering features will be illustrated on a project-tracking application that
-            contains three classes in it's domain model and few resources (only <literal>Project</literal> resource will be
+            contains three classes in its domain model and few resources (only <literal>Project</literal> resource will be
             shown in this chapter). The full source code for the example application can be found in Jersey
             &jersey.github.ef.example.link;.
         </para>
@@ -493,9 +493,9 @@
             to all the child nodes. Fields and child nodes that do not match at least a single active scope are filtered out.
             When the scope matching is performed, annotations applied to the domain model classes and fields
             are used to compute the scope for each particular component of the model. If there are no annotations on the class
-            or it's fields, the default scope is assumed. During the filtering, first, the annotations on root model class
-            and it's fields are considered. For all composite fields that have not been filtered out, the annotations on the
-            referenced child class and it's fields are considered next, and so on.
+            or its fields, the default scope is assumed. During the filtering, first, the annotations on root model class
+            and its fields are considered. For all composite fields that have not been filtered out, the annotations on the
+            referenced child class and its fields are considered next, and so on.
         </para>
 
         <section>
@@ -625,7 +625,7 @@
             <para>
                 As mentioned above you can define applied entity-filtering scopes using a property set either in the client
                 run-time &lit.jaxrs.core.Configuration; (see <xref linkend="ef.example.client.registration"/>) or by
-                passing the entity-filtering annotations during a creation of an individual request to be sent to server.
+                passing the entity-filtering annotations during a creation of an individual request to be sent to the server.
 
                 <example>
                     <title>Client - Request entity-filtering annotations</title>
@@ -764,7 +764,7 @@
             <itemizedlist>
                 <listitem>
                     <para>&jersey.message.filtering.EntityProcessor;</para>
-                    <para>Implementations of this SPI are invoked to process entity class and it's members. Custom
+                    <para>Implementations of this SPI are invoked to process entity class and its members. Custom
                         implementations can extend from &jersey.message.filtering.AbstractEntityProcessor;.</para>
                 </listitem>
                 <listitem>
diff --git a/docs/src/main/docbook/filters.xml b/docs/src/main/docbook/filters.xml
index fa2ec6f..ec25557 100644
--- a/docs/src/main/docbook/filters.xml
+++ b/docs/src/main/docbook/filters.xml
@@ -513,7 +513,7 @@
             it is annotated with &lit.jaxrs.NameBinding;. The <literal>@Compress</literal> is applied on the
             resource method <literal>getVeryLongString()</literal> and on the interceptor
             <literal>GZIPWriterInterceptor</literal>. The interceptor will be executed only if any resource method
-            with such a annotation will be executed. In our example case the interceptor will be executed only for
+            with such an annotation will be executed. In our example case the interceptor will be executed only for
             the <literal>getVeryLongString()</literal> method. The interceptor will not be executed for method
             <literal>getHello()</literal>. In this example the reason is probably clear. We would like to compress
             only long data and we do not need to compress the short response of "Hello World!".
@@ -536,7 +536,7 @@
             just an edge case which will not be used so often.
         </para>
         <para>
-            Note that <emphasis>global filters are executed always</emphasis>, so even for resource methods
+            Note that <emphasis>global filters are always executed</emphasis>, even for resource methods
             which have any name binding annotations.
         </para>
     </section>
@@ -638,7 +638,7 @@
         <para>
             It's a good practice to assign a priority to filters and interceptors. Use &jaxrs.Priorities; class which
             defines standardized priorities in JAX-RS for different usages, rather than inventing your
-            own priorities. So, when you for example write an authentication filter you would assign a priority 1000 which
+            own priorities. For example, when you write an authentication filter you would assign a priority 1000 which
             is the value of &lit.jaxrs.Priorities;<literal>.AUTHENTICATION</literal>. The following example
             shows the filter from the beginning
             of this chapter with a priority assigned.
diff --git a/docs/src/main/docbook/getting-started.xml b/docs/src/main/docbook/getting-started.xml
index e2c9300..fdb64a8 100644
--- a/docs/src/main/docbook/getting-started.xml
+++ b/docs/src/main/docbook/getting-started.xml
@@ -176,7 +176,7 @@
 
             In this unit test, a Grizzly container is first started and server application is deployed in the
             test <literal>setUp()</literal> method by a static call to <literal>Main.startServer()</literal>.
-            Next, a JAX-RS client components are created in the same test set-up method. First a new JAX-RS client
+            Next, JAX-RS client components are created in the same test set-up method. First a new JAX-RS client
             instance <literal>c</literal> is built and then a JAX-RS web target component pointing to the context root of our
             application deployed at <literal>http://localhost:8080/myapp/</literal> (a value of
             <literal>Main.BASE_URI</literal> constant) is stored into a <literal>target</literal> field of the unit test class.
diff --git a/docs/src/main/docbook/jaxrs-resources.xml b/docs/src/main/docbook/jaxrs-resources.xml
index 9ec514f..5f73ad4 100644
--- a/docs/src/main/docbook/jaxrs-resources.xml
+++ b/docs/src/main/docbook/jaxrs-resources.xml
@@ -612,7 +612,7 @@
         <para>If the path of the request URL is "printers" then the resource methods not annotated with &jaxrs.Path;
             will be selected. If the request path of the request URL is "printers/list" then first the root resource class
             will be matched and then the sub-resource methods that match "list" will be selected, which in this case
-            is the sub-resource method<literal>getListOfPrinters</literal>. So, in this example hierarchical matching
+            is the sub-resource method <literal>getListOfPrinters</literal>. So, in this example hierarchical matching
             on the path of the request URL is performed.
         </para>
 
diff --git a/docs/src/main/docbook/mbw.xml b/docs/src/main/docbook/mbw.xml
index cff05c4..b61881b 100644
--- a/docs/src/main/docbook/mbw.xml
+++ b/docs/src/main/docbook/mbw.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2012, 2020 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
@@ -416,7 +416,7 @@
                     <literal>@Consumes("application/xml")</literal>,
                     therefore for purpose of de-serialization of entity for the <literal>postMyBean()</literal> method,
                     only requests with entities represented as <literal>"application/xml"</literal>
-                    media type will match the method. However, this method might be executed for for entity types that are sub classes
+                    media type will match the method. However, this method might be executed for entity types that are sub classes
                     or super classes of the declared generic type on the &lit.jaxrs.ext.MessageBodyReader; will be also considered.
                     It is a responsibility of the <literal>isReadable</literal> method to decide whether it is able
                     to de-serialize the entity and type comparison is one of the basic decision steps.
@@ -592,7 +592,7 @@
                     Determine the media type of the response.
                 </para>
                 <para>
-                    In our case. for resource method <literal>getMyBean</literal>
+                    In our case, for resource method <literal>getMyBean</literal>
                     annotated with <literal>@Produces("application/xml")</literal>, the media type will be
                     <literal>"application/xml"</literal>.
                 </para>
@@ -649,7 +649,7 @@
                 <stepalternatives>
                     <step>
                         <para>
-                            Otherwise, the server runtime MUST generate a generate an
+                            Otherwise, the server runtime MUST generate an
                             <literal>InternalServerErrorException</literal>, a subclass of
                             <literal>WebApplicationException</literal> with its status set to 500, and no entity and the client
                             runtime MUST generate a <literal>ProcessingException</literal>.
diff --git a/docs/src/main/docbook/media.xml b/docs/src/main/docbook/media.xml
index e0dca33..301c6c2 100644
--- a/docs/src/main/docbook/media.xml
+++ b/docs/src/main/docbook/media.xml
@@ -267,7 +267,7 @@
 
                 <para>
                     As stated in the <xref linkend="deployment.autodiscoverable"/> as well as earlier in this chapter, MOXy media
-                    module is one of the modules where you don't need to explicitly register it's &lit.jaxrs.core.Feature;s
+                    module is one of the modules where you don't need to explicitly register its &lit.jaxrs.core.Feature;s
                     (&lit.jersey.media.MoxyJsonFeature;) in your client/server &jaxrs.core.Configurable; as this feature is
                     automatically discovered and registered when you add &lit.jersey-media-moxy; module to your class-path.
                 </para>
@@ -458,7 +458,7 @@
 
                 <para>
                     As stated in <xref linkend="deployment.autodiscoverable"/> JSON-Processing media module is one of the
-                    modules where you don't need to explicitly register it's
+                    modules where you don't need to explicitly register its
                     &lit.jaxrs.core.Feature;s (&lit.jersey.media.JsonProcessingFeature;) in your client/server
                     &jaxrs.core.Configurable; as this feature is automatically discovered and registered when you add
                     &lit.jersey-media-json-processing; module to your classpath.
@@ -1507,7 +1507,7 @@
             <title>Client</title>
 
             <para>
-                &jersey.media.multipart.MultiPart; class (or it's subclasses) can be used as an entry point to using
+                &jersey.media.multipart.MultiPart; class (or it's subclasses) can be used as an entry point to use
                 &lit.jersey-media-multipart; module on the client side. This class represents a
                 <link xlink:href='&wikipedia.uri;MIME#Multipart_messages'>MIME multipart message</link> and is able
                 to hold an arbitrary number of &jersey.media.multipart.BodyPart;s. Default media type is
@@ -1696,7 +1696,7 @@
                             <para>
                                 A <literal>List</literal> or <literal>Collection</literal> of
                                 &lit.jersey.media.multipart.FormDataBodyPart;.
-                                The value of the parameter will one or more named body parts with the same name or
+                                The value of the parameter will be one or more named body parts with the same name or
                                 &lit.null; if such a named body part is not present.
                             </para>
                         </listitem>
@@ -1711,7 +1711,7 @@
                             <para>
                                 A <literal>List</literal> or <literal>Collection</literal> of
                                 &lit.jersey.media.multipart.FormDataContentDisposition;.
-                                The value of the parameter will one or more content dispositions of the named body parts with the
+                                The value of the parameter will be one or more content dispositions of the named body parts with the
                                 same name or &lit.null; if such a named body part is not present.
                             </para>
                         </listitem>
diff --git a/docs/src/main/docbook/migration.xml b/docs/src/main/docbook/migration.xml
index b502ce7..c639909 100644
--- a/docs/src/main/docbook/migration.xml
+++ b/docs/src/main/docbook/migration.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2012, 2020 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,7 +40,7 @@
                             module) are now being built with Java SE 8 and with 1.8 language level.
                         </para>
                         <para>
-                            As a consequential change, one of the modules was dropped, the<literal>rx-client-jsr166e</literal>.
+                            As a consequential change, one of the modules was dropped, the <literal>rx-client-jsr166e</literal>.
                             This implementation relied on the
                             <literal>ConcurrentHashMapV8</literal>
                             and was made redundant by the JDK upgrade. Please use
@@ -52,7 +52,7 @@
                             of Java 8 support with Spring 3.x versions.
                         </para>
                         <para>
-                            Jersey proprietary reactive client API has beed dropped and replaced by JAX-RS 2.1 Reactive Client API.
+                            Jersey proprietary reactive client API has been dropped and replaced by JAX-RS 2.1 Reactive Client API.
                             The backwards compatibility rule couldn't be respected in this case, since the JAX-RS API are based on
                             what was done in Jersey and there were unresolvable code incompatibilities.
                         </para>
@@ -217,11 +217,11 @@
                             http header, the URI was resolved against
                             <emphasis>base uri</emphasis>
                             of the application. This behaviour was not correct, as pointed out by &jersey.jira.2883;. With this
-                            change, the URI is, by default, resolved against<emphasis>request base uri</emphasis>.
+                            change, the URI is, by default, resolved against <emphasis>request base uri</emphasis>.
                         </para>
                         <para>
-                            For example, having a resource at<literal>http://server.com/api/management/user</literal>, that
-                            returns response with<literal>Location: foo</literal>, while the root of the app is
+                            For example, having a resource at <literal>http://server.com/api/management/user</literal>, that
+                            returns response with <literal>Location: foo</literal>, while the root of the app is
                             <literal>http://server.com/api</literal>, the resulting URI will be:
                             <simplelist>
                                 <member>with Jersey 2.21 and earlier:
@@ -247,7 +247,7 @@
                         <para>
                             Alternatively, the entire URI resolving logic can be switched off by newly
                             introduced &jersey.server.ServerProperties.LOCATION_HEADER_RELATIVE_URI_RESOLUTION_DISABLED; property.
-                            If the value is<literal>true</literal>, Jersey will not change the URI contained in the
+                            If the value is <literal>true</literal>, Jersey will not change the URI contained in the
                             <literal>Location</literal>
                             header at all (even if this behaviour may not match with behaviour described in JavaDoc).
                         </para>
@@ -266,9 +266,9 @@
                 <itemizedlist>
                     <listitem>
                         <para>
-                            New parameter,<literal>org.glassfish.hk2.api.ServiceLocator</literal>, has been added
+                            New parameter, <literal>org.glassfish.hk2.api.ServiceLocator</literal>, has been added
                             to &jersey.server.spi.ExternalRequestScope; methods. This is to allow 3rd party component providers to
-                            hook up with the actual HK2 locator in case of multiple Jersey applications are running in paralell
+                            hook up with the actual HK2 locator in case of multiple Jersey applications are running in parallel
                             within a single 3rd party component container. The change was driven by CDI/Servlet requirements.
                         </para>
                     </listitem>
@@ -286,7 +286,7 @@
                 <itemizedlist>
                     <listitem>
                         <para>
-                            New method,<literal>close</literal>, has been added to &jersey.server.ResourceFinder;. It's intention
+                            New method, <literal>close</literal>, has been added to &jersey.server.ResourceFinder;. Its intention
                             is to release allocated/opened resources (such as streams) without a need to iterate through the
                             whole &lit.jersey.server.ResourceFinder;.
                         </para>
@@ -490,7 +490,7 @@
             <section>
                 <title>Performance gain when using Sub-Resource Locators</title>
                 <para>
-                    We improved the performance for using sub-resource locators in an Jersey application. The performance gains
+                    We improved the performance for using sub-resource locators in a Jersey application. The performance gains
                     are available for cases when the sub-resource locator method returns either a resource class (return value is
                     e.g.
                     <literal>Class&lt;?&gt;</literal>
@@ -588,7 +588,7 @@
                     example,<link xlink:href='https://github.com/jersey/jersey/tree/master/examples/helloworld-weld'>
                     helloworld-weld</link>, has been introduced to demonstrate the new feature using Grizzly HTTP server. Another
                     example application,<link xlink:href='https://github.com/jersey/jersey/tree/master/examples/cdi-webapp'>
-                    cdi-webapp</link>, has been updated so that it enables Apache Tomcat Server deployment.
+                    cdi-webapp</link>, has been updated so it enables Apache Tomcat Server deployment.
                 </para>
             </section>
 
@@ -666,13 +666,12 @@
                             For performance purposes a new server property &jersey.server.ServerProperties.MONITORING_ENABLED; has
                             been introduced. It is possible to enable just basic almost static monitoring information using the
                             property. It allows to inject &jersey.server.monitoring.ApplicationInfo; object, renamed original
-                            class<literal>org.glassfish.jersey.server.monitoring.ApplicationStatistics</literal>.
+                            class <literal>org.glassfish.jersey.server.monitoring.ApplicationStatistics</literal>.
                             And &jersey.server.monitoring.MonitoringStatistics; no more have a reference to<literal>
                             ApplicationStatistics</literal>, method
                             <literal>getApplicationStatistics()</literal>
                             has been removed.
                         </para>
-                        gitc
                     </listitem>
                 </itemizedlist>
             </para>
@@ -723,7 +722,7 @@
                     We have reintroduced support for JSON processing via Jackson 1.x JSON provider (1.9.11). In order to use
                     Jackson 1 in your application you need to add
                     <literal>jersey-media-json-jackson1</literal>
-                    module (+ it's dependencies) to your class-path and register
+                    module (+ its dependencies) to your class-path and register
                     <literal>Jackson1Feature</literal>
                     in your application (server or client).
                 </para>
@@ -812,7 +811,7 @@
                 <para>
                     Our media module that supports working with JSON via Jackson library has been updated to use Jackson 2.x
                     (2.3.2). All samples and tests have been rewritten to use Jackson 2 as well. In order to use Jackson 2 in your
-                    application you need to add jersey-media-json-jackson (+ it's Jackson dependencies) to your class-path and
+                    application you need to add jersey-media-json-jackson (+ its Jackson dependencies) to your class-path and
                     register
                     <literal>JacksonFeature</literal>
                     in your application.
@@ -842,7 +841,7 @@
                     default). You can now run the tests in parallel using either JUnit or TestNG. See chapters dedicated to TestNG
                     and parallel testing for more information:
                     <xref linkend="testng"/>
-                    and<xref linkend="parallel"/>.
+                    and <xref linkend="parallel"/>.
                 </para>
             </section>
         </section>
@@ -865,7 +864,7 @@
                     </listitem>
                     <listitem>
                         <para>
-                            Automatic registration of<literal>MessageBodyWriter</literal>,
+                            Automatic registration of <literal>MessageBodyWriter</literal>,
                             <literal>MessageBodyReaders</literal>
                             and
                             <literal>ExceptionMappers</literal>
@@ -873,7 +872,7 @@
                             <literal>META-INF/services</literal>
                             mechanism has been removed. Disabling the automatic registration of providers via
                             <literal>META-INF/services</literal>
-                            may affect 3rd party libraries (i.e. Jackson 2.x) that are using this mechanism to register it's
+                            may affect 3rd party libraries (i.e. Jackson 2.x) that are using this mechanism to register its
                             providers. In order to restore this functionality the
                             <literal>org.glassfish.jersey.ext:jersey-metainf-services</literal>
                             has to be added on the classpath. Otherwise such providers has to be registered manually.
@@ -921,7 +920,7 @@
                         <para>
                             &jersey.sse.SseFeature; now gets automatically discovered and enabled if the SSE module is present on
                             the class path. This behavior can be suppressed by setting &jersey.sse.SseFeature.DISABLE_SSE;
-                            property to<literal>true</literal>. The behavior can also be selectively suppressed in either client
+                            property to <literal>true</literal>. The behavior can also be selectively suppressed in either client
                             or server runtime by setting the &jersey.sse.SseFeature.DISABLE_SSE_CLIENT;
                             or &jersey.sse.SseFeature.DISABLE_SSE_SERVER; property respectively.
                         </para>
@@ -1193,7 +1192,7 @@
                         <para>
                             MVC support: method
                             <literal>writeTo</literal>
-                            of &jersey.server.mvc.TemplateProcessor; was modified by adding an argument<literal>MultivaluedMap&lt;String,
+                            of &jersey.server.mvc.TemplateProcessor; was modified by adding an argument <literal>MultivaluedMap&lt;String,
                             Object&gt; httpHeaders</literal>. This is an incompatible change (the method was modified directly in
                             the interface). All Jersey provided MVC implementation were adjusted but if you have your own MVC
                             implementation then you need to modify the method signature of the implementation.
@@ -1201,7 +1200,7 @@
                     </listitem>
                     <listitem>
                         <para>
-                            A minor JAX-RS incompatibility issue has been recently discovered and reported (see<link
+                            A minor JAX-RS incompatibility issue has been recently discovered and reported (see <link
                                 xlink:href="https://java.net/jira/browse/JERSEY-2387">JERSEY-2387</link>). As part of the fix,
                             minor breaking changes related to URI resolving and creation have been introduced in the behavior
                             of &jaxrs.core.UriBuilder;, &jaxrs.core.Link.Builder; and &jaxrs.client.WebTarget; classes. It is no
@@ -1370,8 +1369,8 @@
                         WADL is by default displayed in the simplified form. It does not contain supporting resources like OPTIONS
                         methods or
                         <literal>/application.wadl</literal>
-                        itself. In order to get the full WADL use query param<literal>detail=true</literal>. For example make a
-                        GET request to<literal>http://localhost:8080/application.wadl?detail=true</literal>.
+                        itself. In order to get the full WADL use query param <literal>detail=true</literal>. For example make a
+                        GET request to <literal>http://localhost:8080/application.wadl?detail=true</literal>.
                     </para>
                 </listitem>
             </itemizedlist>
@@ -1390,7 +1389,7 @@
                         methods or
                         <literal>/application.wadl</literal>
                         itself. In order to get the full WADL use query param<literal>detail=true</literal>. For example make a
-                        GET request to<literal>http://localhost:8080/application.wadl?detail=true</literal>.
+                        GET request to <literal>http://localhost:8080/application.wadl?detail=true</literal>.
                     </para>
                 </listitem>
             </itemizedlist>
@@ -1527,7 +1526,7 @@
                             <literal>org.glassfish.jersey.spi.RequestsExecutorsProvider</literal>. It has been also extended with
                             an additional
                             <literal>releaseRequestingExecutor</literal>
-                            method to address executor shutdown handling issues reported in<link
+                            method to address executor shutdown handling issues reported in <link
                                 xlink:href='https://java.net/jira/browse/JERSEY-2205'>JERSEY-2205</link>. As such, any custom
                             implementation of the SPI is now required to implement the new method. (Note that the SPI has been
                             removed in Jersey 2.18 - see the Jersey 2.18 release migration guide section for more details.)
@@ -1548,7 +1547,7 @@
                     <para>
                         The unsupported
                         <literal>ClientProperties.BUFFER_RESPONSE_ENTITY_ON_EXCEPTION</literal>
-                        property, with value of<literal>jersey.config.client.bufferResponseEntityOnException</literal>, has been
+                        property, with value of <literal>jersey.config.client.bufferResponseEntityOnException</literal>, has been
                         removed from the API. Since Jersey 2.4 where
                         <link xlink:href='https://java.net/jira/browse/jersey-2157'>JERSEY-2157</link>
                         issue has been fixed, Jersey client runtime automatically buffers error response entities. This behavior
@@ -1573,7 +1572,7 @@
                         methods have been introduced instead in Jersey 2.3 for consistency with other parts of client-side JAX-RS
                         API. Access to the raw SSE event data content is provided via a &lit.jersey.sse.InboundEvent;'s
                         <literal>byte[] getRawData()</literal>
-                        method that has been too introduced in Jersey 2.3.
+                        method that has been introduced in Jersey 2.3 as well.
                     </para>
                 </listitem>
                 <listitem>
@@ -1610,7 +1609,7 @@
                         Generic &jersey.server.Broadcaster; methods for adding/removing &jersey.server.BroadcasterListener;
                         registrations have been renamed from
                         <literal>addBroadcasterListener/removeBroadcasterListener</literal>
-                        to simply<literal>add/remove</literal>.
+                        to simply <literal>add/remove</literal>.
                     </para>
                 </listitem>
                 <listitem>
@@ -1744,7 +1743,7 @@
 
                     Containers, which support the reload functionality implement the
                     <literal>ContainerListener</literal>
-                    interface, so that once you get access to the actual container instance, you could call it's
+                    interface, so that once you get access to the actual container instance, you could call its
                     <literal>onReload</literal>
                     method and get the container re-load the config. The second interface helps you to obtain the actual container
                     instance reference. An example on how things are wired together follows.
@@ -2115,7 +2114,7 @@
                             Jackson</literal>,<literal>Jettison</literal>) can be used as well. The relevant feature has to be
                             registered (and dependency added) and custom implementation of
                             <literal>ContextResolver</literal>
-                            has to be provided. See the code snippets in the<link linkend="json.jackson">related chapter</link>.
+                            has to be provided. See the code snippets in the <link linkend="json.jackson">related chapter</link>.
                         </para>
                         <para>
                             For more on particular
@@ -2190,7 +2189,7 @@
                 <para>
                     As mentioned, the centralized configuration of Jersey&nbsp;1's
                     <literal>JSONConfiguration</literal>
-                    does not have a direct equivalent in Jersey&nbsp;2. Each provider has it's own way to be configured. Detailed
+                    does not have a direct equivalent in Jersey&nbsp;2. Each provider has its own way to be configured. Detailed
                     description of each method and property is out of scope of this migration guide and can be found in the
                     documentation and APIs of the relevant providers and/or the relevant Jersey module API. Bellow are several
                     basic examples how to configure certain options when using MOXy with Jersey's
@@ -2237,7 +2236,7 @@
                     <literal>Marshaller</literal>
                     and/or
                     <literal>Unmarshaller</literal>
-                    using:<literal>MoxyJsonConfig</literal>'s<literal>property()</literal>,
+                    using: <literal>MoxyJsonConfig</literal>'s <literal>property()</literal>,
                     <literal>marshallerProperty()</literal>
                     and
                     <literal>unmarshallerProperty()</literal>
@@ -2245,7 +2244,7 @@
                 </para>
             </section>
             <para>
-                More on the JSON Support topic can be found in<xref linkend="json"/>.
+                More on the JSON Support topic can be found in <xref linkend="json"/>.
             </para>
         </section>
     </section>
diff --git a/docs/src/main/docbook/monitoring.xml b/docs/src/main/docbook/monitoring.xml
index aab0cd9..db9f1b3 100644
--- a/docs/src/main/docbook/monitoring.xml
+++ b/docs/src/main/docbook/monitoring.xml
@@ -40,7 +40,7 @@
                 </para>
             </important>
             <para>
-                Jersey provides functionality for monitoring JAX-RS/Jersey applications. Application monitoring is useful in cases
+                Jersey provides functionality for monitoring JAX-RS/Jersey applications. Application monitoring is useful
                 when you need to identify the performance hot-spots in your JAX-RS application, observe
                 execution statistics of particular resources or listen to application
                 or request lifecycle events. Note that this functionality is Jersey-specific extension to JAX-RS API.
@@ -54,7 +54,7 @@
                         <listitem>
                             <para>
                                 Event listeners allow users to receive and process a predefined set of events that occur during
-                                a application lifecycle (such as application initialization, application destroy) as well as
+                                an application lifecycle (such as application initialization, application destroy) as well as
                                 request processing lifecycle events (request started, resource method finished, exception thrown,
                                 etc.). This feature is always enabled in Jersey server runtime and is leveraged by the other
                                 monitoring features.
@@ -82,7 +82,7 @@
                                 is able to expose the statistics as JMX MBeans (for example
                                 &jersey.server.monitoring.ApplicationMXBean;).
                                 Jersey monitoring MXBeans can be accessed programmatically using JMX APIs or browsed via JMX-enabled
-                                tool (<literal>JConsole</literal> for example). This functionality is, too,  by default disabled for
+                                tool (<literal>JConsole</literal> for example). This functionality is also disabled by default for
                                 performance reasons and must be enabled if needed.
                             </para>
                         </listitem>
@@ -196,7 +196,7 @@
             </para>
 
             <para>
-                Once the listeners and the monitored resource is defined, it's time to initialize our application. The following
+                Once the listeners and the monitored resource are defined, it's time to initialize our application. The following
                 piece of code shows a &jersey.server.ResourceConfig; that is used to initialize the application (please
                 note that only &lit.jersey.server.monitoring.ApplicationEventListener; is registered as provider).
 
@@ -220,7 +220,7 @@
                 from an <literal>ApplicationEventListener.onRequest</literal> method and not any other requests. In our case the
                 returned request event listener keeps information about the request number of the current request and a start time of
                 the request which is later used to print out the request processing times statistics. This demonstrates the principle
-                of listening to request events: for one request there is a one instance which can be used to hold all the information
+                of listening to request events: for one request there is one instance which can be used to hold all the information
                 about the particular request. In other words, &lit.jersey.server.monitoring.RequestEventListener; is designed to be
                 implicitly request-scoped.
             </para>
@@ -456,7 +456,7 @@
                     of &lit.jersey.server.monitoring.MonitoringStatistics; does not make any assumptions about mutability of
                     monitoring statistics instances (to allow future optimizations and changes in implementation strategy). In
                     order to get always latest statistics, we recommend injecting a &jee6.javax.inject.Provider; rather than a
-                    direct reference and use it's <literal>get()</literal> method to retrieve the latest statistics. For example,
+                    direct reference and use its <literal>get()</literal> method to retrieve the latest statistics. For example,
                     in singleton resources the use of the technique is very important otherwise statistics might correspond
                     to the time when singleton was firstly created and might not update since that time.
                 </para>
@@ -533,21 +533,21 @@
                     <link linkend="resource-builder">"Programmatic API for Building Resources"</link>), one Java resource class
                     can be an endpoint for resource methods on many different URIs. And also one URI can be served by method from
                     many different Java classes. Therefore both views are not to be compared 1:1. Instead they provide
-                    different loggical views on your JAX-RS application. This monitoring feature can also help when designing
+                    different loggical views on your JAX-RS application. This monitoring feature can also be helpful when designing
                     the JAX-RS APIs as it provides nice view on available root application URIs.
                 </para>
                 <para>
                     Both logical views on the resources exposed by application share few common principles. A single resource entry
                     is always a set of resource methods which are available under the <literal>methods</literal> sub-group. Statistics
                     can be found in MBeans <literal>MethodTimes</literal> and <literal>RequestTimes</literal>.
-                    <literal>MethodTimes</literal> contains statistics measured on on resource methods (duration of execution of a
+                    <literal>MethodTimes</literal> contains statistics measured on resource methods (duration of execution of a
                     code of the a resource method), whereas <literal>RequestTimes</literal> contains statistics of an entire request
                     execution (not only a time of the execution of the resource method but the overall time of the execution of whole
                     request by Jersey runtime). Another useful information is that statistics directly under resource (not under
                     the <literal>methods</literal> sub-group) contains summary of statistics for all resource methods grouped in the
                     resource entry.
                 </para>
-                <para>Additional useful details that about statistics</para>
+                <para>Additional useful details about statistics</para>
                 <itemizedlist>
                     <listitem><para><literal>Global->Configuration->Registered(Classes/Instances)</literal>:
                         registered resource classes and instances by the user (i.e., not added by &jersey.server.ModelProcessor;
@@ -612,7 +612,7 @@
                 </para>
                 <para>
                     To reiterate, exposing Jersey MXBeans and the calculating monitoring statistics may have an performance impact
-                    on your application and therefore should be enabled only when needed. Also, please note, that it Jersey
+                    on your application and therefore should be enabled only when needed. Also, please note, that Jersey
                     monitoring is exposing quite a lot of information about the monitored application which might be viewed as
                     problematic in some cases (e.g. in production server deployments).
                 </para>
diff --git a/docs/src/main/docbook/mp-config.xml b/docs/src/main/docbook/mp-config.xml
index 36c1e45..a201cf1 100644
--- a/docs/src/main/docbook/mp-config.xml
+++ b/docs/src/main/docbook/mp-config.xml
@@ -30,8 +30,8 @@
     <title>Jersey configuration</title>
     <para>
         This chapter provides Jersey configuration basics which includes configuration using default configuration
-        provider (included in Jersey by default) using system properties. And micro-profile configuration extension
-        which allows plugging-in of configuration modules based on micro profile configuration specification
+        provider (included in Jersey by default) using system properties, and micro-profile configuration extension
+        which allows plugging-in of configuration modules based on micro profile configuration specification.
     </para>
     <section xml:id="default-config">
         <title>Jersey default configuration provider</title>
diff --git a/docs/src/main/docbook/mvc.xml b/docs/src/main/docbook/mvc.xml
index 171e7af..81c58ac 100644
--- a/docs/src/main/docbook/mvc.xml
+++ b/docs/src/main/docbook/mvc.xml
@@ -284,7 +284,7 @@
         <title>Handling errors with MVC</title>
 
         <para>
-            In addition to &jersey.server.mvc.Template; a &jersey.server.mvc.ErrorTemplate; annotation has been introduced in
+            In addition to &jersey.server.mvc.Template; an &jersey.server.mvc.ErrorTemplate; annotation has been introduced in
             Jersey 2.3. The purpose of this annotation is to bind the model to an error view in case an exception has been raised during
             processing of a request. This is true for any exception thrown after the resource matching phase (i.e. this not only
             applies to JAX-RS resources but providers and even Jersey runtime as well). The model in this case is the thrown exception
@@ -292,7 +292,7 @@
         </para>
         <para>
             <xref linkend="mvc.example.error.simple"/> shows how to use &lit.jersey.server.mvc.ErrorTemplate; on a resource method.
-            If all goes well with the method processing, then the <literal>/short-link</literal> template is used to as page sent
+            If all goes well with the method processing, then the <literal>/short-link</literal> template is used as page sent
             to the user. Otherwise if an exception is raised then the <literal>/error-form</literal> template is shown to the user.
         </para>
         <example xml:id="mvc.example.error.simple">
@@ -321,7 +321,7 @@
             <title>MVC &amp; Bean Validation</title>
 
             <para>
-                &lit.jersey.server.mvc.ErrorTemplate; can be used in also with Bean Validation to display specific error pages in
+                &lit.jersey.server.mvc.ErrorTemplate; can also be used with Bean Validation to display specific error pages in
                 case the validation of input/output values fails for some reason. Everything works as described above except the
                 model is not the thrown exception but rather a list of &jersey.ext.ValidationError;s. This list can be iterated in
                 the template and all the validation errors can be shown to the user in a desirable way.
@@ -465,7 +465,7 @@
                 <step>
                     <para>
                         if <literal>ServletContext.getResource</literal>, <literal>Class.getResource</literal> or
-                        <literal>File.exists</literal>returns a non-&lit.null; value for the reference then
+                        <literal>File.exists</literal> returns a non-&lit.null; value for the reference then
                         return the reference as the processable template reference otherwise return &lit.null;
                         (to indicate the absolute reference has not been resolved by the Mustache template processor).
                     </para>
@@ -541,7 +541,7 @@
                 <step>
                     <para>
                         if <literal>ServletContext.getResource</literal>, <literal>Class.getResource</literal> or
-                        <literal>File.exists</literal>returns a non-&lit.null; value for the reference then
+                        <literal>File.exists</literal> returns a non-&lit.null; value for the reference then
                         return the reference as the processable template reference otherwise return &lit.null;
                         (to indicate the absolute reference has not been resolved by the Freemarker template processor).
                     </para>
diff --git a/docs/src/main/docbook/representations.xml b/docs/src/main/docbook/representations.xml
index 8a10427..fda8d6a 100644
--- a/docs/src/main/docbook/representations.xml
+++ b/docs/src/main/docbook/representations.xml
@@ -81,7 +81,7 @@
             request parameters, the method parameter associated with the
             representation being consumed does not require annotating. In other words the
             representation (entity) parameter does not require a specific 'entity' annotation. A method parameter
-            without a annotation is an entity. A maximum of
+            without an annotation is an entity. A maximum of
             one such unannotated method parameter may exist since there may only be a
             maximum of one such representation sent in a request.
         </para>
@@ -367,7 +367,7 @@
 
         <para>Notice that in this example the constructor of a resource class is used
             to perform actions that may otherwise have to be duplicated to
-            invoked for each resource method. The life cycle of resource classes is per-request
+            be invoked for each resource method. The life cycle of resource classes is per-request
             which means that the resource instance is created for each request and therefore
             can work with request parameters and for example make changes to the request processing by
             throwing an exception as it is shown in this example.
diff --git a/docs/src/main/docbook/rx-client.xml b/docs/src/main/docbook/rx-client.xml
index fe46cab..db91eef 100644
--- a/docs/src/main/docbook/rx-client.xml
+++ b/docs/src/main/docbook/rx-client.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2014, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2014, 2020 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
@@ -165,7 +165,7 @@
 }</programlisting>
                 </example>
 
-                The downside of this approach is it's slowness. You need to sequentially process all the independent requests which
+                The downside of this approach is its slowness. You need to sequentially process all the independent requests which
                 means that you're wasting resources. You are needlessly blocking threads, that could be otherwise used for some real work.
             </para>
             <para>
@@ -534,7 +534,7 @@
                 &rxjava.link;, contributed by Netflix, is probably the most advanced reactive library for Java at the moment. It's
                 used for composing asynchronous and event-based programs by using observable sequences. It uses the
                 <link xlink:href="&wikipedia.uri;Observer_pattern">observer pattern</link> to support these sequences of data/events
-                via it's &rxjava.Observable; entry point class which implements the Reactive Pattern. &lit.rxjava.Observable; is
+                via its &rxjava.Observable; entry point class which implements the Reactive Pattern. &lit.rxjava.Observable; is
                 actually the parameter type in the RxJava's extension of &jaxrs.client.RxInvoker;, called
                 &jersey.ext.rx.client.rxjava.RxObservableInvoker;. This means that the return type of HTTP method calls is
                 &lit.rxjava.Observable; in this case (accordingly parametrized).
@@ -611,7 +611,7 @@
                 &rxjava.link;, contributed by Netflix, is probably the most advanced reactive library for Java at the moment. It's
                 used for composing asynchronous and event-based programs by using observable sequences. It uses the
                 <link xlink:href="&wikipedia.uri;Observer_pattern">observer pattern</link> to support these sequences of data/events
-                via it's &rxjava2.Flowable; entry point class which implements the Reactive Pattern. &lit.rxjava2.Flowable; is
+                via its &rxjava2.Flowable; entry point class which implements the Reactive Pattern. &lit.rxjava2.Flowable; is
                 actually the parameter type in the RxJava's extension of &jaxrs.client.RxInvoker;, called
                 &jersey.ext.rx.client.rxjava2.RxFlowableInvoker;. This means that the return type of HTTP method calls is
                 &lit.rxjava2.Flowable; in this case (accordingly parametrized).
diff --git a/docs/src/main/docbook/sse.xml b/docs/src/main/docbook/sse.xml
index 8d89922..2e46ee8 100644
--- a/docs/src/main/docbook/sse.xml
+++ b/docs/src/main/docbook/sse.xml
@@ -216,18 +216,18 @@
                 the client can read headers and starts listening for individual events.
             </para>
             <para>
-                In the<xref linkend="example-simple-sse-jaxrs"/>, the resource method creates a new thread that sends a
+                In the <xref linkend="example-simple-sse-jaxrs"/>, the resource method creates a new thread that sends a
                 sequence of 10 events. There is a 1 second delay between two subsequent events as indicated in a comment. Each
                 event is represented by <literal>jakarta.ws.rs.sse.OutboundSseEvent</literal> type and is built with a help of a
                 provided <literal>Builder</literal>. The <literal>Builder</literal> is obtain via the injected instance
                 (actually, it is a singleton) of <literal>jakarta.ws.rs.sse.Sse</literal> (the
                 <literal>newEventBuilder()</literal>
-                method. The <literal>OutboundSseEvent</literal> implementation reflects the standardized format of
+                method). The <literal>OutboundSseEvent</literal> implementation reflects the standardized format of
                 SSE messages and contains properties that represent <literal>name</literal> (for named events),
                 <literal>comment</literal>, <literal>data</literal> or <literal>id</literal>. The code also sets the
                 event data media type using the <literal>mediaType(MediaType)</literal> method on the
                 <literal>eventBuilder</literal>. The media type, together with the data type set by the
-                <literal>data(Class, Object></literal>
+                <literal>data(Class, Object)</literal>
                 method (in our case <literal>String.class</literal>), is used
                 for serialization of the event data. Note that the event data media type will not be written to any headers as
                 the response <literal>Content-type</literal> header is already defined by the &lit.jaxrs.Produces; and set to
@@ -361,7 +361,7 @@
     @GET
     @Produces(MediaType.SERVER_SENT_EVENTS)
     public void listenToBroadcast(@Context SseEventSink eventSink) {
-        this.broadcaster.subscribe(eventSink);
+        this.broadcaster.register(eventSink);
     }
 }
                     </programlisting>
@@ -369,7 +369,7 @@
                 Let's explore the example together. The <literal>BroadcasterResource</literal> resource class is annotated with
                 &jee6.inject.Singleton; annotation which tells Jersey runtime that only a single instance of the resource
                 class should be used to serve all the incoming requests to <literal>/broadcast</literal> path. This is needed as
-                we want to keep an application-wide single reference to the private <literal>broadcaster</literal> field so that
+                we want to keep an application-wide single reference to the private <literal>broadcaster</literal> field so
                 we can use the same instance for all requests. Clients that want to listen to SSE events first send a
                 &lit.http.GET; request to the <literal>BroadcasterResource</literal>, that is handled by the
                 <literal>listenToBroadcast()</literal>
@@ -411,7 +411,7 @@
                 of the registered <literal>EventSink</literal>s as well as it frees all the server-side resources associated with
                 the stale connection.
                 Additionally, the <literal>SseBroadcaster</literal> is implemented to be thread-safe, so that clients can connect
-                and disconnect in any time and <literal>SseBroadcaster</literal> will always broadcast messages to the most recent
+                and disconnect at any time and <literal>SseBroadcaster</literal> will always broadcast messages to the most recent
                 collection of registered and active set of clients.
             </para>
         </section>
@@ -560,7 +560,7 @@
                             method <emphasis>MUST</emphasis> be called, otherwise
                             the subscriber will not receive ANY data. Furthermore, in the current
                             <literal>SseEventSource</literal>
-                            implementation, such a subscriber will block a threadm and will
+                            implementation, such a subscriber will block a thread and will
                             occasionally lead to overflow of an internal buffer in <literal>SseEventSource</literal>. As
                             mentioned, calling <literal>subscription.request(Long.MAX_VALUE)</literal>, e.g. in the registered
                             <literal>onSubscribe</literal>
@@ -596,7 +596,7 @@
                 </para>
             </note>
             <para>
-                By default, when a connection the the SSE endpoint is lost, the event source will use a default delay
+                By default, when a connection to the SSE endpoint is lost, the event source will use a default delay
                 before attempting to reconnect to the SSE endpoint. The SSE endpoint can however control the client-side
                 retry delay by including a special <literal>retry</literal> field value in any event sent to the client.
                 Jersey &jakarta.ws.rs.sse.SseEventSource; implementation automatically tracks any received SSE event
@@ -642,7 +642,7 @@
             <xref linkend="overview-jaxrs"/>
         </para>
         <para>
-            The API contains support SSE support for both - server and client. To use the Jersey-specific SSE API, you need to
+            The API contains SSE support for both - server and client. To use the Jersey-specific SSE API, you need to
             add the dependency to the
         </para>
         <para>
@@ -726,7 +726,7 @@
                     &jersey.server.ChunkedOutput; API for output chunked message processing.
                 </para>
                 <para>
-                    In the<xref linkend="example-simple-sse"/>, the resource method creates a new thread that sends a sequence of
+                    In the <xref linkend="example-simple-sse"/>, the resource method creates a new thread that sends a sequence of
                     10 events. There is a 1 second delay between two subsequent events as indicated in a comment. Each event is
                     represented by &lit.jersey.sse.OutboundEvent; type and is built with a help of an outbound event
                     <literal>Builder</literal>. The &lit.jersey.sse.OutboundEvent; reflects the standardized format of SSE
@@ -1053,7 +1053,7 @@
                         </programlisting>
                     </example>
 
-                    The code above is very similar to the code in<xref linkend="sse.ex.client.eventListener"/>. In this example
+                    The code above is very similar to the code in <xref linkend="sse.ex.client.eventListener"/>. In this example
                     however, the &lit.jersey.sse.EventSource; is constructed directly using a single-parameter constructor.
                     This way, the connection to the SSE endpoint is by default automatically opened at the event source
                     creation. The implementation of the &lit.jersey.sse.EventListener; has been moved into the overridden
diff --git a/docs/src/main/docbook/test-framework.xml b/docs/src/main/docbook/test-framework.xml
index 526d4ee..e32c14e 100644
--- a/docs/src/main/docbook/test-framework.xml
+++ b/docs/src/main/docbook/test-framework.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2012, 2020 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
@@ -196,7 +196,7 @@
             <itemizedlist>
                 <listitem>
                     <para>
-                        Extend &jersey.test.JerseyTestNg;, or one of it's inner classes &jersey.test.JerseyTestNg.ContainerPerClassTest;
+                        Extend &jersey.test.JerseyTestNg;, or one of its inner classes &jersey.test.JerseyTestNg.ContainerPerClassTest;
                         / &jersey.test.JerseyTestNg.ContainerPerMethodTest;, instead of &jersey.test.JerseyTest;.
                     </para>
                 </listitem>
@@ -389,7 +389,7 @@
 &lt;/dependency&gt;</programlisting>
 
                 As indicated, the "container" exposed by this module is just a wrapper or stub, that redirects all request to
-                a configured host and port. Writing tests for this container is same as for any other but you have to provide
+                a configured host and port. Writing tests for this container is similar to any other but you have to provide
                 the information about host and port during the test execution:
 
                 <screen>mvn test -Djersey.test.host=myhost.org -Djersey.config.test.container.port=8080</screen>
diff --git a/docs/src/main/docbook/user-guide.xml b/docs/src/main/docbook/user-guide.xml
index 0247500..bddbfac 100644
--- a/docs/src/main/docbook/user-guide.xml
+++ b/docs/src/main/docbook/user-guide.xml
@@ -39,7 +39,7 @@
         </para>
         <para>
             If you would like to contribute to the guide or have questions on things not covered in our docs, please
-            contact us at<link xlink:href="mailto:jersey-dev@eclipse.org">users@jersey.java.net</link>. Similarly,
+            contact us at <link xlink:href="mailto:jersey-dev@eclipse.org">users@jersey.java.net</link>. Similarly,
             in case you spot any errors in the Jersey documentation, please report them by filing a new issue in our
             <link xlink:href="https://github.com/eclipse-ee4j/jersey/issues">Jersey JIRA Issue Tracker</link>
             under
diff --git a/docs/src/main/docbook/wadl.xml b/docs/src/main/docbook/wadl.xml
index 62599a4..991f8e4 100644
--- a/docs/src/main/docbook/wadl.xml
+++ b/docs/src/main/docbook/wadl.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2012, 2020 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,7 +35,7 @@
             Jersey contains support for
             <link xlink:href='https://javaee.github.io/wadl/'>Web Application Description Language (WADL)</link>. WADL is
             a XML description of a deployed RESTful web application. It contains model of the deployed resources, their
-            structure, supported media types, HTTP methods and so on. In a sense, WADL is a similar to the WSDL
+            structure, supported media types, HTTP methods and so on. In a sense, WADL is similar to the WSDL
             (Web Service Description Language) which describes SOAP web services. WADL is however specifically designed
             to describe RESTful Web resources.
         </para>
@@ -242,7 +242,7 @@
             and one &lit.http.GET; method which return this WADL. There is also
             a sub-resource with a path defined by path param <literal>{path}</literal>. This means that you can request
             a resource on the URI <literal>http://localhost:9998/application.wadl/something</literal>.
-            This is used only to return an external grammar if there is any attached. Such a external grammar can be
+            This is used only to return an external grammar if there is any attached. Such an external grammar can be
             for example an <literal>XSD</literal> schema of the response entity which if the response entity is a JAXB bean.
             An external grammar support via Jersey <emphasis>extended WADL support</emphasis> is described in sections below.
         </para>
@@ -256,7 +256,7 @@
             primary use case of getting formatted data.
         </para>
         <para>
-            Let's now send an HTTP &lit.http.OPTIONS; request to <literal>"country/{id}"</literal> resource using the the
+            Let's now send a HTTP &lit.http.OPTIONS; request to <literal>"country/{id}"</literal> resource using the the
             <literal>curl</literal> command:
             <programlisting linenumbering="unnumbered">curl -X OPTIONS -H "Allow: application/vnd.sun.wadl+xml" \
     -v http://localhost:9998/country/15</programlisting>
@@ -491,7 +491,7 @@
             The <literal>resource</literal> with <literal>path="customer/{id}"</literal> is similar to the
             country resource from the previous example. There is a path parameter which identifies the customer
             by <literal>id</literal>. The resource contains 2 user-declared methods and again auto-generated
-            &lit.http.OPTIONS; methods added by Jersey. THe resource declares 2 sub-resource locators which are
+            &lit.http.OPTIONS; methods added by Jersey. The resource declares 2 sub-resource locators which are
             represented in the returned WADL document as nested <literal>resource</literal> elements. Note that the sub-resource
             locator <literal>getCustomerAddress()</literal> returns a type CustomerAddressSubResource in the
             method declaration and also in the WADL there is a <literal>resource</literal> element for such
diff --git a/etc/travis/travis.sh b/etc/travis/travis.sh
index 21985dc..c71dbc3 100644
--- a/etc/travis/travis.sh
+++ b/etc/travis/travis.sh
@@ -25,6 +25,8 @@
 bash -c "while true; do tail -5 $BUILD_OUTPUT; sleep $PING_SLEEP; done" &
 PING_LOOP_PID=$!
 
+mvn -version
+
 if [ "$1" = "glassfish-copyright:copyright" ]; then
     mvn glassfish-copyright:copyright
 else
diff --git a/examples/groovy/pom.xml b/examples/groovy/pom.xml
index 80c648d..f037666 100644
--- a/examples/groovy/pom.xml
+++ b/examples/groovy/pom.xml
@@ -28,7 +28,8 @@
         <dependency>
             <groupId>org.codehaus.groovy</groupId>
             <artifactId>groovy-all</artifactId>
-            <version>2.4.3</version>
+            <type>pom</type>
+            <version>3.0.2</version>
         </dependency>
         <dependency>
             <groupId>org.glassfish.jersey.test-framework.providers</groupId>
diff --git a/examples/osgi-helloworld-webapp/functional-test/pom.xml b/examples/osgi-helloworld-webapp/functional-test/pom.xml
index 7bc1a63..96dd8e7 100644
--- a/examples/osgi-helloworld-webapp/functional-test/pom.xml
+++ b/examples/osgi-helloworld-webapp/functional-test/pom.xml
@@ -225,24 +225,17 @@
 
     <profiles>
         <profile>
-            <id>testsSkipJdk11</id>
+            <id>testsJdk11</id>
             <activation>
                 <jdk>[11,)</jdk>
             </activation>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <!-- Exclude unit tests on jdk 11 for now -->
-                            <excludes>
-                                <exclude>**/WebAppFelixTest.java</exclude>
-                            </excludes>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
+            <dependencies>
+                <dependency>
+                    <groupId>com.sun.activation</groupId>
+                    <artifactId>jakarta.activation</artifactId>
+                    <version>${jakarta.activation.version}</version>
+                </dependency>
+            </dependencies>
         </profile>
         <profile>
             <id>release</id>
diff --git a/examples/osgi-helloworld-webapp/functional-test/src/test/java/org/glassfish/jersey/examples/helloworld/test/AbstractWebAppTest.java b/examples/osgi-helloworld-webapp/functional-test/src/test/java/org/glassfish/jersey/examples/helloworld/test/AbstractWebAppTest.java
index 78ae2e3..fc11f8f 100644
--- a/examples/osgi-helloworld-webapp/functional-test/src/test/java/org/glassfish/jersey/examples/helloworld/test/AbstractWebAppTest.java
+++ b/examples/osgi-helloworld-webapp/functional-test/src/test/java/org/glassfish/jersey/examples/helloworld/test/AbstractWebAppTest.java
@@ -35,6 +35,7 @@
 
 import javax.inject.Inject;
 
+import org.glassfish.jersey.internal.util.JdkVersion;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
 
 import org.ops4j.pax.exam.Configuration;
@@ -54,6 +55,7 @@
 import static org.ops4j.pax.exam.CoreOptions.options;
 import static org.ops4j.pax.exam.CoreOptions.systemPackage;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.vmOption;
 
 /**
  * @author Jakub Podlesak
@@ -104,6 +106,7 @@
 
                 // uncomment for verbose class loading info
                 // vmOption("-verbose:class"),
+                getAddOpensForFelixFrameWorkSecurity(),
 
                 // bootDelegationPackage("org.glassfish.jersey.client.*"),
 
@@ -147,6 +150,7 @@
                 mavenBundle().groupId("jakarta.xml.bind").artifactId("jakarta.xml.bind-api").versionAsInProject(),
                 //SUN JAXB IMPL OSGI
                 mavenBundle().groupId("com.sun.xml.bind").artifactId("jaxb-osgi").versionAsInProject().versionAsInProject(),
+                getActivationBundle(),
                 systemPackage("com.sun.source.tree"),
                 systemPackage("com.sun.source.util"),
 
@@ -190,6 +194,18 @@
         return options;
     }
 
+    private static Option getActivationBundle() {
+        return JdkVersion.getJdkVersion().getMajor() > 8
+                ? mavenBundle().groupId("com.sun.activation").artifactId("jakarta.activation").versionAsInProject()
+                : null;
+    }
+
+    private static Option getAddOpensForFelixFrameWorkSecurity() {
+        return JdkVersion.getJdkVersion().getMajor() > 8
+                ? vmOption("--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED")
+                : null;
+    }
+
     public List<Option> jettyOptions() {
         return Arrays.asList(options(
                 mavenBundle().groupId("org.ops4j.pax.web").artifactId("pax-web-jetty-bundle").versionAsInProject(),
diff --git a/examples/osgi-helloworld-webapp/war-bundle/pom.xml b/examples/osgi-helloworld-webapp/war-bundle/pom.xml
index c53317a..7e3dbb6 100644
--- a/examples/osgi-helloworld-webapp/war-bundle/pom.xml
+++ b/examples/osgi-helloworld-webapp/war-bundle/pom.xml
@@ -66,6 +66,11 @@
             <artifactId>org.apache.felix.eventadmin</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/examples/osgi-http-service/bundle/pom.xml b/examples/osgi-http-service/bundle/pom.xml
index 3b41c66..0545b4f 100644
--- a/examples/osgi-http-service/bundle/pom.xml
+++ b/examples/osgi-http-service/bundle/pom.xml
@@ -51,6 +51,11 @@
             <artifactId>org.apache.felix.eventadmin</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/examples/osgi-http-service/functional-test/pom.xml b/examples/osgi-http-service/functional-test/pom.xml
index 9b6d7db..3e8d10d 100644
--- a/examples/osgi-http-service/functional-test/pom.xml
+++ b/examples/osgi-http-service/functional-test/pom.xml
@@ -202,25 +202,17 @@
 
     <profiles>
         <profile>
-            <id>testsSkipJdk11</id>
+            <id>testsJdk11</id>
             <activation>
                 <jdk>[11,)</jdk>
             </activation>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <!-- Exclude unit tests on jdk 11 for now -->
-                            <excludes>
-                                <exclude>**/GrizzlyHttpServiceFelixTest.java</exclude>
-                                <exclude>**/JettyHttpServiceFelixTest.java</exclude>
-                            </excludes>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
+            <dependencies>
+                <dependency>
+                    <groupId>com.sun.activation</groupId>
+                    <artifactId>jakarta.activation</artifactId>
+                    <version>${jakarta.activation.version}</version>
+                </dependency>
+            </dependencies>
         </profile>
         <profile>
             <id>jdk8</id>
diff --git a/examples/osgi-http-service/functional-test/src/test/java/org/glassfish/jersey/examples/osgihttpservice/test/AbstractHttpServiceTest.java b/examples/osgi-http-service/functional-test/src/test/java/org/glassfish/jersey/examples/osgihttpservice/test/AbstractHttpServiceTest.java
index 824f6ce..2f3d18e 100644
--- a/examples/osgi-http-service/functional-test/src/test/java/org/glassfish/jersey/examples/osgihttpservice/test/AbstractHttpServiceTest.java
+++ b/examples/osgi-http-service/functional-test/src/test/java/org/glassfish/jersey/examples/osgihttpservice/test/AbstractHttpServiceTest.java
@@ -30,6 +30,7 @@
 
 import javax.inject.Inject;
 
+import org.glassfish.jersey.internal.util.JdkVersion;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
 
 import org.ops4j.pax.exam.Configuration;
@@ -115,6 +116,7 @@
                 mavenBundle().groupId("jakarta.xml.bind").artifactId("jakarta.xml.bind-api").versionAsInProject(),
                 //SUN JAXB IMPL OSGI
                 mavenBundle().groupId("com.sun.xml.bind").artifactId("jaxb-osgi").versionAsInProject().versionAsInProject(),
+                getActivationBundle(),
                 systemPackage("com.sun.source.tree"),
                 systemPackage("com.sun.source.util"),
 
@@ -256,4 +258,10 @@
         result.put(EventConstants.EVENT_TOPIC, topics);
         return result;
     }
+
+    private static Option getActivationBundle() {
+        return JdkVersion.getJdkVersion().getMajor() > 8
+                ? mavenBundle().groupId("com.sun.activation").artifactId("jakarta.activation").versionAsInProject()
+                : null;
+    }
 }
diff --git a/examples/osgi-http-service/pom.xml b/examples/osgi-http-service/pom.xml
index 904ddb0..af3dbeb 100644
--- a/examples/osgi-http-service/pom.xml
+++ b/examples/osgi-http-service/pom.xml
@@ -29,7 +29,7 @@
 
     <modules>
         <module>bundle</module>
-        <module>functional-test</module>
+<!--        <module>functional-test</module>-->
     </modules>
 
     <profiles>
diff --git a/pom.xml b/pom.xml
index 8eae84f..c830fea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -465,7 +465,7 @@
                             <exclude>bundles/**</exclude>
                             <fileExclude>module-info.java</fileExclude>
                         </sourceFileExcludes>
-                        <verbose />
+                        <verbose>true</verbose>
                         <additionalparam>-Xdoclint:none</additionalparam>
                         <maxmemory>256m</maxmemory>
                     </configuration>
@@ -1914,13 +1914,6 @@
 
             <dependency>
                 <groupId>org.ops4j.pax.exam</groupId>
-                <artifactId>pax-exam-container-native</artifactId>
-                <version>${pax.exam.version}</version>
-                <scope>test</scope>
-            </dependency>
-
-            <dependency>
-                <groupId>org.ops4j.pax.exam</groupId>
                 <artifactId>pax-exam-junit-extender-impl</artifactId>
                 <version>1.2.4</version>
                 <scope>test</scope>
@@ -1961,6 +1954,12 @@
                 <scope>test</scope>
             </dependency>
             <dependency>
+                <groupId>org.junit.jupiter</groupId>
+                <artifactId>junit-jupiter-engine</artifactId>
+                <version>${junit5.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
                 <groupId>org.testng</groupId>
                 <artifactId>testng</artifactId>
                 <version>6.9.6</version>
@@ -1995,22 +1994,21 @@
             <dependency>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>org.apache.felix.framework</artifactId>
-                <!--5.2.0+ does not work with moxy osgi functional tests-->
-                <version>5.0.1</version>
+                <version>6.0.3</version>
                 <scope>test</scope>
             </dependency>
 
             <dependency>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>org.apache.felix.eventadmin</artifactId>
-                <version>1.2.2</version>
+                <version>1.5.0</version>
                 <scope>test</scope>
             </dependency>
 
             <dependency>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>org.apache.felix.framework.security</artifactId>
-                <version>2.2.0</version>
+                <version>2.6.1</version>
                 <scope>test</scope>
             </dependency>
 
@@ -2072,7 +2070,7 @@
         <jersey.version>${project.version}</jersey.version>
         <!-- asm is now source integrated - keeping this property to see the version -->
         <!-- see core-server/src/main/java/jersey/repackaged/asm/.. -->
-        <asm.version>7.2</asm.version>
+        <asm.version>8.0</asm.version>
         <bnd.plugin.version>2.3.6</bnd.plugin.version>
         <cdi.api.version>1.1</cdi.api.version>
         <commons-lang3.version>3.3.2</commons-lang3.version>
@@ -2081,7 +2079,6 @@
         <checkstyle.version>8.28</checkstyle.version>
         <easymock.version>3.3</easymock.version>
         <ejb.version>3.2.5</ejb.version>
-        <gf.impl.version>5.1.0-RC2</gf.impl.version>
         <fasterxml.classmate.version>1.3.3</fasterxml.classmate.version>
         <findbugs.glassfish.version>1.7</findbugs.glassfish.version>
         <findbugs.version>3.0.4</findbugs.version>
@@ -2098,44 +2095,20 @@
         <hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[2.5,4)"</hk2.jvnet.osgi.version>
         <hk2.config.version>5.1.0</hk2.config.version>
         <httpclient.version>4.5.9</httpclient.version>
-        <istack.commons.runtime.version>3.0.8</istack.commons.runtime.version>
         <jackson.version>2.10.1</jackson.version>
-        <jakarta.activation-api.version>2.0.0-RC3</jakarta.activation-api.version>
-        <jakarta.activation.version>2.0.0-RC3</jakarta.activation.version>
         <javassist.version>3.25.0-GA</javassist.version>
-        <javax.annotation.osgi.version>javax.annotation.*;version="[1.2,3)"</javax.annotation.osgi.version>
-        <jakarta.annotation.osgi.version>jakarta.annotation.*;version="[1.2,3)"</jakarta.annotation.osgi.version>
-        <jakarta.annotation.version>2.0.0-RC1</jakarta.annotation.version>
-        <javax.annotation.version>1.3.5</javax.annotation.version>
-        <javax.el.version>3.0.3</javax.el.version>
-        <javax.el.impl.version>3.0.2</javax.el.impl.version>
-        <javax.interceptor.version>1.2.5</javax.interceptor.version>
-        <javax.persistence.version>2.2.3</javax.persistence.version>
-        <javax.validation.api.version>2.0.2</javax.validation.api.version>
-        <jaxb.api.version>3.0.0-RC2</jaxb.api.version>
-        <javax.jaxb.api.version>2.3.2</javax.jaxb.api.version>
-        <jaxb.ri.version>3.0.0-M1</jaxb.ri.version>
-        <jsonb.api.version>1.0.2</jsonb.api.version>
-        <jaxrs.api.spec.version>3.0</jaxrs.api.spec.version>
-        <jaxrs.api.impl.version>3.0.0-M1</jaxrs.api.impl.version>
         <jboss.logging.version>3.3.0.Final</jboss.logging.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 -->
-        <jetty.plugin.version>6.1.26</jetty.plugin.version>
-        <jetty.version>9.4.17.v20190418</jetty.version>
-        <jetty.servlet.api.25.version>6.1.14</jetty.servlet.api.25.version>
         <jmh.version>1.10.2</jmh.version>
         <jmockit.version>1.44</jmockit.version>
-        <jsonp.ri.version>1.1.5</jsonp.ri.version>
-        <jsonp.jaxrs.version>1.1.5</jsonp.jaxrs.version>
         <jsp.version>2.3.6</jsp.version>
         <jstl.version>1.2.7</jstl.version>
         <jta.api.version>1.3.3</jta.api.version>
+        <junit5.version>5.6.0</junit5.version>
         <kryo.version>4.0.1</kryo.version>
-        <mimepull.version>1.9.11</mimepull.version>
         <mockito.version>1.10.19</mockito.version>
-        <moxy.version>2.7.4</moxy.version>
         <mustache.version>0.8.17</mustache.version>
         <netty.version>4.1.43.Final</netty.version>
         <nexus-staging.mvn.plugin.version>1.6.7</nexus-staging.mvn.plugin.version>
@@ -2160,6 +2133,34 @@
         <weld.version>2.2.14.Final</weld.version> <!-- 2.4.1 doesn't work - bv tests -->
         <weld3.version>3.0.0.Final</weld3.version>
         <xerces.version>2.11.0</xerces.version>
-        <yasson.version>1.0.3</yasson.version>
+
+        <!-- do not need CQs -->
+        <gf.impl.version>5.1.0</gf.impl.version>
+        <istack.commons.runtime.version>3.0.8</istack.commons.runtime.version>
+        <jakarta.activation-api.version>2.0.0-RC3</jakarta.activation-api.version>
+        <jakarta.activation.version>2.0.0-RC3</jakarta.activation.version>
+        <javax.el.version>3.0.3</javax.el.version>
+        <javax.el.impl.version>3.0.3</javax.el.impl.version>
+        <javax.annotation.osgi.version>javax.annotation.*;version="[1.2,3)"</javax.annotation.osgi.version>
+        <jakarta.annotation.osgi.version>jakarta.annotation.*;version="[1.2,3)"</jakarta.annotation.osgi.version>
+        <jakarta.annotation.version>2.0.0-RC1</jakarta.annotation.version>
+        <javax.annotation.version>1.3.5</javax.annotation.version>
+        <javax.interceptor.version>1.2.5</javax.interceptor.version>
+        <javax.persistence.version>2.2.3</javax.persistence.version>
+        <javax.validation.api.version>2.0.2</javax.validation.api.version>
+        <jaxb.api.version>3.0.0-RC2</jaxb.api.version>
+        <javax.jaxb.api.version>2.3.2</javax.jaxb.api.version>
+        <jaxb.ri.version>3.0.0-M1</jaxb.ri.version>
+        <jaxrs.api.spec.version>3.0</jaxrs.api.spec.version>
+        <jaxrs.api.impl.version>3.0.0-M1</jaxrs.api.impl.version>
+        <jetty.plugin.version>6.1.26</jetty.plugin.version>
+        <jetty.version>9.4.27.v20200227</jetty.version>
+        <jetty.servlet.api.25.version>6.1.14</jetty.servlet.api.25.version>
+        <jsonb.api.version>1.0.2</jsonb.api.version>
+        <jsonp.ri.version>1.1.6</jsonp.ri.version>
+        <jsonp.jaxrs.version>1.1.6</jsonp.jaxrs.version>
+        <mimepull.version>1.9.13</mimepull.version>
+        <moxy.version>2.7.6</moxy.version>
+        <yasson.version>1.0.6</yasson.version>
     </properties>
 </project>
diff --git a/test-framework/maven/container-runner-maven-plugin/pom.xml b/test-framework/maven/container-runner-maven-plugin/pom.xml
index 539b839..c3b915d 100644
--- a/test-framework/maven/container-runner-maven-plugin/pom.xml
+++ b/test-framework/maven/container-runner-maven-plugin/pom.xml
@@ -36,9 +36,9 @@
     </description>
 
     <properties>
-        <groovy.version>2.4.9</groovy.version>
-        <groovy-eclipse-compiler.version>2.9.2-01</groovy-eclipse-compiler.version>
-        <groovy-eclipse-batch.version>2.5.7-01</groovy-eclipse-batch.version>
+        <groovy.version>3.0.2</groovy.version>
+        <groovy-eclipse-compiler.version>3.6.0-03</groovy-eclipse-compiler.version>
+        <groovy-eclipse-batch.version>3.0.2-02</groovy-eclipse-batch.version>
         <maven.version>3.6.0</maven.version>
         <maven-plugin.version>3.6.0</maven-plugin.version>
     </properties>
@@ -109,6 +109,7 @@
         <dependency>
             <groupId>org.codehaus.groovy</groupId>
             <artifactId>groovy-all</artifactId>
+            <type>pom</type>
             <version>${groovy.version}</version>
         </dependency>
 
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/HeaderDelegateProviderTest.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/HeaderDelegateProviderTest.java
index 38bea6e..71cc2ca 100644
--- a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/HeaderDelegateProviderTest.java
+++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/HeaderDelegateProviderTest.java
@@ -17,8 +17,12 @@
 package org.glassfish.jersey.tests.e2e.header;
 
 import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.client.ClientConfig;
 import org.glassfish.jersey.internal.ServiceFinder;
 import org.glassfish.jersey.message.internal.HeaderUtils;
+import org.glassfish.jersey.message.internal.HeaderValueException;
+import org.glassfish.jersey.message.internal.InboundMessageContext;
+import org.glassfish.jersey.message.internal.OutboundMessageContext;
 import org.glassfish.jersey.spi.HeaderDelegateProvider;
 import org.junit.Assert;
 import org.junit.Test;
@@ -34,14 +38,18 @@
 import jakarta.ws.rs.container.ContainerResponseFilter;
 import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ReaderInterceptor;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
+import static org.junit.Assert.fail;
+
 public class HeaderDelegateProviderTest {
     static final String HEADER_NAME = "BEAN_HEADER";
     static final String DISABLED_VALUE = new BeanForHeaderDelegateProviderTest().toString();
@@ -64,6 +72,23 @@
         }
     }
 
+    public static class EmptyContentTypeHandler implements HeaderDelegateProvider<MediaType> {
+        @Override
+        public boolean supports(Class<?> type) {
+            return MediaType.class == type;
+        }
+
+        @Override
+        public MediaType fromString(String value) {
+            return value.isEmpty() ? MediaType.APPLICATION_OCTET_STREAM_TYPE : MediaType.valueOf(value);
+        }
+
+        @Override
+        public String toString(MediaType value) {
+            return value.toString();
+        }
+    };
+
     public static class BeanForHeaderDelegateProviderTest {
         public static String getValue() {
             return "CORRECT_VALUE";
@@ -116,13 +141,18 @@
 
     @Test
     public void testTheProviderIsFound() {
+        int found = 0;
         for (HeaderDelegateProvider provider : ServiceFinder.find(HeaderDelegateProvider.class, true)) {
-            Assert.assertEquals(provider.getClass(), BeanHeaderDelegateProvider.class);
+            if (provider.getClass() == BeanHeaderDelegateProvider.class
+                    || provider.getClass() == EmptyContentTypeHandler.class) {
+                found++;
+            }
         }
+        Assert.assertEquals(2, found);
     }
 
     @Test
-    public void headerDelegateIsUsedWhenRuntimeDelegateDecoratorIsUsed() {
+    public void testHeaderDelegateIsUsedWhenRuntimeDelegateDecoratorIsUsed() {
         MultivaluedHashMap headers = new MultivaluedHashMap();
         headers.put(HEADER_NAME, Arrays.asList(new BeanForHeaderDelegateProviderTest()));
         MultivaluedMap<String, String> converted = HeaderUtils.asStringHeaders(headers, null);
@@ -134,7 +164,7 @@
     }
 
     @Test
-    public void headerDelegateIsNotUsed() {
+    public void testHeaderDelegateIsNotUsed() {
         MultivaluedHashMap headers = new MultivaluedHashMap();
         headers.put(HEADER_NAME, Arrays.asList(new BeanForHeaderDelegateProviderTest()));
 
@@ -147,6 +177,54 @@
         testMap(converted, DISABLED_VALUE);
     }
 
+    @Test
+    public void testGetMediaTypeInInboundMessageContext() {
+        ClientConfig config = new ClientConfig().property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
+        InboundMessageContext inboundMessageContext = new InboundMessageContext(config.getConfiguration()) {
+            @Override
+            protected Iterable<ReaderInterceptor> getReaderInterceptors() {
+                return null;
+            }
+        };
+        inboundMessageContext.header(HttpHeaders.CONTENT_TYPE, "");
+        try {
+            inboundMessageContext.getMediaType();
+            fail("Expected HeaderValueException has not been thrown");
+        } catch (HeaderValueException ex) {
+            // expected
+        }
+
+        config.property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, false);
+        inboundMessageContext = new InboundMessageContext(config.getConfiguration()) {
+            @Override
+            protected Iterable<ReaderInterceptor> getReaderInterceptors() {
+                return null;
+            }
+        };
+        inboundMessageContext.header(HttpHeaders.CONTENT_TYPE, "");
+        MediaType mediaType = inboundMessageContext.getMediaType();
+        Assert.assertEquals(MediaType.APPLICATION_OCTET_STREAM_TYPE, mediaType);
+    }
+
+    @Test
+    public void testGetMediaTypeInOutboundMessageContext() {
+        ClientConfig config = new ClientConfig().property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
+        OutboundMessageContext outboundMessageContext = new OutboundMessageContext(config.getConfiguration());
+        outboundMessageContext.getHeaders().add(HttpHeaders.CONTENT_TYPE, "");
+        try {
+            outboundMessageContext.getMediaType();
+            fail("Expected HeaderValueException has not been thrown");
+        } catch (IllegalArgumentException ex) {
+            // expected
+        }
+
+        config.property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, false);
+        outboundMessageContext = new OutboundMessageContext(config.getConfiguration());
+        outboundMessageContext.getHeaders().add(HttpHeaders.CONTENT_TYPE, "");
+        MediaType mediaType = outboundMessageContext.getMediaType();
+        Assert.assertEquals(MediaType.APPLICATION_OCTET_STREAM_TYPE, mediaType);
+    }
+
     private void testMap(MultivaluedMap<String, String> map, String expectedValue) {
         for (Map.Entry<String, List<String>> entry : map.entrySet()) {
             Assert.assertEquals(HEADER_NAME, entry.getKey());
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/json/entity/ComplexBeanWithAttributes4.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/json/entity/ComplexBeanWithAttributes4.java
index f14c9c7..660a6e2 100644
--- a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/json/entity/ComplexBeanWithAttributes4.java
+++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/json/entity/ComplexBeanWithAttributes4.java
@@ -86,7 +86,7 @@
     public int hashCode() {
         int hash = 3;
         hash = 19 * hash + (this.a1 != null ? this.a1.hashCode() : 0);
-        hash = 19 * hash + this.a2;
+        hash = 19 * hash + (this.a2 != null ? this.a2.hashCode() : 0);
         hash = 19 * hash + (this.b != null ? this.b.hashCode() : 0);
         hash = 19 * hash + (this.filler1 != null ? this.filler1.hashCode() : 0);
         hash = 19 * hash + (this.filler2 != null ? this.filler2.hashCode() : 0);
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/json/entity/SimpleBeanWithObjectAttributes.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/json/entity/SimpleBeanWithObjectAttributes.java
index 4cea599..5dc1d2a 100644
--- a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/json/entity/SimpleBeanWithObjectAttributes.java
+++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/json/entity/SimpleBeanWithObjectAttributes.java
@@ -80,7 +80,9 @@
         if (null != uri) {
             hash += 17 * uri.hashCode();
         }
-        hash += 13 * i;
+        if (null != i) {
+            hash += 13 * i;
+        }
         return hash;
     }
 
diff --git a/tests/e2e-entity/src/test/resources/META-INF/services/org.glassfish.jersey.spi.HeaderDelegateProvider b/tests/e2e-entity/src/test/resources/META-INF/services/org.glassfish.jersey.spi.HeaderDelegateProvider
index 1cca664..73f95b8 100644
--- a/tests/e2e-entity/src/test/resources/META-INF/services/org.glassfish.jersey.spi.HeaderDelegateProvider
+++ b/tests/e2e-entity/src/test/resources/META-INF/services/org.glassfish.jersey.spi.HeaderDelegateProvider
@@ -1 +1,2 @@
-org.glassfish.jersey.tests.e2e.header.HeaderDelegateProviderTest$BeanHeaderDelegateProvider
\ No newline at end of file
+org.glassfish.jersey.tests.e2e.header.HeaderDelegateProviderTest$BeanHeaderDelegateProvider
+org.glassfish.jersey.tests.e2e.header.HeaderDelegateProviderTest$EmptyContentTypeHandler
\ No newline at end of file
diff --git a/tests/integration/asm/src/test/java/org/glassfish/jersey/integration/asm/AnnotatedClassVisitorTest.java b/tests/integration/asm/src/test/java/org/glassfish/jersey/integration/asm/AnnotatedClassVisitorTest.java
index 708684d..54dbdc6 100644
--- a/tests/integration/asm/src/test/java/org/glassfish/jersey/integration/asm/AnnotatedClassVisitorTest.java
+++ b/tests/integration/asm/src/test/java/org/glassfish/jersey/integration/asm/AnnotatedClassVisitorTest.java
@@ -16,11 +16,17 @@
 package org.glassfish.jersey.integration.asm;
 
 import jersey.repackaged.org.objectweb.asm.ClassVisitor;
+import jersey.repackaged.org.objectweb.asm.Opcodes;
 import org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.List;
@@ -75,4 +81,97 @@
         }
         Assert.assertThat(containsAllMethods, Matchers.is(true));
     }
+
+    @Test
+    public void testCorrectOpcodeAsmIsUsedInAnnotationAcceptingListener() {
+        final int asmOpcode = getMaxValueOfField("ASM", 6);
+        final AnnotationAcceptingListener aal = new AnnotationAcceptingListener();
+
+        String aalOpcode = null;
+        try {
+            final Field classVisitorField = aal.getClass().getDeclaredField("classVisitor");
+            classVisitorField.setAccessible(true);
+            final Object classVisitor = classVisitorField.get(aal);
+            final Field opcodeField = classVisitor.getClass().getSuperclass().getDeclaredField("api");
+            opcodeField.setAccessible(true);
+            aalOpcode = String.valueOf(((Integer) opcodeField.get(classVisitor)) >> 16);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            e.printStackTrace();
+        }
+
+        Assert.assertEquals(
+                "You need to set: \nAnnotatedClassVisitor() {\n    super(Opcodes.ASM" + asmOpcode + ");\n}",
+                String.valueOf(asmOpcode), aalOpcode
+        );
+    }
+
+    @Test
+    public void testWarningOpcodeInClassReaderWrapperSetCorrectly() {
+        final Integer jdkVersion = getMaxValueOfField("V", 13);
+
+        Class<?> classReaderWrapper = null;
+        for (Class<?> innerClass : AnnotationAcceptingListener.class.getDeclaredClasses()) {
+            if (innerClass.getName().contains("ClassReaderWrapper")) {
+                classReaderWrapper = innerClass;
+                break;
+            }
+        }
+
+        Integer warnFieldValue = 0;
+        try {
+            final Field warnField = classReaderWrapper.getDeclaredField("WARN_VERSION");
+            warnField.setAccessible(true);
+            warnFieldValue = (Integer) warnField.get(null) - (Opcodes.V1_1 & 0x00FF) + 1;
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            e.printStackTrace();
+        }
+
+        Assert.assertEquals(
+                "You need to set ClassReaderWrapper.WARN_VERSION=Opcodes.V" + jdkVersion,
+                jdkVersion, warnFieldValue
+        );
+    }
+
+    @Test
+    public void testLoggerInClassReaderWrapper() throws IOException {
+        final String warningMsg = "Unsupported class file major version";
+
+        final Integer maxOpcode = getMaxValueOfField("V", 13);
+        final byte[] array = new byte[10];
+        array[7] = (byte) ((maxOpcode.byteValue() + Opcodes.V1_1) & 0x00FF);
+
+        final ByteArrayOutputStream log = new ByteArrayOutputStream(500);
+        final PrintStream saveErr = System.err;
+
+        try {
+            System.setErr(new PrintStream(log));
+            try {
+                new AnnotationAcceptingListener().process("", new ByteArrayInputStream(array));
+            } catch (ArrayIndexOutOfBoundsException aioobe) {
+                //expected, given array is too small for a class file
+            }
+        } finally {
+            System.setErr(saveErr);
+        }
+
+        final String message = new String(log.toByteArray());
+        Assert.assertTrue(
+                "The WARNING `" + warningMsg + "` has not been printed for a class with byte code version " + array[7],
+                message.contains(warningMsg)
+        );
+    }
+
+    private static int getMaxValueOfField(String fieldPrefix, int initialValue) {
+        int value = initialValue;
+        do {
+            try {
+                value++;
+                Field field = Opcodes.class.getField(fieldPrefix + value);
+            } catch (NoSuchFieldException e) {
+                value--;
+                break;
+            }
+        } while (true);
+        return value;
+    }
 }
diff --git a/tests/integration/jersey-2689/pom.xml b/tests/integration/jersey-2689/pom.xml
index 244e27e..f13b7a0 100644
--- a/tests/integration/jersey-2689/pom.xml
+++ b/tests/integration/jersey-2689/pom.xml
@@ -109,6 +109,14 @@
                             </excludes>
                         </configuration>
                     </plugin>
+                    <!-- TODO remove after jakartification -->
+                    <plugin>
+                        <groupId>org.eclipse.jetty</groupId>
+                        <artifactId>jetty-maven-plugin</artifactId>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </plugin>
                 </plugins>
             </build>
         </profile>
diff --git a/tests/integration/jetty-response-close/pom.xml b/tests/integration/jetty-response-close/pom.xml
new file mode 100644
index 0000000..ae3d0f2
--- /dev/null
+++ b/tests/integration/jetty-response-close/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration</groupId>
+        <version>3.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>jetty-response-close</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-jetty-http</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-server</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <!-- Test Backward compatibility with this version -->
+            <version>9.4.17.v20190418</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <properties>
+        <surefire.security.argline>-Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/surefire.policy</surefire.security.argline>
+    </properties>
+
+</project>
\ No newline at end of file
diff --git a/tests/integration/jetty-response-close/src/main/java/org/glassfish/jersey/tests/jettyresponseclose/Resource.java b/tests/integration/jetty-response-close/src/main/java/org/glassfish/jersey/tests/jettyresponseclose/Resource.java
new file mode 100644
index 0000000..ee620f4
--- /dev/null
+++ b/tests/integration/jetty-response-close/src/main/java/org/glassfish/jersey/tests/jettyresponseclose/Resource.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020 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.jettyresponseclose;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+
+@Path("/")
+public class Resource {
+    @GET
+    public String get() {
+        return Resource.class.getName();
+    }
+}
diff --git a/tests/integration/jetty-response-close/src/test/java/org/glassfish/jersey/tests/jettyresponseclose/JettyHttpContainerCloseTest.java b/tests/integration/jetty-response-close/src/test/java/org/glassfish/jersey/tests/jettyresponseclose/JettyHttpContainerCloseTest.java
new file mode 100644
index 0000000..3ffa479
--- /dev/null
+++ b/tests/integration/jetty-response-close/src/test/java/org/glassfish/jersey/tests/jettyresponseclose/JettyHttpContainerCloseTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 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.jettyresponseclose;
+
+import org.eclipse.jetty.server.Server;
+import org.glassfish.jersey.jetty.JettyHttpContainer;
+import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.core.Response;
+import java.net.URI;
+
+public class JettyHttpContainerCloseTest {
+
+    private static Server server;
+    private static JettyHttpContainer container;
+    private static final String URL = "http://localhost:9080";
+
+    @BeforeAll
+    public static void setup() {
+        server = JettyHttpContainerFactory.createServer(URI.create(URL),
+                new ResourceConfig(Resource.class));
+        container = (JettyHttpContainer) server.getHandler();
+    }
+
+    @AfterAll
+    public static void teardown() throws Exception {
+        container.doStop();
+    }
+
+    @Test
+    public void testResponseClose() {
+        try (Response response = ClientBuilder.newClient().target(URL).request().get()) {
+            Assertions.assertEquals(200, response.getStatus());
+            Assertions.assertEquals(Resource.class.getName(), response.readEntity(String.class));
+
+        }
+    }
+}
diff --git a/tests/integration/jetty-response-close/src/test/resources/surefire.policy b/tests/integration/jetty-response-close/src/test/resources/surefire.policy
new file mode 100644
index 0000000..f012633
--- /dev/null
+++ b/tests/integration/jetty-response-close/src/test/resources/surefire.policy
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 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
+ */
+
+// we do not care about java lib itself
+grant codebase "file:${java.home}/-" {
+  permission java.security.AllPermission;
+};
+
+// we do not care about our dependencies
+grant codebase "file:${settings.localRepository}/-" {
+  permission java.security.AllPermission;
+};
+
+grant codebase "file:${user.home}/-" {
+    permission java.io.FilePermission "<<ALL FILES>>", "read";
+};
+
+grant {
+    permission java.lang.management.ManagementPermission "monitor";
+    permission java.util.PropertyPermission "*", "read, write";
+    permission java.util.logging.LoggingPermission "control";
+    permission java.lang.RuntimePermission "setIO";
+    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+
+    permission java.lang.RuntimePermission "accessDeclaredMembers";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.io.FilePermission "<<ALL FILES>>", "read";
+
+    permission java.lang.RuntimePermission "getenv.JETTY_AVAILABLE_PROCESSORS";
+    permission java.net.SocketPermission "localhost", "accept,connect,listen,resolve";
+    permission java.lang.RuntimePermission "setContextClassLoader";
+};
diff --git a/tests/integration/microprofile/config/helidon/pom.xml b/tests/integration/microprofile/config/helidon/pom.xml
index ae6af54..5d2970e 100644
--- a/tests/integration/microprofile/config/helidon/pom.xml
+++ b/tests/integration/microprofile/config/helidon/pom.xml
@@ -20,10 +20,9 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
-        <artifactId>project</artifactId>
-        <groupId>org.glassfish.jersey.tests.integration</groupId>
+        <artifactId>microprofile-config-project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId>
         <version>3.0-SNAPSHOT</version>
-        <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -32,7 +31,7 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.glassfish.jersey.tests.integration</groupId>
+            <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId>
             <artifactId>config-webapp</artifactId>
             <version>${project.version}</version>
             <scope>test</scope>
diff --git a/tests/integration/microprofile/config/pom.xml b/tests/integration/microprofile/config/pom.xml
new file mode 100644
index 0000000..1013402
--- /dev/null
+++ b/tests/integration/microprofile/config/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>microprofile-integration-project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId>
+        <version>3.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>pom</packaging>
+
+    <artifactId>microprofile-config-project</artifactId>
+    <name>microprofile-config-project</name>
+    <modules>
+        <module>helidon</module>
+        <module>webapp</module>
+    </modules>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-install-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/tests/integration/microprofile/config/webapp/pom.xml b/tests/integration/microprofile/config/webapp/pom.xml
index 62354b0..796497b 100644
--- a/tests/integration/microprofile/config/webapp/pom.xml
+++ b/tests/integration/microprofile/config/webapp/pom.xml
@@ -20,10 +20,9 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
-        <artifactId>project</artifactId>
-        <groupId>org.glassfish.jersey.tests.integration</groupId>
+        <artifactId>microprofile-config-project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId>
         <version>3.0-SNAPSHOT</version>
-        <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/tests/integration/microprofile/pom.xml b/tests/integration/microprofile/pom.xml
new file mode 100644
index 0000000..93f7e03
--- /dev/null
+++ b/tests/integration/microprofile/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration</groupId>
+        <version>3.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>pom</packaging>
+
+    <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId>
+    <artifactId>microprofile-integration-project</artifactId>
+    <name>microprofile-integration-project</name>
+    <modules>
+        <module>config</module>
+<!--        <module>rest-client</module>-->
+    </modules>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-install-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/tests/integration/microprofile/rest-client/pom.xml b/tests/integration/microprofile/rest-client/pom.xml
index 30986ad..937569a 100644
--- a/tests/integration/microprofile/rest-client/pom.xml
+++ b/tests/integration/microprofile/rest-client/pom.xml
@@ -16,15 +16,13 @@
     SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 
 -->
-
 <project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
-        <artifactId>project</artifactId>
-        <groupId>org.glassfish.jersey.tests.integration</groupId>
+        <artifactId>microprofile-integration-project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId>
         <version>3.0-SNAPSHOT</version>
-        <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml
index f254b01..3da31ce 100644
--- a/tests/integration/pom.xml
+++ b/tests/integration/pom.xml
@@ -84,7 +84,9 @@
         <module>jersey-3992</module>
         <module>jersey-4099</module>
         <module>jersey-4321</module>
-<!--        <module>portability-jersey-1</module>-->
+        <module>jetty-response-close</module>
+        <module>microprofile</module>
+<!--        <module>portability-jersey-1</module>--> <!--TODO remove when Jakartified -->
 <!--        <module>portability-jersey-2</module>-->
         <module>property-check</module>
         <module>security-digest</module>
@@ -127,9 +129,6 @@
         <module>spring4</module>
         <module>spring5</module>
         <module>tracing-support</module>
-        <module>microprofile/config/helidon</module>
-        <module>microprofile/config/webapp</module>
-<!--        <module>microprofile/rest-client</module>-->
     </modules>
 
     <profiles>
diff --git a/tests/osgi/functional/pom.xml b/tests/osgi/functional/pom.xml
index 67cda5c..6fbe70d 100644
--- a/tests/osgi/functional/pom.xml
+++ b/tests/osgi/functional/pom.xml
@@ -150,7 +150,7 @@
         <dependency>
             <groupId>org.ops4j.pax.url</groupId>
             <artifactId>pax-url-aether</artifactId>
-            <version>1.6.0</version>
+            <version>2.6.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -184,7 +184,7 @@
             <groupId>org.ops4j.pax.logging</groupId>
             <artifactId>pax-logging-api</artifactId>
             <scope>test</scope>
-            <version>1.8.3</version>
+            <version>1.11.5</version>
         </dependency>
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
@@ -356,13 +356,6 @@
             <artifactId>jakarta.xml.bind-api</artifactId>
             <scope>test</scope>
         </dependency>
-<!--        <dependency>-->
-<!--            Not needed since Jackson 2.10.1 -->
-<!--            <groupId>com.sun.activation</groupId>-->
-<!--            <artifactId>jakarta.activation</artifactId>-->
-<!--            <version>${jakarta.activation.version}</version>-->
-<!--            <scope>test</scope>-->
-<!--        </dependency>-->
 
         <!-- logging -->
         <dependency>
@@ -375,6 +368,19 @@
 
     <profiles>
         <profile>
+            <id>jdk11dependency</id>
+            <activation>
+                <jdk>[11,)</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>com.sun.activation</groupId>
+                    <artifactId>jakarta.activation</artifactId>
+                    <version>${jakarta.activation.version}</version>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
             <id>testsSkipJdk8</id>
             <activation>
                 <jdk>[1.8,11)</jdk>
diff --git a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/util/Helper.java b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/util/Helper.java
index 115c6a9..7811cbe 100644
--- a/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/util/Helper.java
+++ b/tests/osgi/functional/src/test/java/org/glassfish/jersey/osgi/test/util/Helper.java
@@ -21,6 +21,7 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.glassfish.jersey.internal.util.JdkVersion;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
 import org.glassfish.jersey.test.TestProperties;
 
@@ -180,16 +181,21 @@
                     mavenBundle().groupId("org.glassfish.jersey.core").artifactId("jersey-client").versionAsInProject(),
 
                     // Jersey Injection provider
-                    mavenBundle().groupId("org.glassfish.jersey.inject").artifactId("jersey-hk2").versionAsInProject()
+                    mavenBundle().groupId("org.glassfish.jersey.inject").artifactId("jersey-hk2").versionAsInProject(),
 //                     Jaxb - api
-                    // not needed since Jackson 2.10.1
-                    // mavenBundle().groupId("com.sun.activation").artifactId("jakarta.activation").versionAsInProject()
+                    getActivationBundle()
             ));
         }
 
         return addPaxExamMavenLocalRepositoryProperty(options);
     }
 
+    private static Option getActivationBundle() {
+        return JdkVersion.getJdkVersion().getMajor() > 8
+                ? mavenBundle().groupId("com.sun.activation").artifactId("jakarta.activation").versionAsInProject()
+                : null;
+    }
+
     /**
      * Create expanded options list from the supplied options.
      *