SpringBoot实现子类的反序列化示例代码

 更新时间:2019年08月06日 10:51:00   作者:别拿豆包不当干粮  
这篇文章主要给大家介绍了关于SpringBoot实现子类的反序列化的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用SpringBoot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

目标

在SpringBoot接口中,我们一般用@RequestBody类注解需要反序列化的对象,但是当存在多个子类的情况下,常规的反序列化不能满足需求,比如:

我们有一个类Exam用于表示一张试卷:

@Data
public class Exam {

 private String name;
 private List<Question> questions;
}

这里Question比较特殊,Question本身是一个抽象类,提供了一些通用的方法调用,实际子类有单选题、多选题、判断题多种情况

实现

SprintBoot内置的序列化是使用的Jackson,查阅文档后发现Jackson提供了@JsonTypeInfo和@JsonSubTypes这两个注解,搭配使用,可以根据指定的字段值来指定实例化中用到的具体的子类类型

这几个类的实际代码如下:

抽象基类Question:

@Data
@JsonTypeInfo(
  use = JsonTypeInfo.Id.NAME,
  include = JsonTypeInfo.As.EXISTING_PROPERTY,
  property = "type",
  visible = true)
@JsonSubTypes({
  @JsonSubTypes.Type(value = SingleChoiceQuestion.class, name = Question.SINGLE_CHOICE),
  @JsonSubTypes.Type(value = MultipleChoiceQuestion.class, name = Question.MULTIPLE_CHOICE),
  @JsonSubTypes.Type(value = TrueOrFalseQuestion.class, name = Question.TRUE_OR_FALSE),
})
public abstract class Question {

 protected static final String SINGLE_CHOICE = "single_choice";
 protected static final String MULTIPLE_CHOICE = "multiple_choice";
 protected static final String TRUE_OR_FALSE = "true_or_false";

 protected String type;
 protected String content;
 protected String answer;

 protected boolean isCorrect(String answer) {
  return this.answer.equals(answer);
 }
}

判断题TrueOrFalseQuestion:

@Data
@EqualsAndHashCode(callSuper = true)
public class TrueOrFalseQuestion extends Question {

  public TrueOrFalseQuestion() {
    this.type = TRUE_OR_FALSE;
  }
}

选择题ChoiceQuestion:

@Data
@EqualsAndHashCode(callSuper = true)
public abstract class ChoiceQuestion extends Question {

  private List<Option> options;

  @Data
  public static class Option {
    private String code;
    private String content;
  }
}

单选题SingleChoiceQuestion:

@Data
@EqualsAndHashCode(callSuper = true)
public class SingleChoiceQuestion extends ChoiceQuestion {

  public SingleChoiceQuestion() {
    this.type = SINGLE_CHOICE;
  }
}

多选题MultipleChoiceQuestion:

@Data
@EqualsAndHashCode(callSuper = true)
public class MultipleChoiceQuestion extends ChoiceQuestion {

  public MultipleChoiceQuestion() {
    this.type = MULTIPLE_CHOICE;
  }

  @Override
  public void setAnswer(String answer) {
    this.answer = sortString(answer);
  }

  @Override
  public boolean isCorrect(String answer) {
    return this.answer.equals(sortString(answer));
  }

  private String sortString(String str) {
    char[] chars = str.toCharArray();
    Arrays.sort(chars);
    return String.valueOf(chars);
  }
}

测试

接下来测试一下

定义一个接口,我们可以使用@RequestBody传入一个Exam对象,返回解析结果:

@RequestMapping(value = "/exam", method = RequestMethod.POST)
public List<String> parseExam(@RequestBody Exam exam) {
  List<String> results = new ArrayList<>();
  results.add(String.format("Parsed an exam, name = %s", exam.getName()));
  results.add(String.format("Exam has %s questions", exam.getQuestions().size())) 
  
  List<String> types = new ArrayList<>();
  for (Question question : exam.getQuestions()) {
    types.add(question.getType());
  }
  results.add(String.format("Questions types: %s", types.toString()));
  return results;
}

项目跑起来,调用接口测试一下:

curl -X POST \
 http://127.0.0.1:8080/exam/ \
 -H 'Content-Type: application/json' \
 -d '{
  "name":"一场考试",
  "questions": [
    {
      "type": "single_choice",
      "content": "单选题",
      "options": [
        {
          "code":"A",
          "content": "选项A"
        },{
          "code":"B",
          "content": "选项B"
        }],
      "answer": "A"
    },{
      "type": "multiple_choice",
      "content": "多选题",
      "options": [
        {
          "code":"A",
          "content": "选项A"
        },{
          "code":"B",
          "content": "选项B"
        }],
      "answer": "AB"
    },{
      "type": "true_or_false",
      "content": "判断题",
      "answer": "True"
    }]
}'

接口返回如下:

[
  "Parsed an exam, name = 一场考试",
  "Exam has 3 questions",
  "Questions types: [single_choice, multiple_choice, true_or_false]"
]

这里不同类型的question,type字段都能正确读取,表明反序列化过程中确实是调用了具体子类对应的类来进行实例化的。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

相关文章

  • 关于SpringSecurity的基本使用示例

    关于SpringSecurity的基本使用示例

    这篇文章主要介绍了关于SpringSecurity的基本使用示例,SpringSecurity 本质是一个过滤器链SpringSecurity 采用的是责任链的设计模式,它有一条很长的过滤器链,需要的朋友可以参考下
    2023-05-05
  • Java8如何将Array转换为Stream的实现代码

    Java8如何将Array转换为Stream的实现代码

    这篇文章主要介绍了Java8如何将Array转换为Stream的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 关于mybatis传入参数一直为null的问题

    关于mybatis传入参数一直为null的问题

    这篇文章主要介绍了关于mybatis传入参数一直为null的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • spring boot org.junit.jupiter.api不存在的解决

    spring boot org.junit.jupiter.api不存在的解决

    这篇文章主要介绍了spring boot org.junit.jupiter.api不存在的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • spring 整合mybatis后用不上session缓存的原因分析

    spring 整合mybatis后用不上session缓存的原因分析

    因为一直用spring整合了mybatis,所以很少用到mybatis的session缓存。什么原因呢?下面小编给大家介绍spring 整合mybatis后用不上session缓存的原因分析,需要的朋友可以参考下
    2017-02-02
  • java题解Leetcode 8字符串转换整数

    java题解Leetcode 8字符串转换整数

    这篇文章主要为大家介绍了java题解Leetcode 8字符串转换整数实现,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • 详解springcloud 基于feign的服务接口的统一hystrix降级处理

    详解springcloud 基于feign的服务接口的统一hystrix降级处理

    这篇文章主要介绍了详解springcloud 基于feign的服务接口的统一hystrix降级处理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-06-06
  • java项目中的多线程实践记录

    java项目中的多线程实践记录

    项目开发中对于一些数据的处理需要用到多线程,比如文件的批量上传,数据库的分批写入,大文件的分段下载等,主要涉及到多线程的一些知识,本文通过实例代码给大家介绍的非常详细,需要的朋友参考下
    2021-11-11
  • JAVA代码块你了解吗

    JAVA代码块你了解吗

    这篇文章主要介绍了举例说明Java中的代码块,包括静态属性和非静态属性以及构造函数等相关的执行先后,需要的朋友可以参考下
    2021-09-09
  • Idea里github的图形化操作配置方法

    Idea里github的图形化操作配置方法

    这篇文章主要介绍了Idea里github的图形化操作配置方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02

最新评论