NoTypeInfo1654MapTest.java

package tools.jackson.databind.jsontype;

import java.util.*;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.annotation.JsonTypeInfo;

import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.JsonParser;

import tools.jackson.databind.*;
import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.annotation.JsonSerialize;
import tools.jackson.databind.testutil.DatabindTestUtil;

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

/**
 * Test for Map values with {@code @JsonTypeInfo(use = Id.NONE)} override,
 * extending issue #1654 coverage to Map types.
 */
class NoTypeInfo1654MapTest extends DatabindTestUtil
{
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
    static class Value1654 {
        public int x;

        protected Value1654() { }

        public Value1654(int x) {
            this.x = x;
        }
    }

    static class Value1654TypedMapContainer {
        public Map<String, Value1654> values;

        protected Value1654TypedMapContainer() { }

        public Value1654TypedMapContainer(Map<String, Value1654> v) {
            values = v;
        }
    }

    static class Value1654UntypedMapContainer {
        @JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
        public Map<String, Value1654> values;

        protected Value1654UntypedMapContainer() { }

        public Value1654UntypedMapContainer(Map<String, Value1654> v) {
            values = v;
        }
    }

    static class Value1654UsingCustomSerDeserUntypedMapContainer {
        @JsonDeserialize(contentUsing = Value1654Deserializer.class)
        @JsonSerialize(contentUsing = Value1654Serializer.class)
        @JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
        public Map<String, Value1654> values;

        protected Value1654UsingCustomSerDeserUntypedMapContainer() { }

        public Value1654UsingCustomSerDeserUntypedMapContainer(Map<String, Value1654> v) {
            values = v;
        }
    }

    static class SingleValue1654UsingCustomSerDeserUntyped {
        @JsonDeserialize(using = Value1654Deserializer.class)
        @JsonSerialize(using = Value1654Serializer.class)
        @JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
        public Value1654 value;

        protected SingleValue1654UsingCustomSerDeserUntyped() { }

        public SingleValue1654UsingCustomSerDeserUntyped(Value1654 v) {
            value = v;
        }
    }

    static class Value1654Deserializer extends ValueDeserializer<Value1654> {
        @Override
        public Value1654 deserialize(JsonParser p, DeserializationContext ctxt) {
            JsonNode n = ctxt.readTree(p);
            if (!n.has("v")) {
                ctxt.reportInputMismatch(Value1654.class, "Bad JSON input (no 'v'): " + n);
            }
            return new Value1654(n.path("v").intValue());
        }
    }


    static class Value1654Serializer extends ValueSerializer<Value1654> {
        @Override
        public void serialize(Value1654 value, JsonGenerator gen, SerializationContext ctxt)
                throws JacksonException {
            gen.writeStartObject(value);
            gen.writeNumberProperty("v", value.x);
            gen.writeEndObject();
        }
    }

    /*
    /**********************************************************************
    /* Test methods
    /**********************************************************************
     */

    private final ObjectMapper MAPPER = newJsonMapper();

    // [databind#1654]: no override, default polymorphic type id for Map values
    @Test
    void withoutNoTypeElementOverrideSerAndDeser() throws Exception {
        // regular typed case
        Map<String, Value1654> map = new LinkedHashMap<>();
        map.put("first", new Value1654(1));
        map.put("second", new Value1654(2));

        String json = MAPPER.writeValueAsString(new Value1654TypedMapContainer(map));
        String typeId = Value1654.class.getName();
        typeId = "'@type':'" + typeId.substring(typeId.lastIndexOf('.') + 1) + "'";
        assertEquals(a2q("{'values':{'first':{"+typeId+",'x':1},'second':{"+typeId+",'x':2}}}"), json);

        Value1654TypedMapContainer result = MAPPER.readValue(json, Value1654TypedMapContainer.class);
        assertEquals(2, result.values.size());
        assertEquals(2, result.values.get("second").x);
    }

    // [databind#1654]: override, no polymorphic type id for Map values, serialization
    @Test
    void withNoTypeInfoDefaultSer() throws Exception {
        Map<String, Value1654> map = new LinkedHashMap<>();
        map.put("first", new Value1654(3));
        map.put("second", new Value1654(7));

        Value1654UntypedMapContainer cont = new Value1654UntypedMapContainer(map);
        assertEquals(a2q("{'values':{'first':{'x':3},'second':{'x':7}}}"),
                MAPPER.writeValueAsString(cont));
    }

    // [databind#1654]: override, no polymorphic type id for Map values, deserialization
    @Test
    void withNoTypeInfoDefaultDeser() throws Exception {
        final String noTypeJson = a2q(
                "{'values':{'first':{'x':3},'second':{'x':7}}}"
        );
        Value1654UntypedMapContainer unResult = MAPPER.readValue(noTypeJson,
                Value1654UntypedMapContainer.class);
        assertEquals(2, unResult.values.size());
        assertEquals(7, unResult.values.get("second").x);
    }

    // [databind#1654]: override, no polymorphic type id for Map values, custom serialization
    @Test
    void withNoTypeInfoOverrideSer() throws Exception {
        Map<String, Value1654> map = new LinkedHashMap<>();
        map.put("first", new Value1654(1));
        map.put("second", new Value1654(2));

        Value1654UsingCustomSerDeserUntypedMapContainer cont =
                new Value1654UsingCustomSerDeserUntypedMapContainer(map);
        assertEquals(a2q("{'values':{'first':{'v':1},'second':{'v':2}}}"),
                MAPPER.writeValueAsString(cont));
    }

    // [databind#1654]: override, no polymorphic type id for Map values, custom deserialization
    @Test
    void withNoTypeInfoOverrideDeser() throws Exception {
        final String noTypeJson = a2q(
                "{'values':{'first':{'v':3},'second':{'v':7}}}"
        );
        Value1654UsingCustomSerDeserUntypedMapContainer unResult = MAPPER.readValue(noTypeJson,
                Value1654UsingCustomSerDeserUntypedMapContainer.class);
        assertEquals(2, unResult.values.size());
        assertEquals(3, unResult.values.get("first").x);
        assertEquals(7, unResult.values.get("second").x);
    }

    // // And then validation for individual value, not in Container

    // override, no polymorphic type id, custom serialization
    @Test
    void singleWithNoTypeInfoOverrideSer() throws Exception {
        SingleValue1654UsingCustomSerDeserUntyped wrapper = new SingleValue1654UsingCustomSerDeserUntyped(
                new Value1654(42));
        assertEquals(a2q("{'value':{'v':42}}"),
                MAPPER.writeValueAsString(wrapper));
    }

    // override, no polymorphic type id, custom deserialization
    @Test
    void singleWithNoTypeInfoOverrideDeser() throws Exception {
        String noTypeJson = a2q("{'value':{'v':42}}");
        SingleValue1654UsingCustomSerDeserUntyped result = MAPPER.readValue(noTypeJson,
                SingleValue1654UsingCustomSerDeserUntyped.class);
        assertEquals(42,result.value.x);
    }
}