jackson-databind icon indicating copy to clipboard operation
jackson-databind copied to clipboard

Multiple suitable annotated Creator factory methods to be used as the Key deserializer when using record als key in Map

Open toonborgers opened this issue 2 years ago • 7 comments

Describe the bug When using a java record class with multiple @JsonCreator annotated factory methods as the key type in a map, deserialization fails with a com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Multiple suitable annotated Creator factory methods to be used as the Key deserializer for type ... error

Version information 2.14.3

To Reproduce Following snippet works for the first 2 invocations of MAPPER.readValue, the others do work:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Map;

class DeserializeTest {

    public static final ObjectMapper MAPPER = new ObjectMapper();

    public static void main(String... args) throws Exception {
        MAPPER.readValue("""
                {
                  "value": "abc"
                }
                """, ClassWithMultipleFactories.class);
        MAPPER.readValue("""
                {
                  "foo": "abc"
                }
                """, WrapperClass.class);
        MAPPER.readValue("""
                {
                  "map": {
                    "foo": "bar"
                  }
                }
                """, WrapperClassWithMap.class);
        MAPPER.readValue("""
                {}
                """, WrapperClassWithMap.class);
    }

    public static class WrapperClassWithMap {
        private final Map<ClassWithMultipleFactories, String> map;

        @JsonCreator
        public WrapperClassWithMap(@JsonProperty("map") Map<ClassWithMultipleFactories, String> map) {
            this.map = map;
        }

        public Map<ClassWithMultipleFactories, String> getMap() {
            return map;
        }
    }

    public static class WrapperClass {
        private final ClassWithMultipleFactories foo;

        @JsonCreator
        public WrapperClass(@JsonProperty("foo") ClassWithMultipleFactories foo) {
            this.foo = foo;
        }

        public ClassWithMultipleFactories getFoo() {
            return foo;
        }
    }

    public record ClassWithMultipleFactories(String value) {
        @JsonCreator
        public static ClassWithMultipleFactories fromValue(String value) {
            return new ClassWithMultipleFactories(value);
        }

        @JsonCreator
        public static ClassWithMultipleFactories fromWrapped(@JsonProperty("value") String value) {
            return new ClassWithMultipleFactories(value);
        }

        public String getValue() {
            return value;
        }
    }
}

Expected behavior I'd expect the ObjectMapper to correctly detect how to deserialize the key of the map, similar to how it detects it in the other invocations of readValue()

toonborgers avatar May 22 '23 08:05 toonborgers