alibrahimMrx opened a new issue, #2669:
URL: https://github.com/apache/activemq/issues/2669

   ### Summary
   After upgrading activemq-client from 6.2.6 to 6.3.2, strings nested inside a 
`List` (or `Map`) value of a `MapMessage` are returned to the consumer as 
`org.fusesource.hawtbuf.UTF8Buffer` instead of `java.lang.String`.
   
   Top-level values are not affected: `ActiveMQMapMessage.getObject()` converts 
a top-level `UTF8Buffer` to `String`, but elements inside a returned 
`List`/`Map` are left as `UTF8Buffer`. Code that worked on 6.2.6 now fails with:
   
   ```
   java.lang.ClassCastException: class org.fusesource.hawtbuf.UTF8Buffer cannot 
be cast to class java.lang.String
   ```
   
   `UTF8Buffer` is an internal type, and the JMS spec only allows `String` for 
text values, so applications should not receive it.
   
   ### Versions
   - Works: activemq-client 6.2.6
   - Fails: activemq-client 6.3.2 (intermediate versions not tested)
   - Java 21
   
   ### Reproducer (no broker required)
   ```java
   import static org.junit.jupiter.api.Assertions.assertEquals;
   
   import java.util.ArrayList;
   import java.util.List;
   
   import org.apache.activemq.command.ActiveMQMapMessage;
   import org.junit.jupiter.api.Test;
   
   class NestedStringTypeTest {
   
       @Test
       void nestedStringIsReturnedAsString() throws Exception {
           ActiveMQMapMessage message = new ActiveMQMapMessage();
           message.setObject("list", new ArrayList<>(List.of(123L, "ABC", 1)));
   
           message.storeContentAndClear();   // marshal body to bytes
           message.setReadOnlyBody(true);
   
           List<?> received = (List<?>) message.getObject("list");   // 
unmarshal
   
           // 6.2.6: java.lang.String
           // 6.3.2: org.fusesource.hawtbuf.UTF8Buffer
           assertEquals(String.class, received.get(1).getClass());
       }
   }
   ```
   
   ### Analysis
   In `org.apache.activemq.util.MarshallingSupport`, `unmarshalPrimitive` takes 
a `force` flag. Nested collections pass `force = true` (the `LIST_TYPE` branch 
calls `unmarshalPrimitiveList(in, true)`), which used to make the `STRING_TYPE` 
branch return a `java.lang.String`.
   
   In the current code, the `STRING_TYPE` branch no longer checks `force` and 
always returns the `UTF8Buffer` from `readUTF(in, maxBufferSize, length)`. The 
`BIG_STRING_TYPE` branch still honours `force`, so in the same list, short 
strings come back as `UTF8Buffer` and long strings as `String`. This 
inconsistency suggests the change was unintentional. It appears to have come in 
with the deserialization hardening (buffer-size and nesting-depth limits, PR 
#2080), but I have only tested 6.2.6 and 6.3.2.
   
   The wire format is unchanged; only the consumer side is affected.
   
   ### Expected behaviour
   Strings nested in `MapMessage` `List`/`Map` values are returned as 
`java.lang.String`, as in 6.2.6.
   
   ### Suggested fix
   In the `STRING_TYPE` branch of `MarshallingSupport.unmarshalPrimitive`, 
honour `force` the same way `BIG_STRING_TYPE` does: when `force` is true, 
return the `String` form of the length-limited read, so the new size limits are 
kept.
   
   ### Workaround
   Recursively convert `UTF8Buffer` elements to `String` after calling 
`getObject()` on the consumer side.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
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