This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-jms.git


The following commit(s) were added to refs/heads/main by this push:
     new 78781ea6 QPIDJMS-632: update to proton-j 0.35.0
78781ea6 is described below

commit 78781ea6d867ebb4185c8f786f6a873885983343
Author: Robbie Gemmell <[email protected]>
AuthorDate: Fri Jul 31 19:02:32 2026 +0100

    QPIDJMS-632: update to proton-j 0.35.0
    
    add options to configure new settings
---
 pom.xml                                            |   2 +-
 .../qpid/jms/provider/amqp/AmqpConnection.java     |   8 +
 .../qpid/jms/provider/amqp/AmqpConsumer.java       |   8 +
 .../qpid/jms/provider/amqp/AmqpProvider.java       |  56 +++++++
 .../qpid/jms/provider/amqp/message/AmqpCodec.java  |  10 +-
 .../amqp/message/AmqpTypedObjectDelegate.java      |   4 +-
 .../jms/integration/ConnectionIntegrationTest.java |  16 +-
 .../jms/integration/ConsumerIntegrationTest.java   | 185 +++++++++++++++++++++
 .../MultiTransferFrameMessageIntegrationTest.java  |  61 +++++++
 .../integration/ObjectMessageIntegrationTest.java  |   4 +
 .../jms/provider/amqp/AmqpProviderFactoryTest.java |  36 ++++
 .../qpid/jms/provider/amqp/AmqpProviderTest.java   |  52 ++++++
 .../jms/provider/amqp/message/AmqpCodecTest.java   | 131 ++++++++++++++-
 .../amqp/message/AmqpJmsMessageTypesTestCase.java  |   8 +
 .../qpid/jms/test/testpeer/TestAmqpPeer.java       |  12 +-
 15 files changed, 578 insertions(+), 15 deletions(-)

diff --git a/pom.xml b/pom.xml
index e90f33f1..2ad68904 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,7 +36,7 @@
 
   <properties>
     <!-- Dependency Versions for this Project -->
-    <proton-version>0.34.1</proton-version>
+    <proton-version>0.35.0</proton-version>
     <netty-version>4.1.137.Final</netty-version>
     <slf4j-version>2.0.18</slf4j-version>
     <jakarta.jms-api-version>3.1.0</jakarta.jms-api-version>
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
index 6bdca103..ac7025cf 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
@@ -233,6 +233,14 @@ public class AmqpConnection extends 
AmqpAbstractResource<JmsConnectionInfo, Conn
         return getProvider().getAnonymousFallbackCacheTimeout();
     }
 
+    public int getMaxDecodeDepth() {
+        return getProvider().getMaxDecodeDepth();
+    }
+
+    public int getZeroWidthArrayElementLimit() {
+        return getProvider().getZeroWidthArrayElementLimit();
+    }
+
     /**
      * @return the AMQP based JmsMessageFactory for this Connection.
      */
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConsumer.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConsumer.java
index 696a6984..163e2d4d 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConsumer.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConsumer.java
@@ -637,6 +637,14 @@ public class AmqpConsumer extends 
AmqpAbstractResource<JmsConsumerInfo, Receiver
         return session.getProvider().getDrainTimeout();
     }
 
+    public int getMaxDecodeDepth() {
+        return session.getProvider().getMaxDecodeDepth();
+    }
+
+    public int getZeroWidthArrayElementLimit() {
+        return session.getProvider().getZeroWidthArrayElementLimit();
+    }
+
     @Override
     public String toString() {
         return "AmqpConsumer { " + getResourceInfo().getId() + " }";
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
index d7f2f354..cd47e110 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
@@ -124,6 +124,9 @@ public class AmqpProvider implements Provider, 
TransportListener , AmqpResourceP
     private static final int DEFAULT_MAX_WRITE_BYTES_BEFORE_FLUSH = 128 * 1024;
     private static final int DEFAULT_ANONYMOUS_FALLBACK_CACHE_TIMEOUT = 30000;
     private static final int DEFAULT_ANONYMOUS_FALLBACK_CACHE_SIZE = 1;
+    private static final int DEFAULT_MAX_TRANSFERS_PER_DELIVERY = 65535;
+    private static final int DEFAULT_MAX_DECODE_DEPTH = 32;
+    private static final int DEFAULT_ZERO_WIDTH_ARRAY_ELEMENT_LIMIT = 0;
 
     private volatile ProviderListener listener;
     private volatile AmqpConnection connection;
@@ -144,6 +147,9 @@ public class AmqpProvider implements Provider, 
TransportListener , AmqpResourceP
     private int maxWriteBytesBeforeFlush = 
DEFAULT_MAX_WRITE_BYTES_BEFORE_FLUSH;
     private int anonymousFallbackCacheTimeout = 
DEFAULT_ANONYMOUS_FALLBACK_CACHE_TIMEOUT;
     private int anonymousFallbackCacheSize = 
DEFAULT_ANONYMOUS_FALLBACK_CACHE_SIZE;
+    private int maxTransfersPerDelivery = DEFAULT_MAX_TRANSFERS_PER_DELIVERY;
+    private int maxDecodeDepth = DEFAULT_MAX_DECODE_DEPTH;
+    private int zeroWidthArrayElementLimit = 
DEFAULT_ZERO_WIDTH_ARRAY_ELEMENT_LIMIT;
 
     private boolean allowNonSecureRedirects;
 
@@ -246,6 +252,10 @@ public class AmqpProvider implements Provider, 
TransportListener , AmqpResourceP
                     
protonTransport.setOutboundFrameSizeLimit(getMaxFrameSize());
                 }
 
+                if (getMaxTransfersPerDelivery() > 0) {
+                    
protonTransport.setMaxTransfersPerDelivery(getMaxTransfersPerDelivery());
+                }
+
                 protonTransport.setChannelMax(getChannelMax());
                 protonTransport.setIdleTimeout(idleTimeout);
                 protonTransport.bind(protonConnection);
@@ -1389,6 +1399,52 @@ public class AmqpProvider implements Provider, 
TransportListener , AmqpResourceP
         this.maxFrameSize = maxFrameSize;
     }
 
+    public int getZeroWidthArrayElementLimit() {
+        return zeroWidthArrayElementLimit;
+    }
+
+    /**
+     * Configures the maximum number of array elements allowed while decoding 
arrays
+     * of zero-width elements (ulong0, uint0, list0, boolean-true, 
boolean-false, null)
+     * before a decode exception.
+     *
+     * Default is 0, meaning only the empty array is permitted.
+     *
+     * @param zeroWidthArrayElementLimit The configured max zero-width 
elements allowed.
+     */
+    public void setZeroWidthArrayElementLimit(int zeroWidthArrayElementLimit) {
+        this.zeroWidthArrayElementLimit = zeroWidthArrayElementLimit;
+    }
+
+    public int getMaxDecodeDepth() {
+        return maxDecodeDepth;
+    }
+
+    /**
+     * Configures the maximum decode depth allowed before error when decoding 
Maps, Lists,
+     * Arrays, and certain related DescribedTypes from an encoded payload. 
Default is 32.
+     *
+     * @param maxDecodeDepth The configured max decode depth allowed.
+     */
+    public void setMaxDecodeDepth(int maxDecodeDepth) {
+        this.maxDecodeDepth = maxDecodeDepth;
+    }
+
+    public int getMaxTransfersPerDelivery() {
+        return maxTransfersPerDelivery;
+    }
+
+    /**
+     * Sets the maximum number of transfer frames that can be used for an 
incoming delivery.
+     *
+     * A value of -1 indicates that the proton default should be used.
+     *
+     * @param maxTransfersPerDelivery the maximum number of transfer frames 
per incoming delivery.
+     */
+    public void setMaxTransfersPerDelivery(int maxTransfersPerDelivery) {
+        this.maxTransfersPerDelivery = maxTransfersPerDelivery;
+    }
+
     public long getSessionOutgoingWindow() {
         return sessionOutoingWindow;
     }
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpCodec.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpCodec.java
index 7a75d25f..0750335a 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpCodec.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpCodec.java
@@ -36,6 +36,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
 import org.apache.qpid.jms.provider.amqp.AmqpConsumer;
 import org.apache.qpid.jms.util.ContentTypeSupport;
 import org.apache.qpid.jms.util.InvalidContentTypeException;
@@ -130,18 +131,23 @@ public final class AmqpCodec {
     /**
      * Given an encoded AMQP Section, decode the value previously written 
there.
      *
+     * @param connection
+     *      the connection this is being done for
      * @param encoded
      *      the AMQP Section value to decode.
      *
      * @return a Section object read from its encoded form.
      */
-    public static Section decode(ByteBuf encoded) {
+    public static Section decode(AmqpConnection connection, ByteBuf encoded) {
         if (encoded == null || !encoded.isReadable()) {
             return null;
         }
 
         DecoderImpl decoder = TLS_CODEC.get().decoder;
         decoder.setByteBuffer(encoded.nioBuffer());
+        decoder.setMaxDecodeDepth(connection.getMaxDecodeDepth());
+        
decoder.setZeroWidthArrayElementLimit(connection.getZeroWidthArrayElementLimit());
+
         Section result = (Section) decoder.readObject();
         decoder.setByteBuffer(null);
         encoded.resetReaderIndex();
@@ -285,6 +291,8 @@ public final class AmqpCodec {
 
         DecoderImpl decoder = getDecoder();
         decoder.setBuffer(messageBytes);
+        decoder.setMaxDecodeDepth(consumer.getMaxDecodeDepth());
+        
decoder.setZeroWidthArrayElementLimit(consumer.getZeroWidthArrayElementLimit());
 
         Header header = null;
         DeliveryAnnotations deliveryAnnotations = null;
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
index 88b7b9dd..88fee9fb 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
@@ -60,7 +60,7 @@ public class AmqpTypedObjectDelegate implements 
AmqpObjectTypeDelegate {
         Section body = null;
 
         if (encodedBody != null) {
-            body = AmqpCodec.decode(encodedBody);
+            body = AmqpCodec.decode(parent.getConnection(), encodedBody);
         }
 
         if (body == null) {
@@ -93,7 +93,7 @@ public class AmqpTypedObjectDelegate implements 
AmqpObjectTypeDelegate {
             // and decoding the value. Save the bytes for subsequent getObject 
and
             // copyInto calls to use.
             encodedBody = AmqpCodec.encode(new AmqpValue(value));
-            Section decodedBody = AmqpCodec.decode(encodedBody);
+            Section decodedBody = AmqpCodec.decode(parent.getConnection(), 
encodedBody);
 
             // This step requires a heavy-weight operation of both encoding 
and decoding the
             // incoming body value in order to create a copy such that changes 
to the original
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConnectionIntegrationTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConnectionIntegrationTest.java
index cc5573be..7b54c9b8 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConnectionIntegrationTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConnectionIntegrationTest.java
@@ -407,22 +407,28 @@ public class ConnectionIntegrationTest extends 
QpidJmsTestCase {
     @Timeout(20)
     public void testMaxFrameSizeOptionCommunicatedInOpen() throws Exception {
         int frameSize = 39215;
-        doMaxFrameSizeOptionTestImpl(frameSize, 
UnsignedInteger.valueOf(frameSize));
+        doMaxFrameSizeOptionTestImpl("&amqp.maxFrameSize=" + frameSize, 
UnsignedInteger.valueOf(frameSize));
     }
 
     @Test
     @Timeout(20)
-    public void testMaxFrameSizeOptionCommunicatedInOpenDefault() throws 
Exception {
-        doMaxFrameSizeOptionTestImpl(-1, UnsignedInteger.MAX_VALUE);
+    public void testMaxFrameSizeOptionCommunicatedInOpenProtonDefault() throws 
Exception {
+        doMaxFrameSizeOptionTestImpl("&amqp.maxFrameSize=-1", 
UnsignedInteger.valueOf(65535));
     }
 
-    private void doMaxFrameSizeOptionTestImpl(int uriOption, UnsignedInteger 
transmittedValue) throws JMSException, InterruptedException, Exception, 
IOException {
+    @Test
+    @Timeout(20)
+    public void testMaxFrameSizeCommunicatedInOpenDefault() throws Exception {
+        doMaxFrameSizeOptionTestImpl("", UnsignedInteger.valueOf(1 * 1024 * 
1024));
+    }
+
+    private void doMaxFrameSizeOptionTestImpl(String uriOption, 
UnsignedInteger transmittedValue) throws JMSException, InterruptedException, 
Exception, IOException {
         try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
             testPeer.expectSaslLayerDisabledConnect(equalTo(transmittedValue));
             // Each connection creates a session for managing temporary 
destinations etc
             testPeer.expectBegin();
 
-            String uri = "amqp://localhost:" + testPeer.getServerPort() + 
"?amqp.saslLayer=false&amqp.maxFrameSize=" + uriOption;
+            String uri = "amqp://localhost:" + testPeer.getServerPort() + 
"?amqp.saslLayer=false" +  uriOption;
             ConnectionFactory factory = new JmsConnectionFactory(uri);
             Connection connection = factory.createConnection();
             connection.start();
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConsumerIntegrationTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConsumerIntegrationTest.java
index 9f91191b..65940563 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConsumerIntegrationTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConsumerIntegrationTest.java
@@ -20,6 +20,7 @@ package org.apache.qpid.jms.integration;
 
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -28,8 +29,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -44,6 +47,7 @@ import jakarta.jms.Message;
 import jakarta.jms.MessageConsumer;
 import jakarta.jms.MessageListener;
 import jakarta.jms.MessageProducer;
+import jakarta.jms.ObjectMessage;
 import jakarta.jms.Queue;
 import jakarta.jms.Session;
 import jakarta.jms.TextMessage;
@@ -55,6 +59,7 @@ import org.apache.qpid.jms.JmsDefaultConnectionListener;
 import org.apache.qpid.jms.JmsOperationTimedOutException;
 import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
 import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
+import org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport;
 import org.apache.qpid.jms.test.QpidJmsTestCase;
 import org.apache.qpid.jms.test.Wait;
 import org.apache.qpid.jms.test.testpeer.AmqpPeerRunnable;
@@ -63,6 +68,7 @@ import org.apache.qpid.jms.test.testpeer.basictypes.AmqpError;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.AmqpValueDescribedType;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.DataDescribedType;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.HeaderDescribedType;
+import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.MessageAnnotationsDescribedType;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.PropertiesDescribedType;
 import org.apache.qpid.jms.test.testpeer.matchers.AcceptedMatcher;
 import org.apache.qpid.jms.test.testpeer.matchers.ModifiedMatcher;
@@ -2563,4 +2569,183 @@ public class ConsumerIntegrationTest extends 
QpidJmsTestCase {
             testPeer.waitForAllHandlersToComplete(2000);
         }
     }
+
+    @Test
+    @Timeout(20)
+    public void testMessageDecodeDepthLimit() throws Exception {
+        // check it allows without option
+        doReceiveMessageWithDepthLimitTestImpl(32, null, false);
+        // check it blocks with option set
+        doReceiveMessageWithDepthLimitTestImpl(32, 10, true);
+
+        // check it blocks without option
+        doReceiveMessageWithDepthLimitTestImpl(33, null, true);
+        // check it allows with option set
+        doReceiveMessageWithDepthLimitTestImpl(33, 33, false);
+    }
+
+    private void doReceiveMessageWithDepthLimitTestImpl(final int depth, 
Integer depthLimitOption, boolean expectDeliveryFailure) throws Exception {
+        String optionsString = "?jms.receiveLocalOnly=true";
+        if(depthLimitOption != null) {
+            optionsString += "&amqp.maxDecodeDepth=" + depthLimitOption;
+        }
+
+        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
+            Connection connection = testFixture.establishConnecton(testPeer, 
optionsString);
+            connection.start();
+
+            testPeer.expectBegin();
+
+            Session session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            MessageAnnotationsDescribedType msgAnnotations = new 
MessageAnnotationsDescribedType();
+            
msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.JMS_MSG_TYPE.toString(),
 AmqpMessageSupport.JMS_OBJECT_MESSAGE);
+
+            List<Object> lists = prepareNestedLists(depth);
+            DescribedType amqpValueContent = new AmqpValueDescribedType(lists);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, msgAnnotations, 
null, null, amqpValueContent);
+            if (expectDeliveryFailure) {
+                testPeer.expectDisposition(true, new 
ModifiedMatcher().withDeliveryFailed(equalTo(true)).withUndeliverableHere(equalTo(true)));
+            } else {
+                testPeer.expectDispositionThatIsAcceptedAndSettled();
+            }
+            testPeer.expectClose();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+
+            Message receivedMessage;
+            if (expectDeliveryFailure) {
+                receivedMessage = messageConsumer.receive(250);
+
+                assertNull(receivedMessage);
+            } else {
+                receivedMessage = messageConsumer.receive(3000);
+
+                assertNotNull(receivedMessage);
+                assertTrue(receivedMessage instanceof ObjectMessage, "Expected 
ObjectMessage instance, but got: " + receivedMessage.getClass().getName());
+                ObjectMessage objectMessage = (ObjectMessage)receivedMessage;
+
+                Object object = objectMessage.getObject();
+                assertNotNull(object, "Expected object but got null");
+                assertEquals(lists, object, "Message body object was not as 
expected");
+            }
+
+            connection.close();
+
+            testPeer.waitForAllHandlersToComplete(3000);
+        }
+    }
+
+    private static List<Object> prepareNestedLists(final int depth) {
+        final List<Object> body = new ArrayList<>();
+
+        List<Object> current = body;
+        for (int i = 1; i < depth; ++i) {
+            final List<Object> next = new ArrayList<>();
+
+            current.add(next);
+            current = next;
+        }
+
+        return body;
+    }
+
+    @Test
+    @Timeout(20)
+    public void testMessageZeroWidthArrayElementLimit() throws Exception {
+        // check it allows empty without option
+        doReceiveMessageWithZeroWidthArrayElementLimitTestImpl(0, null, false);
+        // check it blocks non-empty without option
+        doReceiveMessageWithZeroWidthArrayElementLimitTestImpl(10, null, true);
+        // check it blocks non-empty with option set lower
+        doReceiveMessageWithZeroWidthArrayElementLimitTestImpl(10, 9, true);
+        // check it allows non-empty with option set
+        doReceiveMessageWithZeroWidthArrayElementLimitTestImpl(10, 10, false);
+    }
+
+    private void doReceiveMessageWithZeroWidthArrayElementLimitTestImpl(final 
int elements, Integer elementLmitOption, boolean expectDeliveryFailure) throws 
Exception {
+        String optionsString = "?jms.receiveLocalOnly=true";
+        if (elementLmitOption != null) {
+            optionsString += "&amqp.zeroWidthArrayElementLimit=" + 
elementLmitOption;
+        }
+
+        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
+            Connection connection = testFixture.establishConnecton(testPeer, 
optionsString);
+            connection.start();
+
+            testPeer.expectBegin();
+
+            Session session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            MessageAnnotationsDescribedType msgAnnotations = new 
MessageAnnotationsDescribedType();
+            
msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.JMS_MSG_TYPE.toString(),
 AmqpMessageSupport.JMS_OBJECT_MESSAGE);
+
+            Binary payload = 
prepareMessageEncodingWithArrayOfZeroWidthElements(elements);
+
+            testPeer.expectReceiverAttach();
+            // Expect that once receive is called, it flows credit.
+            testPeer.expectLinkFlow(false, 
equalTo(UnsignedInteger.valueOf(1000)));
+            // Give it an initial (ie. more=true) transfer frame with header 
only.
+            testPeer.sendTransferToLastOpenedLinkOnLastOpenedSession(payload, 
1, "delivery1", false, 0);
+
+            if (expectDeliveryFailure) {
+                testPeer.expectDisposition(true, new 
ModifiedMatcher().withDeliveryFailed(equalTo(true)).withUndeliverableHere(equalTo(true)));
+            } else {
+                testPeer.expectDispositionThatIsAcceptedAndSettled();
+            }
+            testPeer.expectClose();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+
+            Message receivedMessage;
+            if (expectDeliveryFailure) {
+                receivedMessage = messageConsumer.receive(250);
+
+                assertNull(receivedMessage);
+            } else {
+                receivedMessage = messageConsumer.receive(3000);
+
+                assertNotNull(receivedMessage);
+                assertTrue(receivedMessage instanceof ObjectMessage, "Expected 
ObjectMessage instance, but got: " + receivedMessage.getClass().getName());
+                ObjectMessage objectMessage = (ObjectMessage)receivedMessage;
+
+                Object object = objectMessage.getObject();
+                assertNotNull(object, "Expected object but got null");
+
+                assertTrue(object.getClass().isArray());
+                assertEquals(boolean.class, 
object.getClass().getComponentType());
+                final boolean[] expected = new boolean[elements];
+                Arrays.fill(expected, true);
+
+                assertArrayEquals(expected, (boolean[]) object, "Message body 
object was not as expected");
+            }
+
+            connection.close();
+
+            testPeer.waitForAllHandlersToComplete(3000);
+        }
+    }
+
+    private Binary prepareMessageEncodingWithArrayOfZeroWidthElements(int 
elementCount) {
+        assertTrue(elementCount >= 0);
+        assertTrue(elementCount <= 255);
+
+        ByteBuffer buf = ByteBuffer.allocate(7);
+        buf.put((byte) 0x00); // DescribedType
+        buf.put((byte) 0x53); // small-ulong constructor
+        buf.put((byte) 0x77); // amqp-value ulong descriptor
+
+        buf.put((byte) 0xE0); // 'array8' type descriptor code
+        buf.put((byte) (1 + 1)); // 1 byte count + 1 byte type
+        buf.put((byte) elementCount); // count
+        buf.put((byte) 0x41); // boolean-true
+
+        Binary payload = new Binary(buf.array());
+
+        return payload;
+    }
 }
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/MultiTransferFrameMessageIntegrationTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/MultiTransferFrameMessageIntegrationTest.java
index 7d6b2156..4aa3a63a 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/MultiTransferFrameMessageIntegrationTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/MultiTransferFrameMessageIntegrationTest.java
@@ -18,6 +18,9 @@
  */
 package org.apache.qpid.jms.integration;
 
+import static 
org.apache.qpid.proton.amqp.transport.LinkError.TRANSFER_LIMIT_EXCEEDED;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.fail;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -34,12 +37,14 @@ import jakarta.jms.MessageConsumer;
 import jakarta.jms.Queue;
 import jakarta.jms.Session;
 
+import org.apache.qpid.jms.exceptions.JmsConnectionFailedException;
 import org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport;
 import org.apache.qpid.jms.test.QpidJmsTestCase;
 import org.apache.qpid.jms.test.testpeer.TestAmqpPeer;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.DataDescribedType;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.MessageAnnotationsDescribedType;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.PropertiesDescribedType;
+import org.apache.qpid.jms.test.testpeer.matchers.ErrorMatcher;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.DescribedType;
 import org.apache.qpid.proton.amqp.UnsignedInteger;
@@ -127,4 +132,60 @@ public class MultiTransferFrameMessageIntegrationTest 
extends QpidJmsTestCase {
 
         return payload;
     }
+
+    @Test
+    @Timeout(20)
+    public void testExceedsMaxTransfersPerDelivery() throws Exception {
+        doExceedsMaxTransfersPerDeliveryTestImpl(100_000, (11 * 100_000) - 
1000, false, 10);
+        doExceedsMaxTransfersPerDeliveryTestImpl(100_000, (10 * 100_000) - 
1000, true, 10);
+    }
+
+    private void doExceedsMaxTransfersPerDeliveryTestImpl(int 
msgPayloadPerFrame, int payloadSizeInBytes, boolean sendLastEmptyTransfer, int 
option) throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
+            Connection connection = testFixture.establishConnecton(testPeer, 
"?jms.prefetchPolicy.all=0&amqp.maxTransfersPerDelivery=" + option);
+            connection.start();
+
+            testPeer.expectBegin();
+
+            Session session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            PropertiesDescribedType properties = new PropertiesDescribedType();
+            
properties.setContentType(AmqpMessageSupport.OCTET_STREAM_CONTENT_TYPE);
+
+            MessageAnnotationsDescribedType msgAnnotations = new 
MessageAnnotationsDescribedType();
+            
msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.JMS_MSG_TYPE.toString(),
 AmqpMessageSupport.JMS_BYTES_MESSAGE);
+
+            final byte[] expectedContent = 
createMessageBodyContent(payloadSizeInBytes, 0);
+            DescribedType dataContent = new DataDescribedType(new 
Binary(expectedContent));
+
+            testPeer.expectReceiverAttach();
+
+            testPeer.expectLinkFlowAndSendBackMessages(null, msgAnnotations, 
properties, null, dataContent, 1,
+                                                      true, false, 
Matchers.equalTo(UnsignedInteger.valueOf(1)), 1,
+                                                      false, false, 
msgPayloadPerFrame, sendLastEmptyTransfer);
+
+            ErrorMatcher errorMatcher = new ErrorMatcher()
+                    .withCondition(equalTo(TRANSFER_LIMIT_EXCEEDED))
+                    .withDescription(equalTo("Max transfers per delivery limit 
exceeded"));
+
+            testPeer.expectClose(errorMatcher, false);
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+
+            try {
+                messageConsumer.receiveNoWait();
+                fail("Expected exception");
+            } catch (JmsConnectionFailedException e) {
+                final String message = e.getMessage();
+                assertNotNull(message);
+                assertTrue(message.contains("Max transfers per delivery limit 
exceeded"));
+                assertTrue(message.contains("transfer-limit-exceeded"));
+            }
+
+            connection.close();
+
+            testPeer.waitForAllHandlersToComplete(3000);
+        }
+    }
 }
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
index b5036dc3..87d42730 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
@@ -31,7 +31,9 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -43,6 +45,7 @@ import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.AmqpValueDescri
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.DataDescribedType;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.MessageAnnotationsDescribedType;
 import 
org.apache.qpid.jms.test.testpeer.describedtypes.sections.PropertiesDescribedType;
+import org.apache.qpid.jms.test.testpeer.matchers.ModifiedMatcher;
 import 
org.apache.qpid.jms.test.testpeer.matchers.sections.MessageAnnotationsSectionMatcher;
 import 
org.apache.qpid.jms.test.testpeer.matchers.sections.MessageHeaderSectionMatcher;
 import 
org.apache.qpid.jms.test.testpeer.matchers.sections.MessagePropertiesSectionMatcher;
@@ -52,6 +55,7 @@ import 
org.apache.qpid.jms.test.testpeer.matchers.types.EncodedDataMatcher;
 import org.apache.qpid.jms.util.SimplePojo;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.messaging.AmqpValue;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
 import org.slf4j.Logger;
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/AmqpProviderFactoryTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/AmqpProviderFactoryTest.java
index 1b40c26d..9791cf00 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/AmqpProviderFactoryTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/AmqpProviderFactoryTest.java
@@ -158,4 +158,40 @@ public class AmqpProviderFactoryTest extends 
QpidJmsTestCase {
 
         assertEquals("v+host", amqpProvider.getVhost());
     }
+
+    @Test
+    @Timeout(20)
+    public void testCreateProviderAppliesMaxTransfersURIOption() throws 
IOException, Exception {
+        int transfers = 42798;
+        Provider provider = AmqpProviderFactory.create(new 
URI(peerURI.toString() + "?amqp.maxTransfersPerDelivery=" + transfers));
+        assertNotNull(provider);
+        assertTrue(provider instanceof AmqpProvider);
+        AmqpProvider amqpProvider = (AmqpProvider) provider;
+
+        assertEquals(transfers, amqpProvider.getMaxTransfersPerDelivery(), 
"maxTransfersPerDelivery option was not applied");
+    }
+
+    @Test
+    @Timeout(20)
+    public void testCreateProviderAppliesMaxDecodeDepthURIOption() throws 
IOException, Exception {
+        int depth = 17;
+        Provider provider = AmqpProviderFactory.create(new 
URI(peerURI.toString() + "?amqp.maxDecodeDepth=" + depth));
+        assertNotNull(provider);
+        assertTrue(provider instanceof AmqpProvider);
+        AmqpProvider amqpProvider = (AmqpProvider) provider;
+
+        assertEquals(depth, amqpProvider.getMaxDecodeDepth(), "maxDecodeDepth 
option was not applied");
+    }
+
+    @Test
+    @Timeout(20)
+    public void testCreateProviderAppliesZeroWidthArrayElementLimitURIOption() 
throws IOException, Exception {
+        int elements = 24;
+        Provider provider = AmqpProviderFactory.create(new 
URI(peerURI.toString() + "?amqp.zeroWidthArrayElementLimit=" + elements));
+        assertNotNull(provider);
+        assertTrue(provider instanceof AmqpProvider);
+        AmqpProvider amqpProvider = (AmqpProvider) provider;
+
+        assertEquals(elements, amqpProvider.getZeroWidthArrayElementLimit(), 
"zeroWidthArrayElementLimit option was not applied");
+    }
 }
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/AmqpProviderTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/AmqpProviderTest.java
index d00bfa13..f2ecd20c 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/AmqpProviderTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/AmqpProviderTest.java
@@ -271,6 +271,58 @@ public class AmqpProviderTest extends QpidJmsTestCase {
         }
     }
 
+    @Test
+    @Timeout(20)
+    public void testSetMaxTransfersPerDelivery() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer()) {
+            testPeer.expectSaslAnonymous();
+
+            provider = new 
AmqpProviderFactory().createProvider(getPeerURI(testPeer));
+
+            TransportImpl transport = (TransportImpl) 
provider.getProtonTransport();
+
+            final int NEW_MAX = 500;
+
+            provider.setMaxTransfersPerDelivery(NEW_MAX);
+            provider.connect(connectionInfo);
+
+            assertEquals(NEW_MAX, transport.getMaxTransfersPerDelivery());
+
+            testPeer.expectOpen();
+            testPeer.expectClose();
+
+            provider.close();
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    @Test
+    @Timeout(20)
+    public void testSkipSetMaxTransfersPerDelivery() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer()) {
+            testPeer.expectSaslAnonymous();
+
+            provider = new 
AmqpProviderFactory().createProvider(getPeerURI(testPeer));
+
+            TransportImpl transport = (TransportImpl) 
provider.getProtonTransport();
+
+            final int RECORDED_MAX = transport.getMaxTransfersPerDelivery();
+
+            provider.setMaxTransfersPerDelivery(-1);
+            provider.connect(connectionInfo);
+
+            assertEquals(RECORDED_MAX, transport.getMaxTransfersPerDelivery());
+
+            testPeer.expectOpen();
+            testPeer.expectClose();
+
+            provider.close();
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
     @Test
     @Timeout(20)
     public void testStartThrowsIfNoListenerSet() throws Exception {
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpCodecTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpCodecTest.java
index d86e7110..7da0d80b 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpCodecTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpCodecTest.java
@@ -21,17 +21,22 @@
 package org.apache.qpid.jms.provider.amqp.message;
 
 import static 
org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.encodeMessage;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.IOException;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -64,6 +69,8 @@ import org.apache.qpid.proton.amqp.messaging.AmqpValue;
 import org.apache.qpid.proton.amqp.messaging.Data;
 import org.apache.qpid.proton.amqp.messaging.Header;
 import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
+import org.apache.qpid.proton.codec.DecodeException;
+import org.apache.qpid.proton.codec.ReadableBuffer.ByteBufferReader;
 import org.apache.qpid.proton.message.Message;
 import org.apache.qpid.proton.message.impl.MessageImpl;
 import org.junit.jupiter.api.BeforeEach;
@@ -75,6 +82,9 @@ import io.netty.buffer.ByteBuf;
 
 public class AmqpCodecTest extends QpidJmsTestCase {
 
+    private static final int MAX_DECODE_DEPTH = 32;
+    private static final int ZERO_WIDTH_ARRAY_ELEMENTS_LIMIT = 0;
+
     private AmqpConsumer mockConsumer;
     private AmqpConnection mockConnection;
 
@@ -85,8 +95,13 @@ public class AmqpCodecTest extends QpidJmsTestCase {
 
         JmsConsumerId consumerId = new JmsConsumerId("ID:MOCK:1", 1, 1);
         mockConnection = Mockito.mock(AmqpConnection.class);
+        
Mockito.when(mockConnection.getMaxDecodeDepth()).thenReturn(MAX_DECODE_DEPTH);
+        
Mockito.when(mockConnection.getZeroWidthArrayElementLimit()).thenReturn(ZERO_WIDTH_ARRAY_ELEMENTS_LIMIT);
         mockConsumer = Mockito.mock(AmqpConsumer.class);
         Mockito.when(mockConsumer.getResourceInfo()).thenReturn(new 
JmsConsumerInfo(consumerId, null));
+        Mockito.when(mockConsumer.getConnection()).thenReturn(mockConnection);
+        
Mockito.when(mockConsumer.getMaxDecodeDepth()).thenReturn(MAX_DECODE_DEPTH);
+        
Mockito.when(mockConsumer.getZeroWidthArrayElementLimit()).thenReturn(ZERO_WIDTH_ARRAY_ELEMENTS_LIMIT);
     }
 
     //----- AmqpHeader encode and decode 
-------------------------------------//
@@ -96,7 +111,7 @@ public class AmqpCodecTest extends QpidJmsTestCase {
         Header empty = new Header();
 
         ByteBuf encoded = AmqpCodec.encode(empty);
-        Header decoded = (Header) AmqpCodec.decode(encoded);
+        Header decoded = (Header) AmqpCodec.decode(mockConnection, encoded);
 
         assertNotNull(decoded);
 
@@ -115,7 +130,7 @@ public class AmqpCodecTest extends QpidJmsTestCase {
         header.setDurable(true);
 
         ByteBuf encoded = AmqpCodec.encode(header.getHeader());
-        AmqpHeader decoded = new AmqpHeader((Header) 
AmqpCodec.decode(encoded));
+        AmqpHeader decoded = new AmqpHeader((Header) 
AmqpCodec.decode(mockConnection, encoded));
 
         assertTrue(decoded.isDurable());
         assertEquals(4, decoded.getPriority());
@@ -130,7 +145,7 @@ public class AmqpCodecTest extends QpidJmsTestCase {
         header.setDeliveryCount(1);
 
         ByteBuf encoded = AmqpCodec.encode(header.getHeader());
-        AmqpHeader decoded = new AmqpHeader((Header) 
AmqpCodec.decode(encoded));
+        AmqpHeader decoded = new AmqpHeader((Header) 
AmqpCodec.decode(mockConnection, encoded));
 
         assertFalse(decoded.isDurable());
         assertEquals(4, decoded.getPriority());
@@ -149,7 +164,7 @@ public class AmqpCodecTest extends QpidJmsTestCase {
         header.setTimeToLive(32768);
 
         ByteBuf encoded = AmqpCodec.encode(header.getHeader());
-        AmqpHeader decoded = new AmqpHeader((Header) 
AmqpCodec.decode(encoded));
+        AmqpHeader decoded = new AmqpHeader((Header) 
AmqpCodec.decode(mockConnection, encoded));
 
         assertTrue(decoded.isDurable());
         assertTrue(decoded.isFirstAcquirer());
@@ -879,6 +894,100 @@ public class AmqpCodecTest extends QpidJmsTestCase {
         assertTrue(delegate instanceof AmqpTypedObjectDelegate, "Unexpected 
delegate type: " + delegate);
     }
 
+    @Test
+    public void testDecodeDepthLimit() throws Exception {
+        Message message = Proton.message();
+
+        // Verify it fails if exceeding the limit.
+        List<Object> lists = prepareNestedLists(MAX_DECODE_DEPTH + 1);
+        message.setBody(new AmqpValue(lists));
+
+        try {
+            AmqpCodec.decodeMessage(mockConsumer, encodeMessage(message));
+            fail("Expected exception");
+        } catch(DecodeException de) {
+            //Expected
+        }
+
+        // Now check it works if not exceeding the limit.
+        lists = prepareNestedLists(MAX_DECODE_DEPTH);
+        message.setBody(new AmqpValue(lists));
+
+        JmsMessage jmsMessage = AmqpCodec.decodeMessage(mockConsumer, 
encodeMessage(message)).asJmsMessage();
+        assertNotNull(jmsMessage, "Message should not be null");
+        assertEquals(JmsObjectMessage.class, jmsMessage.getClass(), 
"Unexpected message class type");
+
+        JmsMessageFacade facade = jmsMessage.getFacade();
+        assertNotNull(facade, "Facade should not be null");
+        assertEquals(AmqpJmsObjectMessageFacade.class, facade.getClass(), 
"Unexpected facade class type");
+
+        assertEquals(lists, ((AmqpJmsObjectMessageFacade) facade).getObject());
+    }
+
+    @Test
+    public void testZeroWidthArrayElementLimit() throws Exception {
+        // Verify it fails if exceeding the limit.
+        ByteBuffer buf = 
prepareMessageEncodingWithZeroWidthArray(ZERO_WIDTH_ARRAY_ELEMENTS_LIMIT + 1);
+
+        try {
+            AmqpCodec.decodeMessage(mockConsumer, ByteBufferReader.wrap(buf));
+            fail("Expected exception");
+        } catch(DecodeException de) {
+            //Expected
+        }
+
+        // Now check it works if not exceeding the limit.
+        assertEquals(0, ZERO_WIDTH_ARRAY_ELEMENTS_LIMIT);
+        buf = prepareMessageEncodingWithZeroWidthArray(0);
+
+        doZeroWidthArrayElementLimitTestImpl(buf, new boolean[0]);
+
+        // Now check it works if setting a higher limit.
+        final int count = 5;
+        buf = prepareMessageEncodingWithZeroWidthArray(count);
+
+        final boolean[] expected = new boolean[count];
+        Arrays.fill(expected, true);
+
+        
Mockito.when(mockConsumer.getZeroWidthArrayElementLimit()).thenReturn(count);
+
+        doZeroWidthArrayElementLimitTestImpl(buf, expected);
+    }
+
+    private void doZeroWidthArrayElementLimitTestImpl(ByteBuffer buf, final 
boolean[] expected)  throws Exception {
+        JmsMessage jmsMessage = AmqpCodec.decodeMessage(mockConsumer, 
ByteBufferReader.wrap(buf)).asJmsMessage();
+        assertNotNull(jmsMessage, "Message should not be null");
+        assertEquals(JmsObjectMessage.class, jmsMessage.getClass(), 
"Unexpected message class type");
+
+        JmsMessageFacade facade = jmsMessage.getFacade();
+        assertNotNull(facade, "Facade should not be null");
+        assertEquals(AmqpJmsObjectMessageFacade.class, facade.getClass(), 
"Unexpected facade class type");
+
+        final Serializable object = ((AmqpJmsObjectMessageFacade) 
facade).getObject();
+        assertTrue(object.getClass().isArray());
+        assertEquals(boolean.class, object.getClass().getComponentType());
+        assertArrayEquals(expected, (boolean[]) object);
+    }
+
+    private ByteBuffer prepareMessageEncodingWithZeroWidthArray(int 
elementCount) {
+        assertTrue(elementCount >= 0);
+        assertTrue(elementCount <= 255);
+
+        ByteBuffer buf = ByteBuffer.allocate(7);
+        buf.put((byte) 0x00); // DescribedType
+        buf.put((byte) 0x53); // small-ulong constructor
+        buf.put((byte) 0x77); // amqp-value ulong descriptor
+
+        buf.put((byte) 0xE0); // 'array8' type descriptor code
+        buf.put((byte) (1 + 1)); // 1 byte count + 1 byte type
+        buf.put((byte) elementCount); // count
+        buf.put((byte) 0x41); // boolean-true
+
+        buf.flip();
+
+        return buf;
+    }
+
     // --------- AmqpSequence Body Section ---------
 
     /**
@@ -1033,4 +1142,18 @@ public class AmqpCodecTest extends QpidJmsTestCase {
 
         return message;
     }
+
+    private static List<Object> prepareNestedLists(final int depth) {
+        final List<Object> body = new ArrayList<>();
+
+        List<Object> current = body;
+        for (int i = 1; i < depth; ++i) {
+            final List<Object> next = new ArrayList<>();
+
+            current.add(next);
+            current = next;
+        }
+
+        return body;
+    }
 }
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
index 3e2c1fc1..1ee03a4f 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
@@ -32,6 +32,9 @@ import org.mockito.Mockito;
 
 public class AmqpJmsMessageTypesTestCase extends QpidJmsTestCase {
 
+    private static final int MAX_DECODE_DEPTH = 32;
+    private static final int ZERO_WIDTH_ARRAY_ELEMENTS_LIMIT = 0;
+
     private JmsDestination consumerDestination;
 
     @BeforeEach
@@ -133,6 +136,9 @@ public class AmqpJmsMessageTypesTestCase extends 
QpidJmsTestCase {
         Mockito.when(consumer.getConnection()).thenReturn(connection);
         
Mockito.when(consumer.getDestination()).thenReturn(consumerDestination);
         Mockito.when(consumer.getResourceInfo()).thenReturn(new 
JmsConsumerInfo(consumerId, null));
+        
Mockito.when(consumer.getMaxDecodeDepth()).thenReturn(MAX_DECODE_DEPTH);
+        
Mockito.when(consumer.getZeroWidthArrayElementLimit()).thenReturn(ZERO_WIDTH_ARRAY_ELEMENTS_LIMIT);
+
         return consumer;
     }
 
@@ -145,6 +151,8 @@ public class AmqpJmsMessageTypesTestCase extends 
QpidJmsTestCase {
         AmqpConnection connection = Mockito.mock(AmqpConnection.class);
         Mockito.when(connection.getResourceInfo()).thenReturn(new 
JmsConnectionInfo(connectionId));
         
Mockito.when(connection.isObjectMessageUsesAmqpTypes()).thenReturn(amqpTyped);
+        
Mockito.when(connection.getMaxDecodeDepth()).thenReturn(MAX_DECODE_DEPTH);
+        
Mockito.when(connection.getZeroWidthArrayElementLimit()).thenReturn(ZERO_WIDTH_ARRAY_ELEMENTS_LIMIT);
 
         return connection;
     }
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
index 2906f74a..c5634177 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
@@ -2783,6 +2783,16 @@ public class TestAmqpPeer implements AutoCloseable
                                                                 final String 
tagAsString,
                                                                 final Boolean 
more,
                                                                 final int 
sendDelay) {
+        Binary payload = prepareTransferPayload(headerDescribedType, 
messageAnnotationsDescribedType, propertiesDescribedType, 
appPropertiesDescribedType, content);
+
+        sendTransferToLastOpenedLinkOnLastOpenedSession(payload, 
nextIncomingDeliveryId, tagAsString, more, sendDelay);
+    }
+
+    public void sendTransferToLastOpenedLinkOnLastOpenedSession(final Binary 
payload,
+                                                                final int 
nextIncomingDeliveryId,
+                                                                final String 
tagAsString,
+                                                                final Boolean 
more,
+                                                                final int 
sendDelay) {
         synchronized (_handlersLock) {
             CompositeAmqpPeerRunnable comp = 
insertCompsiteActionForLastHandler();
 
@@ -2801,8 +2811,6 @@ public class TestAmqpPeer implements AutoCloseable
                 transferResponse.setMore(more);
             }
 
-            Binary payload = prepareTransferPayload(headerDescribedType, 
messageAnnotationsDescribedType, propertiesDescribedType, 
appPropertiesDescribedType, content);
-
             // The response frame channel will be dynamically set based on the 
incoming frame. Using the -1 is an illegal placeholder.
             final FrameSender transferSender = new FrameSender(this, 
FrameType.AMQP, -1, transferResponse, payload);
             transferSender.setValueProvider(new ValueProvider()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to