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