返回类型为标记接口时使用 Jackson 进行多态序列化

Posted

技术标签:

【中文标题】返回类型为标记接口时使用 Jackson 进行多态序列化【英文标题】:Polymorphic serialization using Jackson when return type is marker interface 【发布时间】:2016-03-12 05:26:50 【问题描述】:

我有一个返回标记接口的休息服务,这个接口有多个实现,并且在实现中没有任何公共属性。

    @RequestMapping(value = "/users/userName", method = RequestMethod.GET)
    public User getUser(@PathVariable("userName") String userName) 
        return userService.getUser(userName);
    

用户及其实现。注意:用户是标记接口。

public interface User 

public AdminUser implements User  // some properties & its setters & getters  

public SupportUser implements User  // some properties & its setters & getters  

我使用 Jackson 1.9.1 进行序列化和反序列化。

当我点击以上服务时,我得到以下响应


当我调试它时,我看到用户实现对象已准备好并发送回 Jackson 进行序列化。但是 jackson 正在向浏览器发送空响应。任何人都可以建议在返回类型为标记接口时如何使用序列化。

【问题讨论】:

【参考方案1】:

使用@JsonTypeInfo@JsonSubTypes反序列化多态类型,在序列化java对象的同时维护子类型信息并重新创建准确的子类型。

举个例子,animal 是一个接口,它可以是老虎或狮子,它们都扩展了 Animal 接口。在反序列化时,我们希望创建准确的动物类型并演示 @JsonTypeInfo 和 @JsonSubTypes 注释的使用。

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
        include=JsonTypeInfo.As.PROPERTY,
        property="name")
@JsonSubTypes(
        @JsonSubTypes.Type(value=Lion.class, name="lion"),
        @JsonSubTypes.Type(value=Tiger.class, name="tiger"),
)
public interface Animal 



@JsonTypeName("lion")
public class Lion implements Animal 

    private String name;
    private String roar;

//constructor & setters & getters


@JsonTypeName("tiger")
public class Tiger implements Animal 

    private String name;
    private String purr;

//constructor & setters & getters

主要方法:

List<Animal> animal = new ArrayList<Animal>();
animal.add(new Lion("lion", "roar"));
animal.add(new Tiger("tiger", "purr"));
animal.add(new Tiger("tiger", "purrrrrrrrr"));

URL url = JacksonPolymorphicSerialization.class.getClassLoader().getResource("animals.json");
File file = new File(url.getPath());

// de-serailization sub types
new ObjectMapper().writeValue(file, animal);

// serailization animals and its subtype
List<Animal> animals = new ObjectMapper().readValue(file, List.class);
System.out.println(animals);


output : [name=lion, roar=roar, name=tiger, purr=purr, name=tiger, purr=purrrrrrrr]

希望这有助于您了解使用 Jackson 对多态类型进行序列化和反序列化。

【讨论】:

没有其他人关心将基类耦合到他们的孩子吗? @KartikChugh 是的,我同意你的看法......创建这种耦合真的很糟糕。我找到了这个,肯定是一种最干净的方法。 ***.com/a/12688574/6400036 @KartikChugh 我想说在这种情况下是有道理的,只是普通的 OOP 设计。 @redigaffi 违反 SRP 和依赖倒置:en.wikipedia.org/wiki/SOLID【参考方案2】:

您可以使用@JsonTypeInfo 注释添加一个属性以在序列化/反序列化之间共享类型信息。 在这里阅读更多:JsonTypeInfo.html

【讨论】:

以上是关于返回类型为标记接口时使用 Jackson 进行多态序列化的主要内容,如果未能解决你的问题,请参考以下文章

Fastjson vs Jackson, Jackson配置Null时返回空值

Spring Mvc使用Jackson进行json转对象时,遇到的字符串转日期的异常处理(JSON parse error: Can not deserialize value of type jav

09.多态

基于唯一属性的存在用 Jackson 反序列化多态类型

Jackson 多态序列化生成不正确的类名

JAVA 重写&重载/多态/抽象类/封装/接口/包