XStream、JAXB 日期(Date)、数字(Number)格式化输出xml

时间:2022-04-23
本文章向大家介绍XStream、JAXB 日期(Date)、数字(Number)格式化输出xml,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

XStream、Jaxb是java中用于对象xml序列化/反序列化 的经典开源项目,利用它们将对象转换成xml时,经常会遇到日期(Date)、数字按指定格式输出的需求,下面是使用示例:

一、日期字段格式化输出

1.1 xStream

1 XStream x = new XStream();
2 x.registerConverter(new DateConverter("yyyy-MM-dd HH:mm:ss", null,TimeZone.getTimeZone("GMT+8")));

xStream默认使用UTC时间格式输出,上面的代码演示了如何按北京时间输出 yyyy-MM-dd HH:mm:ss 格式

1.2 jaxb

jaxb处理这个要麻烦一点,先要创建一个Adapter,下面是示例

 1 package com.cnblogs.yjmyzz.test;
 2 
 3 import java.text.DateFormat;
 4 import java.text.SimpleDateFormat;
 5 import java.util.Date;
 6 
 7 import javax.xml.bind.annotation.adapters.XmlAdapter;
 8 
 9 public class JaxbDateAdapter extends XmlAdapter<String, Date> {
10     static final String STANDARM_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
11 
12     @Override
13     public Date unmarshal(String v) throws Exception {
14         if (v == null) {
15             return null;
16         }
17 
18         DateFormat format = new SimpleDateFormat(STANDARM_DATE_FORMAT);
19         return format.parse(v);
20     }
21 
22     @Override
23     public String marshal(Date v) throws Exception {
24         DateFormat format = new SimpleDateFormat(STANDARM_DATE_FORMAT);
25         return format.format(v);
26     }
27 }

然后要处理的dto类,相应的Date字段的get方法上使用刚才这个Adapter

    @XmlJavaTypeAdapter(JaxbDateAdapter.class) 
    public Date getCreateDate() {
        return createDate;
    }

注:不要在private上使用,最好将注解打在get方法上,否则有可能报错。

这里,再给一个List<T>类型的常见用法: @XmlElementWrapper(name="details") @XmlElement(name="detail") public List<FSUDetail> getDetails() {     return details; } 如果没有这二个注解,xml的结果类似: <root> ...  <details>...</details>     <details>...</details> ... </root> 加上这二个注释后,xml的结果类似: <root> ... <details>         <detail>...</detail>         <detail>...</detail>     </details>   ... </root>

二、数字格式化

假设我们要将一个Double型的成员,按中国货币的格式输出

2.1 xStream

默认的DoubleConverter满足不了要求,得从它派生一个子类来重写toString(Object obj)方法

 1 package com.cnblogs.yjmyzz.test;
 2 
 3 import java.text.NumberFormat;
 4 import java.util.Locale;
 5 
 6 import com.thoughtworks.xstream.converters.basic.DoubleConverter;
 7 
 8 public class DoubleToCurrencyStringConverter extends DoubleConverter {
 9 
10     NumberFormat format;
11 
12     public DoubleToCurrencyStringConverter(Locale local) {
13         format = NumberFormat.getCurrencyInstance(local);
14     }
15 
16     public String toString(Object obj) {
17         return format.format(obj);
18     }
19 
20 }

然后这样使用:

1         XStream x = new XStream();
2         x.registerConverter(new DoubleToCurrencyStringConverter(Locale.CHINA));

2.2 Jaxb

仍然是按Adapter的老路,定义一个专用的Adapter

 1 package com.cnblogs.yjmyzz.test;
 2 
 3 import java.text.NumberFormat;
 4 import java.util.Locale;
 5 
 6 import javax.xml.bind.annotation.adapters.XmlAdapter;
 7 
 8 public class JaxbNumberAdapter extends XmlAdapter<String, Number> {
 9 
10     @Override
11     public Number unmarshal(String v) throws Exception {
12         if (v == null) {
13             return null;
14         }
15         NumberFormat format = NumberFormat.getCurrencyInstance(Locale.CHINA);
16         return format.parse(v);
17     }
18 
19     @Override
20     public String marshal(Number v) throws Exception {        
21         NumberFormat format = NumberFormat.getCurrencyInstance(Locale.CHINA);
22         return format.format(v);
23     }
24 }

然后在相关的Double字段的get方法上,用注解使用这个Adapter

1     @XmlJavaTypeAdapter(JaxbNumberAdapter.class) 
2     public Double getAmount() {
3         return amount;
4     }

最后附一个完整的示例:

为演示效果,先定义一个Dto类:

 1 package com.cnblogs.yjmyzz.test;
 2 
 3 import java.io.Serializable;
 4 import java.util.Date;
 5 
 6 import javax.xml.bind.annotation.XmlRootElement;
 7 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 8 import com.thoughtworks.xstream.annotations.XStreamAlias;
 9 
10 @XmlRootElement(name = "sample")
11 @XStreamAlias("sample")
12 public class Sample implements Serializable{    
13     
14     private static final long serialVersionUID = -6271703229325404123L;
15 
16     private Double amount;
17     
18     
19     private Date createDate;
20 
21     @XmlJavaTypeAdapter(JaxbNumberAdapter.class) 
22     public Double getAmount() {
23         return amount;
24     }
25 
26     public void setAmount(Double amount) {
27         this.amount = amount;
28     }
29 
30     @XmlJavaTypeAdapter(JaxbDateAdapter.class) 
31     public Date getCreateDate() {
32         return createDate;
33     }
34 
35     public void setCreateDate(Date createDate) {
36         this.createDate = createDate;
37     }
38 
39 }

同时为了使用jaxb更方便,定义一个JaxbUtil辅助类

 1 package com.cnblogs.yjmyzz.util;
 2 
 3 import java.io.StringReader;
 4 import java.io.StringWriter;
 5 
 6 import javax.xml.bind.JAXBContext;
 7 import javax.xml.bind.Marshaller;
 8 import javax.xml.bind.Unmarshaller;
 9 
10 public class JaxbUtil {
11 
12     public static String toXml(Object obj) {
13         return toXml(obj, "UTF-8", false);
14     }
15 
16     public static String toXml(Object obj, String encoding,
17             boolean isFormatOutput) {
18         String result = null;
19         try {
20             JAXBContext context = JAXBContext.newInstance(obj.getClass());
21             Marshaller marshaller = context.createMarshaller();
22             marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
23                     isFormatOutput);
24             marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
25 
26             StringWriter writer = new StringWriter();
27             marshaller.marshal(obj, writer);
28             result = writer.toString();
29         } catch (Exception e) {
30             e.printStackTrace();
31         }
32 
33         return result;
34     }
35 
36     @SuppressWarnings("unchecked")
37     public static <T> T toObject(String xml, Class<T> c) {
38         T t = null;
39         try {
40             JAXBContext context = JAXBContext.newInstance(c);
41             Unmarshaller unmarshaller = context.createUnmarshaller();
42             t = (T) unmarshaller.unmarshal(new StringReader(xml));
43         } catch (Exception e) {
44             e.printStackTrace();
45         }
46 
47         return t;
48     }
49 }

完整的单元测试如下:

 1 package com.cnblogs.yjmyzz.test;
 2 
 3 import java.util.Calendar;
 4 import java.util.Locale;
 5 import java.util.TimeZone;
 6 import org.junit.Test;
 7 import com.cnblogs.yjmyzz.util.JaxbUtil;
 8 import com.thoughtworks.xstream.converters.basic.DateConverter;
 9 import com.thoughtworks.xstream.XStream;
10 
11 public class XStreamAndJaxbTest {
12 
13     private Sample getSampleObj() {
14         Calendar c = Calendar.getInstance(Locale.CHINA);
15         c.set(2014, 9, 31, 0, 0, 0);
16         Sample obj = new Sample();
17         obj.setCreateDate(c.getTime());
18         obj.setAmount(1234.5678);
19         return obj;
20     }
21 
22     @Test
23     public void testXStream() {        
24         XStream x = new XStream();
25         x.alias("sample", Sample.class);        
26         x.registerConverter(new DateConverter("yyyy-MM-dd HH:mm:ss", null,
27                 TimeZone.getTimeZone("GMT+8")));        
28         x.registerConverter(new DoubleToCurrencyStringConverter(Locale.CHINA));
29         System.out.println("==> xstream ==>n");
30         System.out.println(x.toXML(getSampleObj()));
31         System.out.println("nn");
32     }
33 
34     @Test
35     public void testJaxb() {
36         System.out.println("==> jaxb ==>n");
37         System.out.println(JaxbUtil.toXml(getSampleObj(),"UTF-8",true));
38         System.out.println("nn");
39     }
40 
41 }

测试结果如下:

==> jaxb ==>

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <sample> <amount>¥1,234.57</amount> <createDate>2014-10-31 00:00:00</createDate> </sample>

==> xstream ==>

<sample> <amount>¥1,234.57</amount> <createDate>2014-10-31 00:00:00</createDate> </sample>