Skip to content

Deserialization Not Working Right with Generic Types and Builders #921

@gilbode

Description

@gilbode

When trying to deserialize a generic type using a builder it is deserializing the generic type as a LinkedHashMap instead of the proper type, exact same code deserialized using @JsonCreator works fine. There seems to be something missing in the builder code.
Test case below demonstrates the problem:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;

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;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import org.junit.Test;

import java.util.List;

public class JacksonDeserTest {
  public static class MyPOJO {
    public String x;
    public String y;

    @JsonCreator
    public MyPOJO(@JsonProperty("x") String x, @JsonProperty("y") String y) {
      this.x = x;
      this.y = y;
    }
  }

  @JsonDeserialize(builder = MyGenericPOJO.Builder.class)
  public static class MyGenericPOJO<T> {
    private List<T> data;

    private MyGenericPOJO(List<T> data) {
      this.data = data;
    }

    public List<T> getData() {
      return data;
    }

    public static class Builder<T> {
      private List<T> data;

      public Builder<T> withData(List<T> data) {
        this.data = data;
        return this;
      }

      public MyGenericPOJO<T> build() {
        return new MyGenericPOJO<T>(data);
      }
    }
  }

  public static class MyGenericPOJOWithCreator<T> {
    private List<T> data;

    private MyGenericPOJOWithCreator(List<T> data) {
      this.data = data;
    }

    @JsonCreator
    public static <T> MyGenericPOJOWithCreator<T> create(@JsonProperty("data") List<T> data) {
      return new MyGenericPOJOWithCreator.Builder<T>().withData(data).build();
    }

    public List<T> getData() {
      return data;
    }

    public static class Builder<T> {
      private List<T> data;

      public Builder<T> withData(List<T> data) {
        this.data = data;
        return this;
      }

      public MyGenericPOJOWithCreator<T> build() {
        return new MyGenericPOJOWithCreator<T>(data);
      }
    }
  }

  @Test
  public void testWithBuilder() throws Exception {
    final ObjectMapper mapper = new ObjectMapper();
    final String json = "{ \"data\": [ { \"x\": \"x\", \"y\": \"y\" } ] }";
    final MyGenericPOJO<MyPOJO> deserialized =
        mapper.readValue(json, new TypeReference<MyGenericPOJO<MyPOJO>>() {});
    assertThat(deserialized.data, hasSize(1));
    assertThat(deserialized.data.get(0), instanceOf(MyPOJO.class));

  }

  @Test
  public void testWithCreator() throws Exception {
    final ObjectMapper mapper = new ObjectMapper();
    final String json = "{ \"data\": [ { \"x\": \"x\", \"y\": \"y\" } ] }";
    final MyGenericPOJOWithCreator<MyPOJO> deserialized =
        mapper.readValue(json, new TypeReference<MyGenericPOJOWithCreator<MyPOJO>>() {});
    assertThat(deserialized.data, hasSize(1));
    assertThat(deserialized.data.get(0), instanceOf(MyPOJO.class));

  }
}

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