用来记录一些原创性的总结
在进行marshal和unmarshal的时候JAXB为我们提供了对应的监听器,允许我们在marshal和unmarshal的过程中对当前对象做一些操作或者记录一些日志等。
marshal过程中的监听器是对应的是Marshaller.Listener抽象类,其定义如下:
public static abstract class Listener {
public void beforeMarshal(Object source) {
}
public void afterMarshal(Object source) {
}
}
默认都是空实现,beforeMarshal方法用于在转换对象为XML之前回调,afterMarshal方法用于在转换对象为XML之后回调,参数source就是当前正在转换为XML的对象。监听器是通过Marshaller.setListener(Listener listener)
来指定的,其会对当前Marshaller进行的对象中的每一个复杂对象转换为XML时回调。假设有下面这样的类定义:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="root")
class OrgHolder {
private Org org;
public Org getOrg() {
return org;
}
public void setOrg(Org org) {
this.org = org;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
class Org {
private String no;
private String name;
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
我们期望在转换对象为XML时记录转换过程,所以定义了如下这样的监听器:
class GlobalMarshalListener extends Marshaller.Listener {
@Override
public void beforeMarshal(Object source) {
System.out.println("马上要被marshal的对象是:" + source);
}
@Override
public void afterMarshal(Object source) {
System.out.println("刚刚被marshal的对象是:" + source);
}
}
运行如下测试程序:
@Test
public void test() throws Exception {
OrgHolder holder = this.buildOrgHolder();
JAXBContext jaxbContext = JAXBContext.newInstance(OrgHolder.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setListener(new GlobalMarshalListener());//指定Listener,全局的,对当前Marshaller中所有的对象marshal都起作用
StringWriter writer = new StringWriter();
marshaller.marshal(holder, writer);
}
private OrgHolder buildOrgHolder() {
OrgHolder holder = new OrgHolder();
Org org = new Org();
org.setNo("A001");
org.setName("XXX");
holder.setOrg(org);
return holder;
}
我们会看到如下这样的输出:
马上要被marshal的对象是:com.elim.learn.basic.jaxb.OrgHolder@5577140b
马上要被marshal的对象是:com.elim.learn.basic.jaxb.OrgHolder@5577140b
马上要被marshal的对象是:com.elim.learn.basic.jaxb.Org@1c6b6478
刚刚被marshal的对象是:com.elim.learn.basic.jaxb.Org@1c6b6478
刚刚被marshal的对象是:com.elim.learn.basic.jaxb.OrgHolder@5577140b
刚刚被marshal的对象是:com.elim.learn.basic.jaxb.OrgHolder@5577140b
从输出中我们可以看到根对应的marshal过程中对应的监听器方法被调用了两次,这应该是一个bug,所以需要确保监听器中进行的操作是幂等的。
unmarshal过程中设置的监听器是Unmarshaller.Listener,其定义如下:
public static abstract class Listener {
public void beforeUnmarshal(Object target, Object parent) {
}
public void afterUnmarshal(Object target, Object parent) {
}
}
beforeUnmarshal方法将在当前对象被实例化,但是在XML转换为对象前调用,afterUnmarshal方法将在XML转换为对象后调用。参数target是当前正在被unmarshal的对象,parent是持有当前对象的引用的对象,即所谓的父对象。unmarshal过程中使用的Listener的示例如下:
class GlobalUnmarshalListener extends Unmarshaller.Listener {
@Override
public void beforeUnmarshal(Object target, Object parent) {
System.out.println("马上要被unmarshal的对象是:" + target + ",该对象的父级对象是:" + parent);
}
@Override
public void afterUnmarshal(Object target, Object parent) {
System.out.println("刚刚被unmarshal的对象是:" + target + ",该对象的父级对象是:" + parent);
}
}
测试代码如下:
@Test
public void test() throws Exception {
OrgHolder holder = this.buildOrgHolder();
JAXBContext jaxbContext = JAXBContext.newInstance(OrgHolder.class);
Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter writer = new StringWriter();
marshaller.marshal(holder, writer);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setListener(new GlobalUnmarshalListener());
unmarshaller.unmarshal(new StringReader(writer.toString()));
}
输出如下:
马上要被unmarshal的对象是:com.elim.learn.basic.jaxb.OrgHolder@26ba2a48,该对象的父级对象是:null
马上要被unmarshal的对象是:com.elim.learn.basic.jaxb.Org@5f2050f6,该对象的父级对象是:com.elim.learn.basic.jaxb.OrgHolder@26ba2a48
刚刚被unmarshal的对象是:com.elim.learn.basic.jaxb.Org@5f2050f6,该对象的父级对象是:com.elim.learn.basic.jaxb.OrgHolder@26ba2a48
刚刚被unmarshal的对象是:com.elim.learn.basic.jaxb.OrgHolder@26ba2a48,该对象的父级对象是:null
Unmarshaller.Listener和Marshaller.Listener作用的都是当前unmarshal或marshal中对应的所有的对象,对每个对象进行转换时都将进行调用,如果我们只是希望对某个具体的对象进行转换时进行监听,则可以使用实例级别的监听,此种用法可以参考下一篇文章的介绍。
(注:本文由Elim写于2017年9月18日)