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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions