将JSON反序列化为类型化类

时间:2014-06-16 11:32:13

标签: json generics jackson json-deserialization

我有一个基类和两个子库:

public /*abstract*/ class TargetPoi {
    private String poiId;
    ...
}

public class TargetSub1Poi extends TargetPoi {
    private String oneMoreId;
    ...
}

public class TargetSub2Poi extends TargetPoi {
    ...
}

是否可以声明基类抽象? ...如果我使用 abstract 关键字,当我发送带有请求的JSON时,我总是会遇到异常......

Exception Description: This class does not define a public default constructor, or the constructor raised an exception.
Internal Exception: java.lang.InstantiationException
Descriptor: XMLDescriptor(com.foo.bar.TargetPoi --> [])

当请求体中带有JSON的POST请求进入Jersy资源时,我想将JSON反序列化为正确的TargetPoi子类。 JSON:

{
"requestId": "84137f1ab38f4bf585d13984fc07c621",
"startTime": "2013-10-30T18:30:00+02:00",
"endTime": "2013-10-30T18:45:00+02:00",
"targetPoi": 
{
    "poiId": "0000000602",
    "oneMoreId": "1"
},
"type": "Block",
"notification": true
}

我的资源有一种以这种方式定义的方法......

@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response doReservation(final ReservationDO reservationDO
        , @QueryParam("serviceType") final String serviceType) {
...
}

JSON应在此类中反序列化:

@XmlRootElement
public class ReservationDO<T extends TargetPoi>
{
    public String           requestId;
    public String           startTime;
    public String           endTime;
    public String           serviceType;
    public T                targetPoi;
    ...
}

如何告诉Jackson将targetPoi的JSON正确绑定到正确的子类型(TargetSub1Poi)? serviceType 可以告诉我targetPoi要绑定到哪个子类型......但我认为这些信息不能用于Jackson,是吗?当我在edoreservation方法中打印出反序列化的JSON时,带有原始JSON的 oneMoreId 部分将丢失。

我是否必须提供任何TypeInfo,或者我可以在没有它的情况下实现它吗?

1 个答案:

答案 0 :(得分:0)

可以声明父类抽象并具有通用字段。您只需要告诉Jackson使用哪个子类型来创建对象的实例。可以使用the Jackson polymorphic deserialization wiki page中所述的@JsonTypeInfo注释来完成此操作。

以下是一个例子:

public class JacksonPoi {
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.PROPERTY, property = "type")
    public static abstract class TargetPoi {
        public String poiId;
    }

    @JsonTypeName("sub1")
    public static class TargetSub1Poi extends TargetPoi {
        public String oneMoreId;

        @Override
        public String toString() {
            return "TargetSub1Poi{" +
                    "poiId='" + poiId + '\'' +
                    "oneMoreId='" + oneMoreId + '\'' +
                    '}';
        }
    }

    @JsonTypeName("sub2")
    public static class TargetSub2Poi extends TargetPoi {
        public String twoMoreId;

        @Override
        public String toString() {
            return "TargetSub2Poi{" +
                    "poiId='" + poiId + '\'' +
                    "twoMoreId='" + twoMoreId + '\'' +
                    '}';
        }
    }

    public static class  Bean<T extends TargetPoi> {
        public String field;
        public T poi;

        @Override
        public String toString() {
            return "Bean{" +
                    "field='" + field + '\'' +
                    ", poi=" + poi +
                    '}';
        }
    }

    public static final String JSON = "{\n" +
            "\"poi\": \n" +
            "{\n" +
            "    \"type\": \"sub1\",\n" +
            "    \"poiId\": \"0000000602\",\n" +
            "    \"oneMoreId\": \"1\"\n" +
            "},\n" +
            "\"field\": \"value1\"\n" +
            "}";
    public static final String JSON2 = "{\n" +
            "\"poi\": \n" +
            "{\n" +
            "    \"type\": \"sub2\",\n" +
            "    \"poiId\": \"0000000602\",\n" +
            "    \"twoMoreId\": \"13\"\n" +
            "},\n" +
            "\"field\": \"value2\"\n" +
            "}";

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerSubtypes(TargetSub1Poi.class, TargetSub2Poi.class);
        Bean<TargetSub1Poi> poi1 = mapper.readValue(JSON, new TypeReference<Bean<TargetSub1Poi>>() {});
        System.out.println(poi1);
        Bean<TargetSub2Poi> poi2 = mapper.readValue(JSON2, new TypeReference<Bean<TargetSub2Poi>>() {});
        System.out.println(poi2);
    }
}

输出:

Bean{field='value1', poi=TargetSub1Poi{poiId='0000000602'oneMoreId='1'}}
Bean{field='value2', poi=TargetSub2Poi{poiId='0000000602'twoMoreId='13'}}