Merge remote-tracking branch 'upstream/2.x' into 'upstream/3.0'

Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
diff --git a/NOTICE.md b/NOTICE.md
index 350c730..e9981e6 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -70,7 +70,7 @@
 * Project: http://www.javassist.org/

 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.

 

-Jackson JAX-RS Providers Version 2.17.2

+Jackson JAX-RS Providers Version 2.18.0

 * License: Apache License, 2.0

 * Project: https://github.com/FasterXML/jackson-jaxrs-providers

 * Copyright: (c) 2009-2024 FasterXML, LLC. All rights reserved unless otherwise indicated.

@@ -95,7 +95,7 @@
 * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS

 * Copyright: Eric Rowell

 

-org.objectweb.asm Version 9.7

+org.objectweb.asm Version 9.7.1

 * License: Modified BSD (https://asm.ow2.io/license.html)

 * Copyright (c) 2000-2011 INRIA, France Telecom. All rights reserved.

 

diff --git a/connectors/netty-connector/pom.xml b/connectors/netty-connector/pom.xml
index 109a009..0d4ed01 100644
--- a/connectors/netty-connector/pom.xml
+++ b/connectors/netty-connector/pom.xml
@@ -101,6 +101,24 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>InaccessibleObjectException</id>
+            <activation><jdk>[12,)</jdk></activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <argLine>
+                                --add-opens java.base/java.lang=ALL-UNNAMED
+                                --add-opens java.base/java.lang.reflect=ALL-UNNAMED
+                            </argLine>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
 
 </project>
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 cec1348..4544157 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
@@ -436,7 +436,7 @@
                     };
                 ch.closeFuture().addListener(closeListener);
 
-                final NettyEntityWriter entityWriter = NettyEntityWriter.getInstance(jerseyRequest, ch);
+                final NettyEntityWriter entityWriter = nettyEntityWriter(jerseyRequest, ch);
                 switch (entityWriter.getType()) {
                     case CHUNKED:
                         HttpUtil.setTransferEncodingChunked(nettyRequest, true);
@@ -524,6 +524,10 @@
         }
     }
 
+    /* package */ NettyEntityWriter nettyEntityWriter(ClientRequest clientRequest, Channel channel) {
+        return NettyEntityWriter.getInstance(clientRequest, channel);
+    }
+
     private SSLContext getSslContext(Client client, ClientRequest request) {
         Supplier<SSLContext> supplier = request.resolveProperty(ClientProperties.SSL_CONTEXT_SUPPLIER, Supplier.class);
         return supplier == null ? client.getSslContext() : supplier.get();
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/JerseyChunkedInput.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/JerseyChunkedInput.java
index ad6da7e..4ffe52e 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/JerseyChunkedInput.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/JerseyChunkedInput.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -101,7 +101,15 @@
 
     @Override
     public ByteBuf readChunk(ByteBufAllocator allocator) throws Exception {
+        try {
+            return readChunk0(allocator);
+        } catch (Exception e) {
+            closeOnThrowable();
+            throw e;
+        }
+    }
 
+    private ByteBuf readChunk0(ByteBufAllocator allocator) throws Exception {
         if (!open) {
             return null;
         }
@@ -143,6 +151,14 @@
         return offset;
     }
 
+    private void closeOnThrowable() {
+        try {
+            close();
+        } catch (Throwable t) {
+            // do not throw other throwable
+        }
+    }
+
     @Override
     public void close() throws IOException {
 
@@ -208,10 +224,12 @@
         try {
             boolean queued = queue.offer(bufferSupplier.get(), WRITE_TIMEOUT, TimeUnit.MILLISECONDS);
             if (!queued) {
+                closeOnThrowable();
                 throw new IOException("Buffer overflow.");
             }
 
         } catch (InterruptedException e) {
+            closeOnThrowable();
             throw new IOException(e);
         }
     }
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/ChunkedInputWriteErrorSimulationTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/ChunkedInputWriteErrorSimulationTest.java
new file mode 100644
index 0000000..78a3448
--- /dev/null
+++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/ChunkedInputWriteErrorSimulationTest.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.netty.connector;
+
+import io.netty.channel.Channel;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.ClientRequest;
+import org.glassfish.jersey.client.spi.Connector;
+import org.glassfish.jersey.client.spi.ConnectorProvider;
+import org.glassfish.jersey.netty.connector.internal.JerseyChunkedInput;
+import org.glassfish.jersey.netty.connector.internal.NettyEntityWriter;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedHashMap;
+import jakarta.ws.rs.core.Response;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class ChunkedInputWriteErrorSimulationTest extends JerseyTest {
+    private static final String EXCEPTION_MSG = "BOGUS BUFFER OVERFLOW";
+    private static final AtomicReference<Throwable> caught = new AtomicReference<>(null);
+
+    public static class ClientThread extends Thread {
+
+        public static AtomicInteger count = new AtomicInteger();
+        public static String url;
+        public static int nLoops;
+
+        private static Client client;
+
+        public static void main(DequeOffer offer, String[] args) throws InterruptedException {
+            url = args[0];
+            int nThreads = Integer.parseInt(args[1]);
+            nLoops = Integer.parseInt(args[2]);
+            initClient(offer);
+            Thread[] threads = new Thread[nThreads];
+            for (int i = 0; i < nThreads; i++) {
+                threads[i] = new ClientThread();
+                threads[i].start();
+            }
+
+            for (int i = 0; i < nThreads; i++) {
+                threads[i].join();
+            }
+            // System.out.println("Processed calls: " + count);
+        }
+
+        private static void initClient(DequeOffer offer) {
+            ClientConfig defaultConfig = new ClientConfig();
+            defaultConfig.property(ClientProperties.CONNECT_TIMEOUT, 10 * 1000);
+            defaultConfig.property(ClientProperties.READ_TIMEOUT, 10 * 1000);
+            defaultConfig.connectorProvider(getJerseyChunkedInputModifiedNettyConnector(offer));
+            client = ClientBuilder.newBuilder()
+                    .withConfig(defaultConfig)
+                    .build();
+        }
+
+        public void doCall() {
+            CompletableFuture<Response> cf = invokeResponse().toCompletableFuture()
+                    .whenComplete((rsp, t) -> {
+                        if (t != null) {
+//                            System.out.println(Thread.currentThread() + " async complete. Caught exception " + t);
+//                            t.printStackTrace();
+                            while (t.getCause() != null) {
+                                t = t.getCause();
+                            }
+                            caught.set(t);
+                        }
+                    })
+                    .handle((rsp, t) -> {
+                        if (rsp != null) {
+                            rsp.readEntity(String.class);
+                        } else {
+                            System.out.println(Thread.currentThread().getName() + " response is null");
+                        }
+                        return rsp;
+                    }).exceptionally(t -> {
+                        System.out.println("async complete. completed exceptionally " + t);
+                        throw new RuntimeException(t);
+                    });
+
+            try {
+                cf.get();
+                System.out.println("Done call " + count.incrementAndGet());
+            } catch (InterruptedException | ExecutionException ex) {
+                Logger.getLogger(ClientThread.class.getName()).log(Level.SEVERE, null, ex);
+            }
+        }
+
+        private static CompletionStage<Response> invokeResponse() {
+            WebTarget target = client.target(url);
+            MultivaluedHashMap hdrs = new MultivaluedHashMap<>();
+            StringBuilder sb = new StringBuilder("{");
+            for (int i = 0; i < 10000; i++) {
+                sb.append("\"fname\":\"foo\", \"lname\":\"bar\"");
+            }
+            sb.append("}");
+            String jsonPayload = sb.toString();
+            Invocation.Builder builder = ((WebTarget) target).request().headers(hdrs);
+            return builder.rx().method("POST", Entity.entity(jsonPayload, MediaType.APPLICATION_JSON_TYPE));
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < nLoops; i++) {
+                try {
+                    doCall();
+                } catch (Throwable t) {
+                    throw new RuntimeException(t);
+                }
+            }
+        }
+    }
+
+    @Path("/console")
+    public static class HangingEndpoint {
+        @Path("/login")
+        @POST
+        public String post(String entity) {
+            return "Welcome";
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        return new ResourceConfig(HangingEndpoint.class);
+    }
+
+    @Test
+    public void testNoHangOnOfferInterrupt() throws InterruptedException {
+        String path = getBaseUri() + "console/login";
+        ClientThread.main(new InterruptedExceptionOffer(), new String[] {path, "5", "10"});
+        Assertions.assertTrue(caught.get().getMessage().contains(EXCEPTION_MSG));
+    }
+
+    @Test
+    public void testNoHangOnPollInterrupt() throws InterruptedException {
+        String path = getBaseUri() + "console/login";
+        ClientThread.main(new DequePoll(), new String[] {path, "5", "10"});
+        Assertions.assertNotNull(caught.get());
+    }
+
+    @Test
+    public void testNoHangOnOfferNoData() throws InterruptedException {
+        String path = getBaseUri() + "console/login";
+        ClientThread.main(new ReturnFalseOffer(), new String[] {path, "5", "10"});
+        Assertions.assertTrue(caught.get().getMessage().contains("Buffer overflow")); //JerseyChunkedInput
+        Thread.sleep(1_000L); // Sleep for the server to finish
+    }
+
+    private interface DequeOffer {
+        public boolean offer(ByteBuffer e, long timeout, TimeUnit unit) throws InterruptedException;
+    }
+
+    private static class InterruptedExceptionOffer implements DequeOffer {
+        private AtomicInteger ai = new AtomicInteger(0);
+
+        @Override
+        public boolean offer(ByteBuffer e, long timeout, TimeUnit unit) throws InterruptedException {
+            if ((ai.getAndIncrement() % 10) == 0) {
+                throw new InterruptedException(EXCEPTION_MSG);
+            }
+            return true;
+        }
+    }
+
+    private static class ReturnFalseOffer implements DequeOffer {
+        private AtomicInteger ai = new AtomicInteger(0);
+        @Override
+        public boolean offer(ByteBuffer e, long timeout, TimeUnit unit) throws InterruptedException {
+            return !((ai.getAndIncrement() % 10) == 1);
+        }
+    }
+
+    private static class DequePoll extends InterruptedExceptionOffer {
+    }
+
+
+    private static ConnectorProvider getJerseyChunkedInputModifiedNettyConnector(DequeOffer offer) {
+        return new ConnectorProvider() {
+            @Override
+            public Connector getConnector(Client client, Configuration runtimeConfig) {
+                return new NettyConnector(client) {
+                    NettyEntityWriter nettyEntityWriter(ClientRequest clientRequest, Channel channel) {
+                        NettyEntityWriter wrapped = NettyEntityWriter.getInstance(clientRequest, channel);
+
+                        JerseyChunkedInput chunkedInput = (JerseyChunkedInput) wrapped.getChunkedInput();
+                        try {
+                            Field field = JerseyChunkedInput.class.getDeclaredField("queue");
+                            field.setAccessible(true);
+
+                            removeFinal(field);
+
+                            field.set(chunkedInput, new LinkedBlockingDeque<ByteBuffer>() {
+                                @Override
+                                public boolean offer(ByteBuffer e, long timeout, TimeUnit unit) throws InterruptedException {
+                                    if (!DequePoll.class.isInstance(offer) && !offer.offer(e, timeout, unit)) {
+                                        return false;
+                                    }
+                                    return super.offer(e, timeout, unit);
+                                }
+
+                                @Override
+                                public ByteBuffer poll(long timeout, TimeUnit unit) throws InterruptedException {
+                                    if (DequePoll.class.isInstance(offer)) {
+                                        offer.offer(null, timeout, unit);
+                                    }
+                                    return super.poll(timeout, unit);
+                                }
+                            });
+
+                        } catch (Exception e) {
+                            throw new RuntimeException(e);
+                        }
+
+                        NettyEntityWriter proxy = (NettyEntityWriter) Proxy.newProxyInstance(
+                                ConnectorProvider.class.getClassLoader(), new Class[]{NettyEntityWriter.class},
+                                (proxy1, method, args) -> {
+                                    if (method.getName().equals("readChunk")) {
+                                        try {
+                                            return method.invoke(wrapped, args);
+                                        } catch (RuntimeException e) {
+                                            // consume
+                                        }
+                                    }
+                                    return method.invoke(wrapped, args);
+                                });
+                        return proxy;
+                    }
+                };
+            }
+        };
+    }
+
+    public static void removeFinal(Field field) throws RuntimeException {
+        try {
+            Method[] classMethods = Class.class.getDeclaredMethods();
+            Method declaredFieldMethod = Arrays
+                    .stream(classMethods).filter(x -> Objects.equals(x.getName(), "getDeclaredFields0"))
+                    .findAny().orElseThrow(() -> new NoSuchElementException("No value present"));
+            declaredFieldMethod.setAccessible(true);
+            Field[] declaredFieldsOfField = (Field[]) declaredFieldMethod.invoke(Field.class, false);
+            Field modifiersField = Arrays
+                    .stream(declaredFieldsOfField).filter(x -> Objects.equals(x.getName(), "modifiers"))
+                    .findAny().orElseThrow(() -> new NoSuchElementException("No value present"));
+            modifiersField.setAccessible(true);
+            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+        } catch (RuntimeException re) {
+            throw re;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Attribute.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Attribute.java
index f63fc71..1fe6dbf 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Attribute.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Attribute.java
@@ -44,11 +44,11 @@
   public final String type;
 
   /**
-   * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
-   * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
-   * included.
+   * The raw content of this attribute, as returned by {@link
+   * #write(ClassWriter,byte[],int,int,int)}. The 6 header bytes of the attribute
+   * (attribute_name_index and attribute_length) are <i>not</i> included.
    */
-  private byte[] content;
+  private ByteVector cachedContent;
 
   /**
    * The next attribute in this attribute list (Attribute instances can be linked via this field to
@@ -93,7 +93,9 @@
    *
    * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
    *     a Code attribute that contains labels.
+   * @deprecated no longer used by ASM.
    */
+  @Deprecated
   protected Label[] getLabels() {
     return new Label[0];
   }
@@ -115,7 +117,9 @@
    *     attribute header bytes (attribute_name_index and attribute_length) are not taken into
    *     account here.
    * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
-   *     is not a Code attribute.
+   *     is not a Code attribute. Labels defined in the attribute must be created and added to this
+   *     array, if not already present, by calling the {@link #readLabel} method (do not create
+   *     {@link Label} instances directly).
    * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
    */
   protected Attribute read(
@@ -126,16 +130,99 @@
       final int codeAttributeOffset,
       final Label[] labels) {
     Attribute attribute = new Attribute(type);
-    attribute.content = new byte[length];
-    System.arraycopy(classReader.classFileBuffer, offset, attribute.content, 0, length);
+    attribute.cachedContent = new ByteVector(classReader.readBytes(offset, length));
     return attribute;
   }
 
   /**
+   * Reads an attribute with the same {@link #type} as the given attribute. This method returns a
+   * new {@link Attribute} object, corresponding to the 'length' bytes starting at 'offset', in the
+   * given ClassReader.
+   *
+   * @param attribute The attribute prototype that is used for reading.
+   * @param classReader the class that contains the attribute to be read.
+   * @param offset index of the first byte of the attribute's content in {@link ClassReader}. The 6
+   *     attribute header bytes (attribute_name_index and attribute_length) are not taken into
+   *     account here.
+   * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
+   * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
+   *     'charBuffer' parameter.
+   * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
+   *     in {@link ClassReader}, or -1 if the attribute to be read is not a Code attribute. The 6
+   *     attribute header bytes (attribute_name_index and attribute_length) are not taken into
+   *     account here.
+   * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
+   *     is not a Code attribute. Labels defined in the attribute are added to this array, if not
+   *     already present.
+   * @return a new {@link Attribute} object corresponding to the specified bytes.
+   */
+  public static Attribute read(
+      final Attribute attribute,
+      final ClassReader classReader,
+      final int offset,
+      final int length,
+      final char[] charBuffer,
+      final int codeAttributeOffset,
+      final Label[] labels) {
+    return attribute.read(classReader, offset, length, charBuffer, codeAttributeOffset, labels);
+  }
+
+  /**
+   * Returns the label corresponding to the given bytecode offset by calling {@link
+   * ClassReader#readLabel}. This creates and adds the label to the given array if it is not already
+   * present. Note that this created label may be a {@link Label} subclass instance, if the given
+   * ClassReader overrides {@link ClassReader#readLabel}. Hence {@link #read(ClassReader, int, int,
+   * char[], int, Label[])} must not manually create {@link Label} instances.
+   *
+   * @param bytecodeOffset a bytecode offset in a method.
+   * @param labels the already created labels, indexed by their offset. If a label already exists
+   *     for bytecodeOffset this method does not create a new one. Otherwise it stores the new label
+   *     in this array.
+   * @return a label for the given bytecode offset.
+   */
+  public static Label readLabel(
+      final ClassReader classReader, final int bytecodeOffset, final Label[] labels) {
+    return classReader.readLabel(bytecodeOffset, labels);
+  }
+
+  /**
+   * Calls {@link #write(ClassWriter,byte[],int,int,int)} if it has not already been called and
+   * returns its result or its (cached) previous result.
+   *
+   * @param classWriter the class to which this attribute must be added. This parameter can be used
+   *     to add the items that corresponds to this attribute to the constant pool of this class.
+   * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
+   *     if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
+   *     attribute.
+   * @param codeLength the length of the bytecode of the method corresponding to this code
+   *     attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length'
+   *     field of the Code attribute.
+   * @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
+   *     -1 if this attribute is not a Code attribute.
+   * @param maxLocals the maximum number of local variables of the method corresponding to this code
+   *     attribute, or -1 if this attribute is not a Code attribute.
+   * @return the byte array form of this attribute.
+   */
+  private ByteVector maybeWrite(
+      final ClassWriter classWriter,
+      final byte[] code,
+      final int codeLength,
+      final int maxStack,
+      final int maxLocals) {
+    if (cachedContent == null) {
+      cachedContent = write(classWriter, code, codeLength, maxStack, maxLocals);
+    }
+    return cachedContent;
+  }
+
+  /**
    * Returns the byte array form of the content of this attribute. The 6 header bytes
    * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
    * ByteVector.
    *
+   * <p>This method is only invoked once to compute the binary form of this attribute. Subsequent
+   * changes to the attribute after it was written for the first time will not be considered.
+   *
    * @param classWriter the class to which this attribute must be added. This parameter can be used
    *     to add the items that corresponds to this attribute to the constant pool of this class.
    * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
@@ -156,7 +243,39 @@
       final int codeLength,
       final int maxStack,
       final int maxLocals) {
-    return new ByteVector(content);
+    return cachedContent;
+  }
+
+  /**
+   * Returns the byte array form of the content of the given attribute. The 6 header bytes
+   * (attribute_name_index and attribute_length) are <i>not</i> added in the returned byte array.
+   *
+   * @param attribute The attribute that should be written.
+   * @param classWriter the class to which this attribute must be added. This parameter can be used
+   *     to add the items that corresponds to this attribute to the constant pool of this class.
+   * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
+   *     if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
+   *     attribute.
+   * @param codeLength the length of the bytecode of the method corresponding to this code
+   *     attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length'
+   *     field of the Code attribute.
+   * @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
+   *     -1 if this attribute is not a Code attribute.
+   * @param maxLocals the maximum number of local variables of the method corresponding to this code
+   *     attribute, or -1 if this attribute is not a Code attribute.
+   * @return the byte array form of this attribute.
+   */
+  public static byte[] write(
+      final Attribute attribute,
+      final ClassWriter classWriter,
+      final byte[] code,
+      final int codeLength,
+      final int maxStack,
+      final int maxLocals) {
+    ByteVector content = attribute.maybeWrite(classWriter, code, codeLength, maxStack, maxLocals);
+    byte[] result = new byte[content.length];
+    System.arraycopy(content.data, 0, result, 0, content.length);
+    return result;
   }
 
   /**
@@ -221,7 +340,7 @@
     Attribute attribute = this;
     while (attribute != null) {
       symbolTable.addConstantUtf8(attribute.type);
-      size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
+      size += 6 + attribute.maybeWrite(classWriter, code, codeLength, maxStack, maxLocals).length;
       attribute = attribute.nextAttribute;
     }
     return size;
@@ -308,7 +427,7 @@
     Attribute attribute = this;
     while (attribute != null) {
       ByteVector attributeContent =
-          attribute.write(classWriter, code, codeLength, maxStack, maxLocals);
+          attribute.maybeWrite(classWriter, code, codeLength, maxStack, maxLocals);
       // Put attribute_name_index and attribute_length.
       output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
       output.putByteArray(attributeContent.data, 0, attributeContent.length);
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 a2bdae3..f5d846a 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
@@ -195,7 +195,7 @@
     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.V23) {
+    if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V24) {
       throw new IllegalArgumentException(
           "Unsupported class file major version " + readShort(classFileOffset + 6));
     }
@@ -3598,6 +3598,20 @@
   }
 
   /**
+   * Reads several bytes in this {@link ClassReader}. <i>This method is intended for {@link
+   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of the bytes to be read in this {@link ClassReader}.
+   * @param length the number of bytes to read.
+   * @return the read bytes.
+   */
+  public byte[] readBytes(final int offset, final int length) {
+    byte[] result = new byte[length];
+    System.arraycopy(classFileBuffer, offset, result, 0, length);
+    return result;
+  }
+
+  /**
    * Reads an unsigned short value in this {@link ClassReader}. <i>This method is intended for
    * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
    *
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 0af80ce..fa16ac9 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
@@ -264,13 +264,7 @@
     super(/* latest api = */ Opcodes.ASM9);
     this.flags = flags;
     symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
-    if ((flags & COMPUTE_FRAMES) != 0) {
-      compute = MethodWriter.COMPUTE_ALL_FRAMES;
-    } else if ((flags & COMPUTE_MAXS) != 0) {
-      compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
-    } else {
-      compute = MethodWriter.COMPUTE_NOTHING;
-    }
+    setFlags(flags);
   }
 
   // -----------------------------------------------------------------------------------------------
@@ -1020,6 +1014,28 @@
     return symbolTable.addConstantNameAndType(name, descriptor);
   }
 
+  /**
+   * Changes the computation strategy of method properties like max stack size, max number of local
+   * variables, and frames.
+   *
+   * <p><b>WARNING</b>: {@link #setFlags(int)} method changes the behavior of new method visitors
+   * returned from {@link #visitMethod(int, String, String, String, String[])}. The behavior will be
+   * changed only after the next method visitor is returned. All the previously returned method
+   * visitors keep their previous behavior.
+   *
+   * @param flags option flags that can be used to modify the default behavior of this class. Must
+   *     be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}.
+   */
+  public final void setFlags(final int flags) {
+    if ((flags & ClassWriter.COMPUTE_FRAMES) != 0) {
+      compute = MethodWriter.COMPUTE_ALL_FRAMES;
+    } else if ((flags & ClassWriter.COMPUTE_MAXS) != 0) {
+      compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
+    } else {
+      compute = MethodWriter.COMPUTE_NOTHING;
+    }
+  }
+
   // -----------------------------------------------------------------------------------------------
   // Default method to compute common super classes when computing stack map frames
   // -----------------------------------------------------------------------------------------------
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 9e7b98c..1c79ca7 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
@@ -215,7 +215,7 @@
     }
     if (minorVersion != 0xFFFF) {
       throw new IllegalStateException(
-          "ASM9_EXPERIMENTAL can only be used by classes compiled with --enable-preview");
+          "ASM10_EXPERIMENTAL can only be used by classes compiled with --enable-preview");
     }
   }
 }
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 c8a482b..e2f2c92 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
@@ -34,15 +34,16 @@
  * visitTypeAnnotation} | {@code visitAttribute} )* [ {@code visitCode} ( {@code visitFrame} |
  * {@code visit<i>X</i>Insn} | {@code visitLabel} | {@code visitInsnAnnotation} | {@code
  * visitTryCatchBlock} | {@code visitTryCatchAnnotation} | {@code visitLocalVariable} | {@code
- * visitLocalVariableAnnotation} | {@code visitLineNumber} )* {@code visitMaxs} ] {@code visitEnd}.
- * In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel} methods must be called in the
- * sequential order of the bytecode instructions of the visited code, {@code visitInsnAnnotation}
- * must be called <i>after</i> the annotated instruction, {@code visitTryCatchBlock} must be called
- * <i>before</i> the labels passed as arguments have been visited, {@code
- * visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try catch block has
- * been visited, and the {@code visitLocalVariable}, {@code visitLocalVariableAnnotation} and {@code
- * visitLineNumber} methods must be called <i>after</i> the labels passed as arguments have been
- * visited.
+ * visitLocalVariableAnnotation} | {@code visitLineNumber} | {@code visitAttribute} )* {@code
+ * visitMaxs} ] {@code visitEnd}. In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel}
+ * methods must be called in the sequential order of the bytecode instructions of the visited code,
+ * {@code visitInsnAnnotation} must be called <i>after</i> the annotated instruction, {@code
+ * visitTryCatchBlock} must be called <i>before</i> the labels passed as arguments have been
+ * visited, {@code visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try
+ * catch block has been visited, and the {@code visitLocalVariable}, {@code
+ * visitLocalVariableAnnotation} and {@code visitLineNumber} methods must be called <i>after</i> the
+ * labels passed as arguments have been visited. Finally, the {@code visitAttribute} method must be
+ * called before {@code visitCode} for non-code attributes, and after it for code attributes.
  *
  * @author Eric Bruneton
  */
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 bccc997..b49f443 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
@@ -1519,14 +1519,14 @@
       return lastCodeRuntimeVisibleTypeAnnotation =
           new AnnotationWriter(
               symbolTable,
-              /* useNamedValues = */ true,
+              /* useNamedValues= */ true,
               typeAnnotation,
               lastCodeRuntimeVisibleTypeAnnotation);
     } else {
       return lastCodeRuntimeInvisibleTypeAnnotation =
           new AnnotationWriter(
               symbolTable,
-              /* useNamedValues = */ true,
+              /* useNamedValues= */ true,
               typeAnnotation,
               lastCodeRuntimeInvisibleTypeAnnotation);
     }
@@ -1642,7 +1642,7 @@
           code.data[endOffset] = (byte) Opcodes.ATHROW;
           // Emit a frame for this unreachable block, with no local and a Throwable on the stack
           // (so that the ATHROW could consume this Throwable if it were reachable).
-          int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
+          int frameIndex = visitFrameStart(startOffset, /* numLocal= */ 0, /* numStack= */ 1);
           currentFrame[frameIndex] =
               Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
           visitFrameEnd();
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 f796c94..eeb3df7 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
@@ -289,6 +289,7 @@
   int V21 = 0 << 16 | 65;
   int V22 = 0 << 16 | 66;
   int V23 = 0 << 16 | 67;
+  int V24 = 0 << 16 | 68;
 
   /**
    * Version flag indicating that the class is using 'preview' features.
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Symbol.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Symbol.java
index f161884..34f3653 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Symbol.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Symbol.java
@@ -178,7 +178,9 @@
    *   <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link
    *       #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG},
    *   <li>the CONSTANT_MethodHandle_info reference_kind field value for {@link
-   *       #CONSTANT_METHOD_HANDLE_TAG} symbols,
+   *       #CONSTANT_METHOD_HANDLE_TAG} symbols (or this value left shifted by 8 bits for
+   *       reference_kind values larger than or equal to H_INVOKEVIRTUAL and if the method owner is
+   *       an interface),
    *   <li>the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link
    *       #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
    *   <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for
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 9ceffb1..e5e16be 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
@@ -221,7 +221,9 @@
               classReader.readByte(itemOffset),
               classReader.readClass(memberRefItemOffset, charBuffer),
               classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
-              classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
+              classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer),
+              classReader.readByte(memberRefItemOffset - 1)
+                  == Symbol.CONSTANT_INTERFACE_METHODREF_TAG);
           break;
         case Symbol.CONSTANT_DYNAMIC_TAG:
         case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
@@ -830,14 +832,15 @@
       final String descriptor,
       final boolean isInterface) {
     final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
+    final int data = getConstantMethodHandleSymbolData(referenceKind, isInterface);
     // Note that we don't need to include isInterface in the hash computation, because it is
     // redundant with owner (we can't have the same owner with different isInterface values).
-    int hashCode = hash(tag, owner, name, descriptor, referenceKind);
+    int hashCode = hash(tag, owner, name, descriptor, data);
     Entry entry = get(hashCode);
     while (entry != null) {
       if (entry.tag == tag
           && entry.hashCode == hashCode
-          && entry.data == referenceKind
+          && entry.data == data
           && entry.owner.equals(owner)
           && entry.name.equals(name)
           && entry.value.equals(descriptor)) {
@@ -851,8 +854,7 @@
       constantPool.put112(
           tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index);
     }
-    return put(
-        new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode));
+    return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, data, hashCode));
   }
 
   /**
@@ -866,16 +868,36 @@
    * @param owner the internal name of a class of interface.
    * @param name a field or method name.
    * @param descriptor a field or method descriptor.
+   * @param isInterface whether owner is an interface or not.
    */
   private void addConstantMethodHandle(
       final int index,
       final int referenceKind,
       final String owner,
       final String name,
-      final String descriptor) {
+      final String descriptor,
+      final boolean isInterface) {
     final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
-    int hashCode = hash(tag, owner, name, descriptor, referenceKind);
-    add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode));
+    final int data = getConstantMethodHandleSymbolData(referenceKind, isInterface);
+    int hashCode = hash(tag, owner, name, descriptor, data);
+    add(new Entry(index, tag, owner, name, descriptor, data, hashCode));
+  }
+
+  /**
+   * Returns the {@link Symbol#data} field for a CONSTANT_MethodHandle_info Symbol.
+   *
+   * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
+   *     Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
+   *     Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
+   *     Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+   * @param isInterface whether owner is an interface or not.
+   */
+  private static int getConstantMethodHandleSymbolData(
+      final int referenceKind, final boolean isInterface) {
+    if (referenceKind > Opcodes.H_PUTSTATIC && isInterface) {
+      return referenceKind << 8;
+    }
+    return referenceKind;
   }
 
   /**
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 f5384f8..917d094 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
@@ -309,7 +309,7 @@
 
     private static class ClassReaderWrapper {
         private static final Logger LOGGER = Logger.getLogger(ClassReader.class.getName());
-        private static final int WARN_VERSION = Opcodes.V23;
+        private static final int WARN_VERSION = Opcodes.V24;
         private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
 
         private final byte[] b;
diff --git a/core-server/src/main/resources/META-INF/NOTICE.markdown b/core-server/src/main/resources/META-INF/NOTICE.markdown
index 27c798d..2016cb4 100644
--- a/core-server/src/main/resources/META-INF/NOTICE.markdown
+++ b/core-server/src/main/resources/META-INF/NOTICE.markdown
@@ -36,7 +36,7 @@
 * Copyright (c) 2015-2018 Oracle and/or its affiliates. All rights reserved.

 * Copyright 2010-2013 Coda Hale and Yammer, Inc.

 

-org.objectweb.asm Version 9.7

+org.objectweb.asm Version 9.7.1

 * License: Modified BSD (https://asm.ow2.io/license.html)

 * Copyright: (c) 2000-2011 INRIA, France Telecom. All rights reserved.

 

diff --git a/etc/jenkins/Jenkinsfile_EE4J_build b/etc/jenkins/Jenkinsfile_EE4J_build
index 65a8b56..609d150 100644
--- a/etc/jenkins/Jenkinsfile_EE4J_build
+++ b/etc/jenkins/Jenkinsfile_EE4J_build
@@ -5,6 +5,10 @@
     triggers {
         pollSCM('H H * * *')
     }
+    options {
+        disableConcurrentBuilds()
+        buildDiscarder(logRotator(numToKeepStr:'15', artifactNumToKeepStr: '2' ))
+    }
     tools {
         jdk 'oracle-jdk8-latest'
         maven 'apache-maven-latest'
diff --git a/etc/jenkins/Jenkinsfile_ci_build b/etc/jenkins/Jenkinsfile_ci_build
index d933c21..9cc5b4f 100644
--- a/etc/jenkins/Jenkinsfile_ci_build
+++ b/etc/jenkins/Jenkinsfile_ci_build
@@ -3,6 +3,8 @@
 
     options {
           timeout(time: 30, activity: true, unit: 'HOURS')
+          buildDiscarder(logRotator(numToKeepStr:'15', artifactNumToKeepStr: '2' ))
+          disableConcurrentBuilds()
     }
 
     stages {
diff --git a/etc/jenkins/Jenkinsfile_master_build b/etc/jenkins/Jenkinsfile_master_build
index a4c5483..9b62947 100644
--- a/etc/jenkins/Jenkinsfile_master_build
+++ b/etc/jenkins/Jenkinsfile_master_build
@@ -5,6 +5,10 @@
     triggers {
         pollSCM('H H * * *')
     }
+    options {
+        disableConcurrentBuilds()
+        buildDiscarder(logRotator(numToKeepStr:'15', artifactNumToKeepStr: '2' ))
+    }
     tools {
         jdk 'oracle-jdk8-latest'
         maven 'apache-maven-latest'
diff --git a/examples/NOTICE.md b/examples/NOTICE.md
index 82590e4..b539cdc 100644
--- a/examples/NOTICE.md
+++ b/examples/NOTICE.md
@@ -71,7 +71,7 @@
 * Project: http://www.javassist.org/
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 
-Jackson JAX-RS Providers Version 2.17.2
+Jackson JAX-RS Providers Version 2.18.0
 * License: Apache License, 2.0
 * Project: https://github.com/FasterXML/jackson-jaxrs-providers
 * Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated.
@@ -96,7 +96,7 @@
 * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS
 * Copyright: Eric Rowell
 
-org.objectweb.asm Version 9.7
+org.objectweb.asm Version 9.7.1
 * License: Modified BSD (https://asm.ow2.io/license.html)
 * Copyright (c) 2000-2011 INRIA, France Telecom. All rights reserved.
 
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzerTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzerTest.java
index 85bfe56..9a6d8da 100644
--- a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzerTest.java
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2022, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -30,6 +30,7 @@
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Tests {@link CachedConstructorAnalyzer}.
@@ -110,7 +111,8 @@
 
         Constructor<BothAnnotatedConstructor> constructor = analyzer.getConstructor();
         assertEquals(1, constructor.getParameterCount());
-        assertEquals(Integer.class, constructor.getParameterTypes()[0]);
+        Class<?> parameterType = constructor.getParameterTypes()[0];
+        assertTrue(parameterType.equals(String.class) || parameterType.equals(Integer.class));
     }
 
     @Test
diff --git a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/CachedConstructorAnalyzerTest.java b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/CachedConstructorAnalyzerTest.java
index cc9e78a..7e105aa 100644
--- a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/CachedConstructorAnalyzerTest.java
+++ b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/CachedConstructorAnalyzerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2022, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -30,6 +30,7 @@
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Tests {@link CachedConstructorAnalyzer}.
@@ -110,7 +111,8 @@
 
         Constructor<BothAnnotatedConstructor> constructor = analyzer.getConstructor();
         assertEquals(1, constructor.getParameterCount());
-        assertEquals(Integer.class, constructor.getParameterTypes()[0]);
+        Class<?> parameterType = constructor.getParameterTypes()[0];
+        assertTrue(parameterType.equals(String.class) || parameterType.equals(Integer.class));
     }
 
     @Test
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
index a209c27..ac0b5c9 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
@@ -18,6 +18,8 @@
 
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.StreamReadConstraints;
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.core.json.PackageVersion;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.ObjectReader;
@@ -130,17 +132,22 @@
 
         if (maxStringLength != StreamReadConstraints.DEFAULT_MAX_STRING_LEN) {
             final StreamReadConstraints constraints = jsonFactory.streamReadConstraints();
-            jsonFactory.setStreamReadConstraints(
-                    StreamReadConstraints.builder()
-                            // our
-                            .maxStringLength(maxStringLength)
-                            // customers
-                            .maxDocumentLength(constraints.getMaxDocumentLength())
-                            .maxNameLength(constraints.getMaxNameLength())
-                            .maxNestingDepth(constraints.getMaxNestingDepth())
-                            .maxNumberLength(constraints.getMaxNumberLength())
-                            .build()
-            );
+            StreamReadConstraints.Builder builder = StreamReadConstraints.builder()
+                // our
+                .maxStringLength(maxStringLength)
+                // customers
+                .maxDocumentLength(constraints.getMaxDocumentLength())
+                .maxNameLength(constraints.getMaxNameLength())
+                .maxNestingDepth(constraints.getMaxNestingDepth())
+                .maxNumberLength(constraints.getMaxNumberLength());
+
+            if (PackageVersion.VERSION.getMinorVersion() >= 18) {
+                 builder.maxTokenCount(constraints.getMaxTokenCount());
+            } else {
+                LOGGER.warning(LocalizationMessages.ERROR_JACKSON_STREAMREADCONSTRAINTS_218("maxTokenCount"));
+            }
+
+            jsonFactory.setStreamReadConstraints(builder.build());
         }
     }
 }
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
index bf365bb..350be25 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
@@ -43,6 +43,7 @@
 import com.fasterxml.jackson.databind.ObjectReader;
 import com.fasterxml.jackson.databind.ObjectWriter;
 import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.util.LookupCache;
 import com.fasterxml.jackson.databind.util.LRUMap;
 import com.fasterxml.jackson.databind.type.TypeFactory;
 
@@ -186,14 +187,12 @@
     /**
      * Cache for resolved endpoint configurations when reading JSON data
      */
-    protected final LRUMap<AnnotationBundleKey, EP_CONFIG> _readers
-            = new LRUMap<AnnotationBundleKey, EP_CONFIG>(16, 120);
+    protected final LookupCache<AnnotationBundleKey, EP_CONFIG> _readers;
 
     /**
      * Cache for resolved endpoint configurations when writing JSON data
      */
-    protected final LRUMap<AnnotationBundleKey, EP_CONFIG> _writers
-            = new LRUMap<AnnotationBundleKey, EP_CONFIG>(16, 120);
+    protected final LookupCache<AnnotationBundleKey, EP_CONFIG> _writers;
 
     /*
     /**********************************************************
@@ -202,8 +201,9 @@
      */
 
     protected ProviderBase(MAPPER_CONFIG mconfig) {
-        _mapperConfig = mconfig;
-        _jaxRSFeatures = JAXRS_FEATURE_DEFAULTS;
+        this(mconfig,
+                new LRUMap<>(16, 120),
+                new LRUMap<>(16, 120));
     }
 
     /**
@@ -214,8 +214,19 @@
      */
     @Deprecated // just to denote it should NOT be directly called; will NOT be removed
     protected ProviderBase() {
-        _mapperConfig = null;
+        this(null);
+    }
+    /**
+     * @since 2.17
+     */
+    protected ProviderBase(MAPPER_CONFIG mconfig,
+            LookupCache<AnnotationBundleKey, EP_CONFIG> readerCache,
+            LookupCache<AnnotationBundleKey, EP_CONFIG> writerCache)
+    {
+        _mapperConfig = mconfig;
         _jaxRSFeatures = JAXRS_FEATURE_DEFAULTS;
+        _readers = readerCache;
+        _writers = writerCache;
     }
 
     /*
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JacksonJaxbJsonProvider.java
index eb7c072..ac207b8 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JacksonJaxbJsonProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JacksonJaxbJsonProvider.java
@@ -25,7 +25,7 @@
  */
 @Provider
 @Consumes(MediaType.WILDCARD) // NOTE: required to support "non-standard" JSON variants
-@Produces(MediaType.WILDCARD)
+@Produces({MediaType.APPLICATION_JSON, "text/json", MediaType.WILDCARD})
 public class JacksonJaxbJsonProvider extends JacksonJsonProvider {
     /**
      * Default annotation sets to use, if not explicitly defined during
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JacksonJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JacksonJsonProvider.java
index 0871ece..13f9275 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JacksonJsonProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/JacksonJsonProvider.java
@@ -52,7 +52,7 @@
  */
 @Provider
 @Consumes(MediaType.WILDCARD) // NOTE: required to support "non-standard" JSON variants
-@Produces(MediaType.WILDCARD)
+@Produces({MediaType.APPLICATION_JSON, "text/json", MediaType.WILDCARD})
 public class JacksonJsonProvider
     extends ProviderBase<JacksonJsonProvider,
             ObjectMapper,
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
index 56b1bf6..44c9073 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
@@ -11,7 +11,7 @@
  */
 public final class PackageVersion implements Versioned {
     public final static Version VERSION = VersionUtil.parseVersion(
-        "2.17.2", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider");
+        "2.18.0", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider");
 
     @Override
     public Version version() {
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/util/package-info.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/util/package-info.java
index 4ec091c..c18b433 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/util/package-info.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/util/package-info.java
@@ -1,4 +1,4 @@
 /**
  * Miscellaneous helper classes used by providers.
  */
-package com.fasterxml.jackson.jaxrs.util;
+package org.glassfish.jersey.jackson.internal.jackson.jaxrs.util;
diff --git a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
index 9440229..d893c65 100644
--- a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
+++ b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
@@ -31,7 +31,7 @@
 

 ## Third-party Content

 

-Jackson JAX-RS Providers version 2.17.2

+Jackson JAX-RS Providers version 2.18.0

 * License: Apache License, 2.0

 * Project: https://github.com/FasterXML/jackson-jaxrs-providers

 * Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated.

diff --git a/media/json-jackson/src/main/resources/org/glassfish/jersey/jackson/localization.properties b/media/json-jackson/src/main/resources/org/glassfish/jersey/jackson/localization.properties
index a9144fd..1943306 100644
--- a/media/json-jackson/src/main/resources/org/glassfish/jersey/jackson/localization.properties
+++ b/media/json-jackson/src/main/resources/org/glassfish/jersey/jackson/localization.properties
@@ -13,6 +13,6 @@
 #
 # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 #
-
 error.jackson.streamreadconstraints=Error setting StreamReadConstraints: {0}. Possibly not Jackson 2.15?
+error.jackson.streamreadconstraints218=Error setting StreamReadConstraints: {0}. Possibly not Jackson 2.18?
 error.modules.not.loaded=Jackson modules could not be loaded: {0}
\ No newline at end of file
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/StreamReadConstrainsTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/StreamReadConstrainsTest.java
index 8fa7cb9..873377c 100644
--- a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/StreamReadConstrainsTest.java
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/StreamReadConstrainsTest.java
@@ -19,7 +19,9 @@
 import com.fasterxml.jackson.annotation.JsonGetter;
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.StreamReadConstraints;
+import com.fasterxml.jackson.core.Version;
 import com.fasterxml.jackson.core.exc.StreamConstraintsException;
+import com.fasterxml.jackson.core.json.PackageVersion;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -130,7 +132,27 @@
         }
     }
 
+    @Test
+    void testMatchingVersion() {
+        final Version coreVersion = PackageVersion.VERSION;
+        final Version jerseyVersion = org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.PackageVersion.VERSION;
 
+        StringBuilder message = new StringBuilder();
+        message.append("Dependency Jackson Version is ")
+                .append(coreVersion.getMajorVersion())
+                .append(".")
+                .append(coreVersion.getMinorVersion());
+        message.append("\n Repackaged Jackson Version is ")
+                .append(jerseyVersion.getMajorVersion())
+                .append(".")
+                .append(jerseyVersion.getMinorVersion());
+
+        Assertions.assertEquals(coreVersion.getMajorVersion(), jerseyVersion.getMajorVersion(), message.toString());
+        Assertions.assertEquals(coreVersion.getMinorVersion(), jerseyVersion.getMinorVersion(), message.toString());
+        Assertions.assertEquals(coreVersion.getMajorVersion(), 2,
+                "update " + DefaultJacksonJaxbJsonProvider.class.getName()
+                        + " updateFactoryConstraints method to support version " + coreVersion.getMajorVersion());
+    }
 
     @Test
     void testStreamReadConstraintsMethods() {
@@ -138,7 +160,9 @@
                 + " Please update the code in " + DefaultJacksonJaxbJsonProvider.class.getName()
                 + " updateFactoryConstraints method";
         Method[] method = StreamReadConstraints.Builder.class.getDeclaredMethods();
-        Assertions.assertEquals(6, method.length, message); // five setMax... + build() methods
+        // 2.17 : five setMax... + build() methods
+        // 2.18 : six setMax... + build() methods
+        Assertions.assertEquals(7, method.length, message);
     }
 
     @Path("len")
diff --git a/pom.xml b/pom.xml
index 470eba2..dcf006d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2201,7 +2201,7 @@
         <arquillian.weld.version>3.0.1.Final</arquillian.weld.version> <!-- 3.0.2.Final fails microprofile TCK tests -->
         <!-- asm is now source integrated - keeping this property to see the version -->
         <!-- see core-server/src/main/java/jersey/repackaged/asm/.. -->
-        <asm.version>9.7</asm.version>
+        <asm.version>9.7.1</asm.version>
         <!--required for spring (ext) modules integration -->
         <aspectj.weaver.version>1.9.22.1</aspectj.weaver.version>
         <!--        <bnd.plugin.version>2.3.6</bnd.plugin.version>-->
@@ -2245,7 +2245,7 @@
         <hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[2.5,4)"</hk2.jvnet.osgi.version>
         <httpclient.version>4.5.14</httpclient.version>
         <httpclient5.version>5.3.1</httpclient5.version>
-        <jackson.version>2.17.2</jackson.version>
+        <jackson.version>2.18.0</jackson.version>
         <javassist.version>3.30.2-GA</javassist.version>
         <jboss.logging.8.version>3.4.3.Final</jboss.logging.8.version>
         <jersey1.version>1.19.3</jersey1.version>
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java
index 70ee14d..e068287 100644
--- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java
+++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -35,6 +35,9 @@
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
 
 public class NoJAXBNoWadlTest extends JerseyTest {
 
@@ -72,7 +75,9 @@
 
         try (Response r = target("dummy").request(MediaTypes.WADL_TYPE).options()) {
             String headers = r.getHeaderString(HttpHeaders.ALLOW);
-            Assertions.assertEquals("OPTIONS,PUT", headers);
+            List<String> methods = Arrays.asList(headers.split(","));
+            Collections.sort(methods);
+            Assertions.assertEquals(Arrays.asList("OPTIONS", "PUT"), methods);
         }
         System.out.println(readableStream.toString());
         Assertions.assertTrue(
diff --git a/tools/jersey-release-notes-maven-plugin/pom.xml b/tools/jersey-release-notes-maven-plugin/pom.xml
index fa51932..004460b 100644
--- a/tools/jersey-release-notes-maven-plugin/pom.xml
+++ b/tools/jersey-release-notes-maven-plugin/pom.xml
@@ -74,7 +74,7 @@
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
-            <version>2.11.0</version>
+            <version>2.14.0</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>