JsonIgnoreSetterFieldBypass5398Test.java

package tools.jackson.databind.introspect;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.annotation.*;

import tools.jackson.databind.*;
import tools.jackson.databind.testutil.DatabindTestUtil;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Tests covering the [databind#5398] follow-up: when a property's setter is
 * {@code @JsonIgnore}d (and the getter carries {@code @JsonProperty} that
 * keeps the property non-ignored as a whole), the inferred field mutator
 * retained via {@code MapperFeature.INFER_PROPERTY_MUTATORS} must NOT be
 * used to bypass the ignored setter. The property should remain
 * serialization-only (read-only).
 */
public class JsonIgnoreSetterFieldBypass5398Test extends DatabindTestUtil
{
    static class RenamedGetterIgnoredSetter {
        private String prop;

        @JsonProperty("renamedProp")
        public String getProp() {
            return prop;
        }

        @JsonIgnore
        public void setProp(String prop) {
            this.prop = prop;
        }
    }

    static class StandardGetterIgnoredSetter {
        private String prop;

        @JsonProperty
        public String getProp() {
            return prop;
        }

        @JsonIgnore
        public void setProp(String prop) {
            this.prop = prop;
        }
    }

    // Sibling shape: READ_ONLY access on getter rather than @JsonIgnore on setter.
    static class ReadOnlyRenamedGetter {
        private String prop;

        @JsonProperty(value = "renamedProp", access = JsonProperty.Access.READ_ONLY)
        public String getProp() {
            return prop;
        }

        public void setProp(String prop) {
            this.prop = prop;
        }
    }

    private final ObjectMapper MAPPER = newJsonMapper();

    @Test
    public void renamedGetterStillSerializes() throws Exception
    {
        RenamedGetterIgnoredSetter bean = new RenamedGetterIgnoredSetter();
        bean.setProp("someValue");
        assertEquals("{\"renamedProp\":\"someValue\"}",
                MAPPER.writeValueAsString(bean));
    }

    @Test
    public void standardGetterStillSerializes() throws Exception
    {
        StandardGetterIgnoredSetter bean = new StandardGetterIgnoredSetter();
        bean.setProp("someValue");
        assertEquals("{\"prop\":\"someValue\"}",
                MAPPER.writeValueAsString(bean));
    }

    // The renamed property must be read-only: @JsonIgnore on the setter
    // blocks the write, and the inferred field mutator must not bypass it.
    @Test
    public void renamedIgnoredSetterDoesNotBypassViaField() throws Exception
    {
        RenamedGetterIgnoredSetter result = MAPPER.readValue(
                "{\"renamedProp\":\"someValue\"}",
                RenamedGetterIgnoredSetter.class);
        assertNotNull(result);
        assertNull(result.getProp());
    }

    @Test
    public void standardIgnoredSetterDoesNotBypassViaField() throws Exception
    {
        StandardGetterIgnoredSetter result = MAPPER.readValue(
                "{\"prop\":\"someValue\"}",
                StandardGetterIgnoredSetter.class);
        assertNotNull(result);
        assertNull(result.getProp());
    }

    // Control: feeding the implicit field name (rather than the renamed
    // public name) also does not write the field.
    @Test
    public void implicitFieldNameDoesNotWriteWhenSetterIgnored() throws Exception
    {
        RenamedGetterIgnoredSetter result = MAPPER.readerFor(RenamedGetterIgnoredSetter.class)
                .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .readValue("{\"prop\":\"someValue\"}");
        assertNotNull(result);
        assertNull(result.getProp());
    }

    // Bypass must also stay closed when INFER_PROPERTY_MUTATORS is disabled,
    // i.e. the fix is not just an artifact of inference being on.
    @Test
    public void inferMutatorsDisabledStillBlocksWrite() throws Exception
    {
        ObjectMapper mapper = jsonMapperBuilder()
                .disable(MapperFeature.INFER_PROPERTY_MUTATORS)
                .build();
        RenamedGetterIgnoredSetter result = mapper.readValue(
                "{\"renamedProp\":\"someValue\"}",
                RenamedGetterIgnoredSetter.class);
        assertNotNull(result);
        assertNull(result.getProp());
    }

    // Sibling: @JsonProperty(access = READ_ONLY) on the renamed getter must
    // produce the same outcome ��� serialize under the new name, not write
    // back via the inferred field mutator.
    @Test
    public void readOnlyRenamedGetterIsSerializeOnly() throws Exception
    {
        ReadOnlyRenamedGetter bean = new ReadOnlyRenamedGetter();
        bean.setProp("someValue");
        assertEquals("{\"renamedProp\":\"someValue\"}",
                MAPPER.writeValueAsString(bean));

        ReadOnlyRenamedGetter result = MAPPER.readValue(
                "{\"renamedProp\":\"someValue\"}",
                ReadOnlyRenamedGetter.class);
        assertNotNull(result);
        assertNull(result.getProp());
    }

}