0

0

Jackson XML序列化多态列表元素:实现自定义标签名

DDD

DDD

发布时间:2025-08-04 17:06:11

|

686人浏览过

|

来源于php中文网

原创

Jackson XML序列化多态列表元素:实现自定义标签名

本文探讨了如何使用Jackson库将包含多态元素的列表序列化为XML,并为列表中的每个不同类型元素生成其对应的类名作为XML标签。针对Jackson默认行为无法满足此需求的问题,文章详细介绍了通过实现自定义JsonSerializer来精确控制XML输出结构的方法。同时,文章也指出了这种自定义方案可能带来的局限性,特别是在牺牲Jackson内置的多态类型信息处理能力(如JsonTypeInfo)方面的权衡。

理解Jackson XML序列化多态列表的挑战

在使用jackson将java对象序列化为xml时,当一个类包含一个多态类型的列表(例如list,其中animal有dog和cat等子类)时,默认的序列化行为可能不会按照预期生成xml标签。

考虑以下Java类结构:

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.ArrayList;
import java.util.List;

// 抽象基类
abstract class Animal {}

// 子类,并指定XML根元素名称
@JacksonXmlRootElement(localName = "Dog")
class Dog extends Animal {}

@JacksonXmlRootElement(localName = "Cat")
class Cat extends Animal {}

// 包含多态列表的类
@JacksonXmlRootElement(localName = "Zoo")
public class Zoo {
  @JacksonXmlProperty
  @JacksonXmlElementWrapper(useWrapping = false) // 禁用列表包装,避免额外的标签
  List animals = new ArrayList<>();
}

当我们尝试序列化一个Zoo实例时:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

public class SerializationDemo {
  public static void main(String[] args) throws JsonProcessingException {
    Zoo zoo = new Zoo();
    zoo.animals.add(new Dog());
    zoo.animals.add(new Cat());
    zoo.animals.add(new Dog());

    XmlMapper mapper = new XmlMapper();
    String xml = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(zoo);
    System.out.println(xml);
  }
}

我们期望的XML输出是这样的:


  
  
  

然而,实际输出却是:


  
  
  

尽管我们使用了@JacksonXmlRootElement来指定Dog和Cat的根元素名,并在Zoo类的animals字段上使用了@JacksonXmlElementWrapper(useWrapping = false)来移除默认的包装器,Jackson在处理列表中的多态元素时,仍然无法自动识别并使用其运行时类型的类名作为XML标签。这是因为Jackson在序列化列表元素时,默认情况下不会为每个元素动态地查找其@JacksonXmlRootElement注解,尤其是在没有显式类型信息提示的情况下。

解决方案:自定义JsonSerializer

为了实现期望的XML输出,我们需要通过实现一个自定义的JsonSerializer来精确控制序列化过程。这种方法允许我们遍历列表中的每个元素,并根据其运行时类型动态地生成相应的XML标签。

首先,我们需要在Zoo类上应用@JsonSerialize注解,指定使用我们自定义的序列化器:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.ArrayList;
import java.util.List;

// Animal, Dog, Cat 类保持不变

@JsonSerialize(using = ZooSerializer.class) // 指定使用自定义序列化器
@JacksonXmlRootElement(localName = "Zoo")
public class Zoo {
  @JacksonXmlProperty
  @JacksonXmlElementWrapper(useWrapping = false)
  List animals = new ArrayList<>();
}

接下来,创建自定义的ZooSerializer类:

Narration Box
Narration Box

Narration Box是一种语音生成服务,用户可以创建画外音、旁白、有声读物、音频页面、播客等

下载
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;

public class ZooSerializer extends StdSerializer {

    // 构造函数
    public ZooSerializer() {
        this(null);
    }

    public ZooSerializer(Class t) {
        super(t);
    }

    @Override
    public void serialize(Zoo zoo, JsonGenerator jg, SerializerProvider sp) throws IOException {
        jg.writeStartObject(); // 写入  标签的开始
        for (Animal animal : zoo.animals) {
            // 获取动物的简单类名(如 "Dog", "Cat")
            String tagName = animal.getClass().getSimpleName();
            // 写入一个空字段,其名称即为动物的类名,从而生成  标签
            jg.writeNullField(tagName);
        }
        jg.writeEndObject(); // 写入  标签的结束
    }
}

在ZooSerializer的serialize方法中,我们执行以下操作:

  1. jg.writeStartObject():这会生成Zoo对象的开始标签,即
  2. 遍历zoo.animals列表中的每个Animal对象。
  3. 对于每个animal,我们通过animal.getClass().getSimpleName()获取其运行时类型的简单名称(例如,如果animal是Dog的实例,则获取"Dog")。
  4. jg.writeNullField(tagName):这是关键步骤。它会创建一个XML元素,其名称为tagName,并且由于它是“null field”,Jackson会将其序列化为自闭合标签,例如
  5. jg.writeEndObject():这会生成Zoo对象的结束标签,即。

使用此自定义序列化器后,再次运行序列化代码,将得到期望的XML输出:


  
  
  

注意事项与权衡

虽然自定义JsonSerializer能够精确地控制XML输出格式,但这种方法也存在一些重要的局限性:

  1. 失去Jackson内置多态处理优势: Jackson提供了@JsonTypeInfo和@JsonSubTypes等注解,用于在JSON/XML中嵌入类型信息,从而实现自动的多态序列化和反序列化。使用自定义序列化器意味着你放弃了这些内置的便利性。例如,如果你需要将上述XML反序列化回Java对象,Jackson将无法自动识别标签对应的具体子类,因为自定义序列化器没有写入任何类型元数据。

  2. 需要自定义反序列化器: 如果你的应用需要支持XML到Java对象的反序列化,那么你将不得不编写一个对应的自定义JsonDeserializer来解析这些特定格式的XML标签,并将其映射回正确的Dog或Cat对象。这增加了代码的复杂性和维护成本。

  3. 通用性降低: 这种自定义序列化器是为特定的Zoo类和其animals列表量身定制的。如果你的应用程序中有许多类似的多态列表需要处理,你可能需要为每个列表编写类似的自定义序列化器,或者尝试设计一个更通用的解决方案(这通常会更复杂)。

总结

当Jackson的默认XML序列化行为无法满足特定需求,例如需要为多态列表中的每个元素生成其运行时类型作为XML标签时,实现自定义JsonSerializer是一种有效的解决方案。它提供了对XML输出格式的精细控制。然而,开发者在采用此方法前应充分权衡其利弊,特别是要考虑到它会牺牲Jackson内置的多态类型处理能力,并可能需要额外开发配套的自定义反序列化器。在大多数情况下,如果XML标签名称的精确控制不是强制要求,并且需要支持双向序列化/反序列化,那么优先考虑使用@JsonTypeInfo和@JsonSubTypes来利用Jackson强大的多态处理能力会是更优的选择。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

825

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

724

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

728

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

395

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

445

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

428

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16861

2023.08.03

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号