如何正确使用XmlAdapter?
最近我需要把Java对象转换为XML文件格式,但直接使用JAXB转换Java对象并不能满足我的需求。
通过研究,我发现XmlAdapter可以用于自定义XML,但我不知道如何正确使用XmlAdapter来实现我的需求。
我期望的效果:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<head>
<a>a</a>
<b>b</b>
<c>c</c>
</head>
<body>
<d>d</d>
<e>e</e>
</body>
</root>
但像这样运行后的效果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<a>a</a>
<b>b</b>
<c>c</c>
<d>d</d>
<e>e</e>
</root>
以下是我的源代码,使用Java 8。
以下是我的目标类。
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "root")
public class MiddleRoot {
private Head head;
private Body body;
public MiddleRoot() {
}
public MiddleRoot(Head head, Body body) {
this.head = head;
this.body = body;
}
public Head getHead() {
return head;
}
public void setHead(Head head) {
this.head = head;
}
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}
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;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
}
static class Body{
private String d;
private String e;
public Body() {
}
public Body(String d, String e) {
this.d = d;
this.e = e;
}
public String getD() {
return d;
}
public void setD(String d) {
this.d = d;
}
public String getE() {
return e;
}
public void setE(String e) {
this.e = e;
}
}
}
以下是我的原始类。
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement(name = "root")
@XmlJavaTypeAdapter(RootAdapter.class)
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;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
public String getD() {
return d;
}
public void setD(String d) {
this.d = d;
}
public String getE() {
return e;
}
public void setE(String e) {
this.e = e;
}
}
以下是我的适配器类。
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class RootAdapter extends XmlAdapter<MiddleRoot,Root> {
@Override
public Root unmarshal(MiddleRoot v) throws Exception {
MiddleRoot.Head head = v.getHead();
MiddleRoot.Body body = v.getBody();
Root r = new Root();
if(head!=null){
r.setA(head.getA());
r.setB(head.getB());
r.setC(head.getC());
}
if(body!=null){
r.setD(body.getD());
r.setE(body.getE());
}
return r;
}
@Override
public MiddleRoot marshal(Root v) throws Exception {
MiddleRoot.Head head = new MiddleRoot.Head(v.getA(), v.getB(), v.getC());
MiddleRoot.Body body = new MiddleRoot.Body(v.getD(), v.getE());
return new MiddleRoot(head,body);
}
}
以下是我的 Test 类。
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 {
JAXBContext context = JAXBContext.newInstance(Root.class);
Root r = new Root("a","b","c","d","e");
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(r,System.out);
} catch (JAXBException e) {
System.out.println(e.getMessage());
}
}
}
这四个类都在同一个包中。如果我删除Root类上的 XmlRootElement,在运行时它会返回 null。
解决方案
问题在于你的 Root 类上有冲突的注解。
当你在同一个类上同时应用 @XmlRootElement 和 @XmlJavaTypeAdapter 时,JAXB不知道该走哪条路。@XmlRootElement 告诉JAXB “将这个类直接序列化为XML”,但适配器表示要先把这个类转换成其他形式。JAXB会变得困惑,选择了错误的路径。
首先:从Root类中移除 @XmlRootElement。
@XmlJavaTypeAdapter(RootAdapter.class)
public class Root {
// everything else stays the same
}
然后更新你的JAXBContext,使其同时包含这两个类。
JAXBContext.newInstance(Root.class, MiddleRoot.class);
然后当JAXB看到你的Root对象时,它将调用你的适配器把 Root 转换为 MiddleRoot。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。