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