Search before asking

  • [x] I searched in the issues and found nothing similar.

Describe the bug

Classes which use @JsonValue and use values which would result in empty string and are used as fields in serializable Pojos, and Object mapper is configured with Include.NON_DEFAULT will result in different json values starting with version 2.18

Following test case will work fine in version 2.17.3, but will fail after upgrading to 2.18+

Note, this might be related to https://github.com/FasterXML/jackson-databind/issues/4741 https://github.com/FasterXML/jackson-databind/issues/4464

Version Information

2.18+

Reproduction

package com.example;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MutableConfigOverride;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_DEFAULT;
import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;

public class JacksonTest {

    record StringValue(String value) {
        @Override
        @JsonValue
        public String value() {
            return value;
        }
    }
    record Pojo1(StringValue value) {
    }

    @JsonInclude(JsonInclude.Include.NON_DEFAULT)
    record Pojo2(StringValue value) {
    }


    record Pojo3(@JsonInclude(JsonInclude.Include.NON_DEFAULT) StringValue value) {
    }


    @Test
    void testSerialization() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(NON_DEFAULT);

        //might be relevant for analysis, but does not affect test outcome
        MutableConfigOverride objectStringConfigOverride = objectMapper.configOverride(String.class);
        objectStringConfigOverride.setIncludeAsProperty(JsonInclude.Value.construct(NON_NULL, NON_NULL));

        Assertions.assertAll(
                //FAIL on jackson 2.18.2 / 2.20.0
                () -> Assertions.assertEquals("{\"value\":\"\"}", objectMapper.writeValueAsString(new Pojo1(new StringValue("")))),
                //PASS
                () -> Assertions.assertEquals("{\"value\":\"\"}", objectMapper.writeValueAsString(new Pojo2(new StringValue("")))),
                //FAIL on jackson 2.18.2 / 2.20.0
                () -> Assertions.assertEquals("{\"value\":\"\"}", objectMapper.writeValueAsString(new Pojo3(new StringValue(""))))
        );
    }
}

Expected behavior

After serialization jackson should produce the same value

Additional context

No response

Comment From: JooHyukKim

Could be regression off of introspection refactor which happened in 2.18. Will look in to it.

Did u find anything that could relate to this issue release-notes? @LSwiatek

Comment From: cowtowncoder

Value of NON_DEFAULT has been problematic for the longest time, unfortunately.

I do not think there has been intentional changes, for what that is worth. But handling of Creators (and due to that, Record types) was rewritten for 2.18.0, with many follow-up fixes in 2.18.x patches, are likely reason for change.

Also good to verify problem remains in 2.19.2 / 2.20.0 (I assume it does but just in case).

Comment From: JooHyukKim

Yup, failing 2.18 and onward (including 2.x latest)