Skip to content

AbstractJackson2MessageConverter: GH-3038 fix incomplete - encoding parameter prevents byte[] path for binary formats #3301

@ugurberkecan

Description

@ugurberkecan

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions