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("\n\n");
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("\n\n");
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>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程之旅

数据结构——二叉查找树(C语言)

二叉查找树,也称作二叉搜索树,有序二叉树,排序二叉树,而当一棵空树或者具有下列性质的二叉树,就可以被定义为二叉查找树:

1954
来自专栏desperate633

LeetCode 144. Binary Tree Preorder Traversal题目分析代码

Given a binary tree, return the preorder traversal of its nodes' values. For ex...

982
来自专栏10km的专栏

jface databinding:List,Set,Map对象的Observable代理封装

需求描述 对于一个已经存在的集合/映射对象(普通的List,Set,Map,非observable),我们希望把将它转换成一个observable对象,这个ob...

2176
来自专栏DHUtoBUAA

找出该树中第二小的值--思路及算法实现

  在二叉树中最重要的操作莫过于遍历,即按照某一顺序访问树中的所有节点。二叉树的前序遍历、中序遍历、后序遍历都有递归和循环两种不同的实现方法。每种遍历的递归实现...

3125
来自专栏格子的个人博客

Java源码阅读之TreeMap(红黑树) - JDK1.8

TreeMap实现了NavigableMap接口, 而NavigableMap则是通过sortedMap间接继承了Map接口,它定义了一系列导航方法,这些Map...

3443
来自专栏来自地球男人的部落格

[LeetCode] 78. Subsets

【原题】 Given a set of distinct integers, nums, return all possible subsets. Not...

2769
来自专栏码匠的流水账

聊聊storm nimbus的mkAssignments

storm-2.0.0/storm-server/src/main/java/org/apache/storm/daemon/nimbus/Nimbus.jav...

1242
来自专栏机器学习入门

LWC 54:699. Falling Squares

LWC 54:699. Falling Squares 传送门:699. Falling Squares Problem: On an infinite nu...

2205
来自专栏xiaoxi666的专栏

【模板小程序】任意长度非负十进制数转化为二进制(java实现)

2214
来自专栏Java爬坑系列

【Java入门提高篇】Day26 Java容器类详解(八)HashSet源码分析

  前面花了好几篇的篇幅把HashMap里里外外说了个遍,大家可能对于源码分析篇已经讳莫如深了。

1124

扫码关注云+社区

领取腾讯云代金券