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

jlmonteiro pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq.git


The following commit(s) were added to refs/heads/main by this push:
     new cada078f2e Fix Jakarta 3.1 compliance for Character property types 
(#1736)
cada078f2e is described below

commit cada078f2e85ecb118fca3a9ea9ad5c94c305910
Author: pradeep85841 <[email protected]>
AuthorDate: Fri Mar 13 02:23:59 2026 +0530

    Fix Jakarta 3.1 compliance for Character property types (#1736)
    
    * Fixing Jakarta 3.1 TCK issue: Added strict check for Character type while 
keeping legacy support
    
    * Add missing ASF license header to test file
    
    * Set nestedMapAndListEnabled to false by default for Jakarta 3.1 compliance
    
    * Align default configuration and tests with Jakarta 3.1 compliance
    
    * Introduce strictCompliance master flag for Jakarta 3.1 alignment
    
    * Add strictCompliance flag and preserve legacy validation logic
    
    * Decouple strictCompliance from legacy flags and isolate Character 
rejection
---
 .../org/apache/activemq/ActiveMQConnection.java    |  19 +++-
 .../apache/activemq/ActiveMQConnectionFactory.java |  21 ++++
 .../apache/activemq/command/ActiveMQMessage.java   |  13 ++-
 .../activemq/ActiveMQMessagePropertyTest.java      | 111 +++++++++++++++++++++
 4 files changed, 161 insertions(+), 3 deletions(-)

diff --git 
a/activemq-client/src/main/java/org/apache/activemq/ActiveMQConnection.java 
b/activemq-client/src/main/java/org/apache/activemq/ActiveMQConnection.java
index 8600861675..dde17b7fec 100644
--- a/activemq-client/src/main/java/org/apache/activemq/ActiveMQConnection.java
+++ b/activemq-client/src/main/java/org/apache/activemq/ActiveMQConnection.java
@@ -141,6 +141,12 @@ public class ActiveMQConnection implements Connection, 
TopicConnection, QueueCon
     private RedeliveryPolicyMap redeliveryPolicyMap;
     private MessageTransformer transformer;
 
+    /**
+     * If set to true, strict Jakarta Messaging 3.1 compliance is enforced.
+     * This strictly rejects non-standard property types such as Character, 
Map, and List.
+     */
+    private boolean strictCompliance = false;
+
     private boolean disableTimeStampsByDefault;
     private boolean optimizedMessageDispatch = true;
     private boolean copyMessageOnSend = true;
@@ -889,7 +895,7 @@ public class ActiveMQConnection implements Connection, 
TopicConnection, QueueCon
                                                                     int 
maxMessages) throws JMSException {
         throw new 
UnsupportedOperationException("createSharedConnectionConsumer() is not 
supported");
     }
-    
+
     // Properties
     // 
-------------------------------------------------------------------------
   
@@ -1035,6 +1041,17 @@ public class ActiveMQConnection implements Connection, 
TopicConnection, QueueCon
         this.nestedMapAndListEnabled = structuredMapsEnabled;
     }
 
+    public boolean isStrictCompliance() {
+        return strictCompliance;
+    }
+
+    /**
+     * Sets whether strict Jakarta Messaging compliance is enforced for this 
connection.
+     */
+    public void setStrictCompliance(boolean strictCompliance) {
+        this.strictCompliance = strictCompliance;
+    }
+
     public boolean isExclusiveConsumer() {
         return exclusiveConsumer;
     }
diff --git 
a/activemq-client/src/main/java/org/apache/activemq/ActiveMQConnectionFactory.java
 
b/activemq-client/src/main/java/org/apache/activemq/ActiveMQConnectionFactory.java
index ae57d2624b..b36f4a0d9d 100644
--- 
a/activemq-client/src/main/java/org/apache/activemq/ActiveMQConnectionFactory.java
+++ 
b/activemq-client/src/main/java/org/apache/activemq/ActiveMQConnectionFactory.java
@@ -123,6 +123,12 @@ public class ActiveMQConnectionFactory extends 
JNDIBaseStorable implements Conne
     private BlobTransferPolicy blobTransferPolicy = new BlobTransferPolicy();
     private MessageTransformer transformer;
 
+    /**
+     * If set to true, strict Jakarta Messaging 3.1 compliance is enforced.
+     * This strictly rejects non-standard property types such as Character, 
Map, and List.
+     */
+    private boolean strictCompliance = false;
+
     private boolean disableTimeStampsByDefault;
     private boolean optimizedMessageDispatch = true;
     private long optimizeAcknowledgeTimeOut = 300;
@@ -408,6 +414,10 @@ public class ActiveMQConnectionFactory extends 
JNDIBaseStorable implements Conne
     protected ActiveMQConnection createActiveMQConnection(Transport transport, 
JMSStatsImpl stats) throws Exception {
         ActiveMQConnection connection = new ActiveMQConnection(transport, 
getClientIdGenerator(),
                 getConnectionIdGenerator(), stats);
+
+        // Copy the compliance flags from the Factory to the Connection
+        connection.setStrictCompliance(isStrictCompliance());
+
         return connection;
     }
 
@@ -1000,6 +1010,17 @@ public class ActiveMQConnectionFactory extends 
JNDIBaseStorable implements Conne
         this.nestedMapAndListEnabled = structuredMapsEnabled;
     }
 
+    public boolean isStrictCompliance() {
+        return strictCompliance;
+    }
+
+    /**
+     * If this flag is set then the connection follows strict Jakarta 
Messaging compliance.
+     */
+    public void setStrictCompliance(boolean strictCompliance) {
+        this.strictCompliance = strictCompliance;
+    }
+
     public String getClientIDPrefix() {
         return clientIDPrefix;
     }
diff --git 
a/activemq-client/src/main/java/org/apache/activemq/command/ActiveMQMessage.java
 
b/activemq-client/src/main/java/org/apache/activemq/command/ActiveMQMessage.java
index f9eb371e58..3a02d074c6 100644
--- 
a/activemq-client/src/main/java/org/apache/activemq/command/ActiveMQMessage.java
+++ 
b/activemq-client/src/main/java/org/apache/activemq/command/ActiveMQMessage.java
@@ -527,9 +527,18 @@ public class ActiveMQMessage extends Message implements 
org.apache.activemq.Mess
         boolean valid = value instanceof Boolean || value instanceof Byte || 
value instanceof Short || value instanceof Integer || value instanceof Long;
         valid = valid || value instanceof Float || value instanceof Double || 
value instanceof Character || value instanceof String || value == null;
 
-        if (!valid) {
+        ActiveMQConnection conn = getConnection();
+
+        // strict rejection for Character
+        if (valid && conn != null && conn.isStrictCompliance() && value 
instanceof Character) {
+            throw new MessageFormatException("Character type not allowed under 
strict Jakarta 3.1 compliance");
+        }
 
-            ActiveMQConnection conn = getConnection();
+        if (!valid) {
+            // Check strict compliance at validation time without 
side-effecting the 'nested' flag
+            if (conn != null && conn.isStrictCompliance()) {
+                throw new MessageFormatException("Only objectified primitive 
objects and String types are allowed under strict Jakarta 3.1 compliance but 
was: " + value + " type: " + value.getClass());
+            }
             // conn is null if we are in the broker rather than a JMS client
             if (conn == null || conn.isNestedMapAndListEnabled()) {
                 if (!(value instanceof Map || value instanceof List)) {
diff --git 
a/activemq-unit-tests/src/test/java/org/apache/activemq/ActiveMQMessagePropertyTest.java
 
b/activemq-unit-tests/src/test/java/org/apache/activemq/ActiveMQMessagePropertyTest.java
new file mode 100644
index 0000000000..1180c825a9
--- /dev/null
+++ 
b/activemq-unit-tests/src/test/java/org/apache/activemq/ActiveMQMessagePropertyTest.java
@@ -0,0 +1,111 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq;
+
+import org.apache.activemq.broker.BrokerService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import jakarta.jms.Connection;
+import jakarta.jms.Message;
+import jakarta.jms.MessageFormatException;
+import jakarta.jms.Session;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static 
org.apache.activemq.command.DataStructureTestSupport.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+public class ActiveMQMessagePropertyTest {
+
+    private BrokerService broker;
+    private String connectionUri;
+
+    @Before
+    public void setUp() throws Exception {
+        broker = new BrokerService();
+        broker.setPersistent(false);
+        broker.setUseJmx(false);
+        broker.addConnector("vm://localhost");
+        broker.start();
+        broker.waitUntilStarted();
+        connectionUri = 
broker.getTransportConnectors().get(0).getPublishableConnectString();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (broker != null) {
+            broker.stop();
+            broker.waitUntilStopped();
+        }
+    }
+
+    @Test
+    public void testStrictComplianceMasterSwitch() throws Exception {
+        ActiveMQConnectionFactory factory = new 
ActiveMQConnectionFactory("vm://localhost");
+
+        // Turn on strict compliance
+        factory.setStrictCompliance(true);
+        // Explicitly turn on the legacy flag to prove strict mode overrides it
+        factory.setNestedMapAndListEnabled(true);
+
+        Connection connection = factory.createConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE);
+        Message message = session.createMessage();
+
+        // Verify standard types work
+        message.setStringProperty("validString", "test"); // Should pass
+
+        // Verify Character is rejected
+        try {
+            message.setObjectProperty("invalidChar", 'A');
+            fail("Should have rejected Character under strict compliance");
+        } catch (MessageFormatException e) {
+            // Expected
+        }
+
+        // Verify Map is rejected (even though nestedMapAndListEnabled is true)
+        try {
+            Map<String, String> map = new HashMap<>();
+            message.setObjectProperty("invalidMap", map);
+            fail("Should have rejected Map under strict compliance");
+        } catch (MessageFormatException e) {
+            // Expected
+        }
+
+        connection.close();
+    }
+
+    @Test
+    public void testLegacyModeStillAllowsCharacter() throws Exception {
+        ActiveMQConnectionFactory factory = new 
ActiveMQConnectionFactory(connectionUri);
+
+        // Default is strictCompliance = false
+        try (Connection connection = factory.createConnection();
+             Session session = connection.createSession(false, 
Session.AUTO_ACKNOWLEDGE)) {
+
+            Message message = session.createMessage();
+            message.setObjectProperty("charProp", 'A'); // Should pass
+            assertEquals('A', message.getObjectProperty("charProp"));
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information, visit: https://activemq.apache.org/contact


Reply via email to