Skip to content

JsonCreator on static method in Enum and Enum used as key in map fails randomlyΒ #2725

@BigMichi1

Description

@BigMichi1

given this piece of code and jackson-databind 2.10.3

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Test {
    public static void main(String[] args) throws JsonProcessingException {
        final ObjectMapper mapper = new ObjectMapper();

        final Map<TestEnum, String> input = new HashMap<>();
        input.put(TestEnum.FOO, "Hello");
        final String inputJson = mapper.writeValueAsString(input);
        System.out.println("inputJson = " + inputJson);

        final Map<TestEnum, String> output = mapper.readValue(inputJson, new TypeReference<Map<TestEnum, String>>() {
        });
        System.out.println("output = " + output);
    }

    private enum TestEnum {
        FOO(1);

        private final int i;

        TestEnum(final int i) {
            this.i = i;
        }

        @JsonValue
        public int getI() {
            return i;
        }

        @JsonCreator
        public static TestEnum getByIntegerId(final Integer id) {
            return id == FOO.i ? FOO : null;
        }

        @JsonCreator
        public static TestEnum getByStringId(final String id) {
            return Integer.parseInt(id) == FOO.i ? FOO : null;
        }
    }
}

and running it on multiple computers the output is different.
sometimes it works and the map is deserialized correctly and sometimes it does not work and fails with Exception in thread "main" java.lang.IllegalArgumentException: Parameter #0 type for factory method ([method foo.Test$TestEnum#getByIntegerId(1 params)]) not suitable, must be java.lang.String

now when I change the order of the methods annotated with JsonCreator it works, but then it started to fail on other computers with the same exception as above.

I tried to debug this and found out that sometimes the order of the annotated methods is different that is iterated over in BasicDeserializerFactory#_createEnumKeyDeserializer when taking a look at the beanDesc.getFactoryMethods() methods. These list of methods as far as I could see is created in AnnotatedCreatorCollector#_findPotentialFactories via ClassUtil.getClassMethods which then calls ClassUtil.getDeclaredMethods(cls) and this is using Class#getDeclaredMethods which as written in the JavaDoc that the methods elements in the returned array are not sorted and are not in any particular order. So this is now probably the root of the issues which I can see. And as the loop stops with the exception after the first candidate has been checked in BasicDeserializerFactory the remaining methods are not taken into consideration.

From my perspective, all annotated methods need to be checked before the exception can be thrown or at least the annotation parser should fail when multiple creators are detected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions