manub
manub

Reputation: 4100

Jackson - deserialize into runtime specified class

I'm writing a class that uses Jackson to serialize/deserialize objects. At compile time I don't know which is the type of the objects I will be serializing/deserializing.

I read a couple of articles and questions about the usages of TypeReference and TypeFactory, however I'm still having some issues.

My class looks like (removed some irrelevant code):

public class JsonSerializer<T> {

  private ObjectMapper objectMapper;
  private TypeReference typeReference;

  @PostConstruct
  public void init() {
      objectMapper = new ObjectMapper();
      typeReference = new TypeReference<T>(){ };
  }

  // ...


  public Object decode(CachedData cachedData) {
    try {
        return objectMapper.readValue(cachedData.getData(), typeReference);
    } // ...
  }
}

And this is the snippet of code I'm using to test this:

public class SerializerTest {

  private JsonSerializer<Clazz> serializer;
  private ObjectMapper objectMapper = new ObjectMapper();
  private static final String CHARSET = "UTF-8";
  private Clazz data = generateData(); // creates a simple object

  @BeforeMethod
  public void beforeMethod() {
      serializer = new JsonSerializer<Clazz>();
      serializer.init();
  }

  // ...

  public void shouldDecodeDataCorrectly() throws Exception {
    CachedData cachedData = new CachedData(0, 
      objectMapper.writeValueAsString(data).getBytes(CHARSET), 
      CachedData.MAX_SIZE);

    Object object = serializer.decode(cachedData);
    assertEquals(data, object);
  }

  public static class Clazz {
    // POJO with getters and setters
  }

}

As far as I could understand, using typeReference should be enough to let know the deserializer that the value read from the byte stream should be put in a Clazz object. However, the object returned by the decode() method is still a Map, which I understand is the default class for deserializing.

I tried also changing the decode() method to return return objectMapper.readValue(cachedData.getData(), objectMapper.getTypeFactory().constructType(typeReference)), but I'm getting the same problem.

I'm quite sure it's something regarding the way I pass the type into the serializer, but I haven't been able so far to fix it. Thanks.

Upvotes: 0

Views: 5392

Answers (3)

StaxMan
StaxMan

Reputation: 116620

It is not quite clear what exactly you are trying to do: much of the code does not make change. Specifically usage of TypeReference is wrong: you can not use type variables with it, type must be concrete.

However, perhaps solution is simpler than you thought. If you can keep track of original Class, just store that (or name from clazz.getName()), and pass that when deserializing.

Upvotes: 1

Guido Simone
Guido Simone

Reputation: 7952

Based on the javadoc at http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/type/TypeReference.html here is how I would do it:

Remove the typeReference field from JsonSerializer

Modify the JsonSerializer.decode method to take a type reference as an argument

Pass the type reference as an argument

Object object = transcoder.decode(cachedData, new TypeReference<Clazz>() {});

BTW - "transcoder" should be "serializer"? Typo?

Upvotes: 0

Chris
Chris

Reputation: 5654

Did you check @JsonTypeInfo ? Please have a look at it's documentation.

Upvotes: 0

Related Questions