-
Notifications
You must be signed in to change notification settings - Fork 644
Open
Description
In what version(s) of Spring AMQP are you seeing this issue?
3.2.6 (and later versions with GH-3038 backport)
Describe the bug
The fix for GH-3038 is incomplete. While supportedCTCharset is now properly set when charset is provided in the MimeType constructor, the byte[] path in convertBytesToObject is only reached when encoding == null, which rarely happens in practice.
Root cause
In convertBytesToObject:
private Object convertBytesToObject(byte[] body, @Nullable String encoding, JavaType targetJavaType) {
String encodingToUse = encoding;
if (encodingToUse == null) { // encoding is usually "UTF-8", not null
if (this.charsetIsUtf8 & this.supportedCTCharset == null) {
return this.objectMapper.readValue(body, targetJavaType);
}
encodingToUse = getDefaultCharset();
}
// Always reaches here when encoding is set
String contentAsString = new String(body, encodingToUse);
return this.objectMapper.readValue(contentAsString, targetJavaType); // CBOR fails
}
The encoding parameter comes from determineEncoding() which always returns a non-null value (typically "UTF-8"). Therefore, even with supportedCTCharset set, the code never reaches the byte[] path and always converts to String, breaking CBOR/Smile/Avro binary formats.
To Reproduce
@Bean
public MessageConverter cborConverter(CBORMapper cborMapper) {
return new AbstractJackson2MessageConverter(
cborMapper,
new MimeType("application", "json", Charset.forName("UTF-8"))
) {};
}
// Producer sends JSON-serialized message with content-type: application/json
// Consumer tries to deserialize
// Result: UnsupportedOperationException: Can not create parser for non-byte-based source
Expected behavior
When supportedCTCharset is set, binary-format ObjectMappers (CBOR, Smile, Avro) should receive byte[] directly, not String.
Proposed fix
private Object convertBytesToObject(byte[] body, @Nullable String encoding, JavaType targetJavaType)
throws IOException {
if (this.supportedCTCharset != null) {
return this.objectMapper.readValue(body, targetJavaType);
}
if (encoding == null) {
if (this.charsetIsUtf8) {
return this.objectMapper.readValue(body, targetJavaType);
}
encoding = getDefaultCharset();
}
String contentAsString = new String(body, encoding);
return this.objectMapper.readValue(contentAsString, targetJavaType);
}
This ensures binary formats always get byte[] when charset is explicitly configured, matching the documentation: "If this contains a charset parameter, the raw bytes are passed to Jackson."