如何正确使用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
相关产品推荐
相关产品推荐

