Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson polymorphic deserialization on integer fields instead of strings

Tags:

java

json

jackson

I'm familiar with the normal polymorphic deserialization stuff where you deserialize an object based on the string value of a certain field. For instance:

@JsonSubTypes(
          {
              @JsonSubTypes.Type(value = LionCage.class, name = "LION"),
              @JsonSubTypes.Type(value = TigerCage.class, name = "TIGER"),
          }
         )
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")

Is there any way to do basically the same thing if the "type" field of the incoming object is an integer instead of a string? So in the example above, "LION" and "TIGER" would be 1 and 2. For whatever reason, I haven't been able to figure this out.

Also, how should I have been able to figure this out? Seems like it should be something obvious.

like image 745
secureboot Avatar asked Jul 11 '14 02:07

secureboot


2 Answers

Jackson automatically converts string to numbers and vice versa. Just use string values for numbers. Like "1" for 1 value. Just try this yourself (jackson version is 2.5.1):

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;

public class HelloWorldJacksonNumber {

    public static class A extends Base {
        String a;
    }

    public static class B extends Base {
        String b;
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
    @JsonSubTypes({
            @JsonSubTypes.Type(value = A.class, name = "1"),
            @JsonSubTypes.Type(value = B.class, name = "2")})
    public static class Base {
        int type;
    }

    public static void main (String[] args) throws Exception {
        final ObjectMapper objectMapper = new ObjectMapper();
        System.out.println(objectMapper.version());

        System.out.println(objectMapper.writeValueAsString(new A()));
        System.out.println(objectMapper.writeValueAsString(new B()));

        System.out.println(objectMapper.readValue("{\"type\":\"1\"}", Base.class).getClass());
        System.out.println(objectMapper.readValue("{\"type\":\"2\"}", Base.class).getClass());
    }
}

Output is:

2.5.1
{"type":"1"}
{"type":"2"}
class HelloWorldJacksonNumber$A
class HelloWorldJacksonNumber$B
like image 149
Cherry Avatar answered Sep 23 '22 12:09

Cherry


No, that's not an option via the annotations. The TypeIdResolver interface takes and returns strings. You could do it with a custom parser/serializer using Jackson's stream API, but that seems like a lot of work to switch it to numeric field. I would only do it if someone else's system required it. If I owned the whole thing, I would just use the setup you posted in the question.

like image 30
toadzky Avatar answered Sep 23 '22 12:09

toadzky