Skip to content

2.11.3 regression involving generics + static @JsonCreator 'of' method #2916

@stevestorey

Description

@stevestorey

Describe the bug
I've discovered what appears to be a regression between 2.11.2 and 2.11.3 involving a combination of generic type references, and the use of static builder methods annotated with `@JsonCreator'

Version information
2.11.3

To Reproduce
Plain unit test:

package regression;

import java.io.IOException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

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

public class Jackson2Dot11Dot3Test {

    @Test
    public void testPolymorphism() throws IOException {
        Holder<TypedChild> holder = Holder.of(new TypedChild("jackson"));
        ObjectMapper om = new ObjectMapper();
        Assertions.assertEquals("{\"value\":{\"name\":\"jackson\"}}", om.writeValueAsString(holder));
        Holder<?> readBack = om.readValue(om.writeValueAsString(holder), new HolderChildReference());
        // In Jackson 2.11.2, this is true, but in 2.11.3, 'value' has been unmarshalled as a plain LinkedHashMap
        // instead ? Seems to be the fact the JsonCreator is a public 'of' method rather than constructor
        Assertions.assertTrue(readBack.getValue() instanceof TypedChild);
    }

    private static class HolderChildReference extends TypeReference<Holder<TypedChild>> {}

    public static class Holder<V> {
        private V value;
        
        private Holder(V value) {
            this.value = value;
        }

        // Use this as the constructor instead, and the test passes in both 2.11.2 and 2.11.3.
        /*@JsonCreator
        private Holder(@JsonProperty("value") V value) {
            this.value = value;
        }*/

        public V getValue() {
            return value;
        }

        @JsonCreator
        public static <V> Holder<V> of(@JsonProperty("value") V value) {
            return new Holder<>(value);
        }
    }

    public static class TypedChild {
        private String name;
        
        @JsonCreator
        public TypedChild(@JsonProperty("name") String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }
}

Expected behavior
The unmarshalled JSON uses the passed type reference information when unmarshalling the child object, so that the unit test passes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions