JAVA JSON databinding 的多态

JSON 在 REST API 的调用中越来越多的应用,如何表达多态是经常碰到的一个问题。

有三种方式解决这个问题

  • PROPERTYEXISTING_PROPERTY, POJO 映射为 JSON Object ,某一个字段表示类型。
  • WRAPPER_OBJECT POJO 映射为只有一个字段的 JSON Object ,字段名表示类型。
  • WRAPPER_ARRAY POJO 映射为两个元素的数组 ,前面的表示类型,后面的表示指值。

背景

@Data
static class  Zoo {
    private Animal leader;
    private Animal[] followers;
}

假设有一个 Zoo 类,里面包含了一个特殊的动物 leader,和一些动物 followers。下面的代码试图转换 JSON

public static void main(String[] args) throws IOException {
    Zoo zoo = new Zoo();
    zoo.setLeader(new Dog());
    zoo.setFollowers(new Animal[]{new Dog(), new Cat()});
    final ObjectMapper mapper = new ObjectMapper();
    final String json = mapper.writeValueAsString(zoo);
    System.out.println(json);
    final Zoo zoo2 = mapper.readValue(json, Zoo.class);
    System.out.println(zoo2);
}

例子 DogCat

static class Dog implements Animal {
    private String name = "wangwang";
    @Override
    public String getAnimalType() {
        return "dog";
    }

    @Override
    public String getName() {
        return name;
    }
    @Override
    public void setName(String name) {
        this.name = name;
    }
}
static class Cat implements Animal {
    private String name = "miao";

    @Override
    public String getAnimalType() {
        return "cat";
    }

    @Override
    public String getName() {
        return name;
    }
    @Override
    public void setName(String name) {
        this.name = name;
    }
}

把 POJO 映射称为 JSON Object , include = JsonTypeInfo.As.EXISTING_PROPERTY

include = JsonTypeInfo.As.PROPERTY 也类似,区别不大。

用字段 animalType 来表示类型信息。

{
  "leader": {
    "name": "wangwang",
    "animalType": "dog"
  },
  "followers": [
    {
      "name": "wangwang",
      "animalType": "dog"
    },
    {
      "name": "miao",
      "animalType": "cat"
    }
  ]
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "animalType")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Dog.class, name = "dog"),
        @JsonSubTypes.Type(value = Cat.class, name = "cat")})
@JsonIgnoreProperties(ignoreUnknown = true)
public interface Animal {
    String getAnimalType();
    String getName();
    void setName(String name);
}

这种类型还有很多变种。例如 use 可以选择 JsonTypeInfo.Id.CLASS 之类的。

把 POJO 映射称为数组 , include = JsonTypeInfo.As.WRAPPER_ARRAY

{
  "leader": [
    "dog",
    {
      "name": "wangwang",
      "animalType": "dog"
    }
  ],
  "followers": [
    [
      "dog",
      {
        "name": "wangwang",
        "animalType": "dog"
      }
    ],
    [
      "cat",
      {
        "name": "miao",
        "animalType": "cat"
      }
    ]
  ]
}

每个POJO 映射为一个两个元素的 JSON 数组,第一个元素表示类型,第二个元素表示真正的内容。

把 POJO 映射称为包装对象 nclude = JsonTypeInfo.As.WRAPPER_OBJECT

{
  "leader": {
    "dog": {
      "name": "wangwang",
      "animalType": "dog"
    }
  },
  "followers": [
    {
      "dog": {
        "name": "wangwang",
        "animalType": "dog"
      }
    },
    {
      "cat": {
        "name": "miao",
        "animalType": "cat"
      }
    }
  ]
}
{
  "leader": {
    "dog": {
      "name": "wangwang",
      "animalType": "dog"
    }
  },
  "followers": [
    {
      "dog": {
        "name": "wangwang",
        "animalType": "dog"
      }
    },
    {
      "cat": {
        "name": "miao",
        "animalType": "cat"
      }
    }
  ]
}

每个 POJO 映射为一个 只有一个 property 的 POJO Object ,这个 property name 表示类型信息。 property value 是 POJO 真正的内容。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,124评论 19 139
  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 11,207评论 0 4
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 33,395评论 18 399
  • 作者: weiyf时间: 2016-10-31 21:35:33原文链接:https://developer.an...
    卫裕发阅读 10,169评论 2 15
  • 我羡慕你有爱情,她对你百依百顺,你们有车有房有存款,你的生活有她打理,你的脾气有她安慰。我真的很羡慕那些情侣,可是...
    回首的背叛阅读 1,324评论 0 2

友情链接更多精彩内容