You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用XmlAdapter实现符合预期的JAXB XML序列化?

如何正确使用XmlAdapter实现符合预期的JAXB XML序列化?

嘿,我看了你的代码和问题,其实问题出在XmlAdapter的使用方式和JAXB注解的搭配上,原来的配置没有让JAXB正确触发适配器的转换逻辑,导致字段直接平铺了。我来一步步帮你修正:

问题分析

你给Root类加了@XmlRootElement和@XmlJavaTypeAdapter,但JAXB在处理根元素时,并没有走适配器的marshal方法,而是直接序列化Root自身的字段,所以才会生成没有<head>和<body>嵌套的XML。另外,你的MiddleRoot类里的head和body字段也缺少JAXB注解,就算适配器生效了,也可能无法正确生成嵌套元素。

解决方案步骤

1. 调整Root类的注解

移除Root类上的@XmlRootElement和@XmlJavaTypeAdapter,因为我们不需要把Root直接作为JAXB的根元素,而是通过适配器转换成MiddleRoot(它才是带正确嵌套结构的根元素):

public class Root {
    private String a;
    private String b;
    private String c;
    private String d;
    private String e;

    public Root() {}

    public Root(String a, String b, String c, String d, String e) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.e = e;
    }

    // 所有getter和setter保持不变
}

2. 完善MiddleRoot的JAXB注解

给MiddleRoot的head和body字段添加@XmlElement注解,明确指定生成的XML元素名,同时给内部类加上@XmlAccessorType(可选,让JAXB更方便访问字段):

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;

@XmlRootElement(name = "root")
@XmlAccessorType(XmlAccessType.FIELD)
public class MiddleRoot {

    @XmlElement(name = "head")
    private Head head;

    @XmlElement(name = "body")
    private Body body;

    public MiddleRoot() {}

    public MiddleRoot(Head head, Body body) {
        this.head = head;
        this.body = body;
    }

    // 所有getter和setter保持不变

    @XmlAccessorType(XmlAccessType.FIELD)
    static class Head{
        private String a;
        private String b;
        private String c;

        public Head() {}

        public Head(String a, String b, String c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }

        // 所有getter和setter保持不变
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    static class Body{
        private String d;
        private String e;

        public Body() {}

        public Body(String d, String e) {
            this.d = d;
            this.e = e;
        }

        // 所有getter和setter保持不变
    }
}

3. 修改测试类,手动触发适配器转换

原来的测试类直接序列化Root,现在我们先通过RootAdapter把Root转换成MiddleRoot,再序列化MiddleRoot(因为MiddleRoot才是JAXB能识别的带结构的根元素):

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class Test {

    public static void main(String[] args) {
        try {
            // 初始化MiddleRoot的JAXB上下文
            JAXBContext context = JAXBContext.newInstance(MiddleRoot.class);
            Root r = new Root("a","b","c","d","e");
            
            // 使用适配器将Root转换为MiddleRoot
            RootAdapter adapter = new RootAdapter();
            MiddleRoot middleRoot = adapter.marshal(r);

            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8");
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            // 序列化MiddleRoot,得到预期的XML结构
            marshaller.marshal(middleRoot, System.out);

        } catch (JAXBException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

为什么原来的代码不行?

  • 你给Root加了@XmlRootElement,JAXB会直接把它当作根元素序列化,忽略了@XmlJavaTypeAdapter的配置;
  • MiddleRoot的head和body字段没有@XmlElement注解,就算适配器生效,JAXB也无法正确生成嵌套的<head>和<body>元素;
  • 之前去掉Root的@XmlRootElement后返回null,是因为你初始化的是Root的JAXB上下文,但Root不是JAXB可识别的根元素,所以序列化失败。

现在运行修改后的代码,就能得到你预期的XML结构啦!

备注:内容来源于stack exchange,提问作者poll_Ff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 18:04:29