用来记录一些原创性的总结
假设我们有下面这样一个User
类。
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class User {
private Integer id;
private String name;
private Date createTime;
//...忽略get/set方法
}
我们使用如下这样的测试代码把它的一个对象转换为XML。
@Test
public void test() throws Exception {
User user = new User();
user.setId(1);
user.setName("张三");
user.setCreateTime(new Date());
JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);//格式化XML
marshaller.marshal(user, System.out);
}
其生成的XML如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
<id>1</id>
<name>张三</name>
<createTime>2017-06-29T19:40:19.821+08:00</createTime>
</user>
我们可以看到其中的日期类型转换后的结果通常不是我们希望的,我们可能更希望它以yyyy-MM-dd HH:mm:ss
的方式进行转换。这个时候我们就可以使用XmlJavaTypeAdapter
注解了,它允许我们指定一个XmlAdapter
类的子类,这样对应的属性在转换为XML时会先通过指定的XmlAdapter
进行转换,转换后的结果再进行XML转换。除了可以作为Java对象转换XML时的适配器外,它也可以作为XML转换Java的适配器。XmlAdapter
中一共定义了两个抽象方法,marshal
和unmarshal
。marshal
用于Java对象转换XML,unmarshal
用于XML转换Java对象。XmlAdapter
上定义了两个泛型,第一个是Java转换XML时适配后返回的类型,第二个是原始的类型。所以我们如果需要把我们的java.util.Date
类型的属性以yyyy-MM-dd HH:mm:ss
格式进行输出,我们需要定义如下这样一个XmlAdapter
类。
public static class DateAdapter extends XmlAdapter<String, Date> {
private static final String FORMAT = "yyyy-MM-dd HH:mm:ss";
@Override
public Date unmarshal(String v) throws Exception {
if (v != null) {
return new SimpleDateFormat(FORMAT).parse(v);
}
return null;
}
@Override
public String marshal(Date v) throws Exception {
if (v != null) {
return new SimpleDateFormat(FORMAT).format(v);
}
return null;
}
}
需要注意的是在
XmlAdapter
中的marshal
和unmarshal
方法中需要注意参数为null的情形。
然后我们就可以在User
的createTime
属性上加上@XmlJavaTypeAdapter(DateAdapter.class)
。加上@XmlJavaTypeAdapter
后的结果如下所示。
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class User {
private Integer id;
private String name;
@XmlJavaTypeAdapter(DateAdapter.class)
private Date createTime;
//...省略get/set方法
}
然后我们使用如下代码进行测试:
@Test
public void test() throws Exception {
User user = new User();
user.setId(1);
user.setName("张三");
user.setCreateTime(new Date());
JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);//格式化XML
StringWriter writer = new StringWriter();
marshaller.marshal(user, writer);
String xml = writer.toString();
User user2 = JAXB.unmarshal(new StringReader(xml), User.class);
System.out.println(xml);
System.out.println(user2.getCreateTime());
}
在测试代码中我们先对User
对象进行marshal
操作,这个时候转换createTime
时会调用DateAdapter
类的marshal
方法。接着我们通过生成的XML进行了一次unmarshal
操作,这个时候会调用DateAdapter
的unmarshal
方法。unmarshal
后我们取了unmarshal
生成的User
对象的createTime
并进行输出。完整输出结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
<id>1</id>
<name>张三</name>
<createTime>2017-06-29 20:19:02</createTime>
</user>
Thu Jun 29 20:19:02 CST 2017
我们可以看到marshal
后的日期格式是我们期望的yyyy-MM-dd HH:mm:ss
,而unmarshal
时基于yyyy-MM-dd HH:mm:ss
也能正确的进行unmarshal
,转换为对应的java.util.Date
类型的对象。
(本文由Elim写于2017年6月29日)