0xTTEPX

Just do it, deeply...

Follow me on GitHub

基于Xstream的Xml工具类

write by donaldhan, 2017-12-06 16:20
xml

实战演练

maven依赖

我们通过一个xml工具类来看,首先引入Xstream maven依赖。

<dependency>
	<groupId>com.thoughtworks.xstream</groupId>
	<artifactId>xstream</artifactId>
	<version>1.4.8</version>
</dependency>

转换器

我们先来看一个Double类型转换器:

/**
 * @author donald
 * @date 2017-12-6
 * @time 下午2:55:55
 */
public class DoubleExtConverter extends AbstractSingleValueConverter {
	private static NumberFormat  numberFormat = NumberFormat.getInstance();
	static{
		numberFormat.setGroupingUsed(false);
		numberFormat.setMaximumFractionDigits(6);
		numberFormat.setMinimumFractionDigits(6);
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
		return type.isAssignableFrom(Double.class);
	}
	@Override
	public String toString(Object obj) {
		return obj != null ? numberFormat.format(obj) : null;
	}
	@Override
	public Object fromString(String str) {
		Double obj = null;
		if (StringHelper.isNotBlank(str) && !str.equals("")) {
			obj = Double.valueOf(str);
		}
		return obj;
	}
}


我们为什么要继承 AbstractSingleValueConverter 呢?我们来看一下 AbstractSingleValueConverter 定义。

public abstract class AbstractSingleValueConverter implements SingleValueConverter {
    public abstract boolean canConvert(Class type);
    public String toString(Object obj) {
        return obj == null ? null : obj.toString();
    }
    public abstract Object fromString(String str);

}

再来看 SingleValueConverter 接口的定义。

public interface SingleValueConverter extends ConverterMatcher {
    /**
     * Marshals an Object into a single value representation.
     * @param obj the Object to be converted
     * @return a String with the single value of the Object or <code>null</code>
     */
    public String toString(Object obj);

    /**
     * Unmarshals an Object from its single value representation.
     * @param str the String with the single value of the Object
     * @return the Object
     */
    public Object fromString(String str);

}

SingleValueConverter 接口有两个方法一个是 toString ,一个是 fromStringtoString 方法用于将bean属性转化为String写到xml中,fromString用于从xml中读取属性字符串转换为bean的属性。从上面的分析可以导出,想要处理bean和xml转换过程中,非 String 类型,可以实现 AbstractSingleValueConverter 重写 toStringfromString 方法,具体转换器可以参考官方网站converters

辅助工具类

为了自定义转换器我们需要先定义,辅助工具类。

字符串工具类

package util;

/**
 * @author donald
 * @date 2017-12-6
 * @time 下午2:52:01
 */
public class StringHelper {
	/**
	 * @param value
	 * @return
	 */
	public static boolean isBlank(String value){
		boolean isBlank = false;
		if(value == null || value.equals("")){
			isBlank = true;
		}
		return isBlank;
	}
	/**
	 * @param value
	 * @return
	 */
	public static boolean isNotBlank(String value){
		return !isBlank(value);
	}
}

时间工具类

package util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author donald
 * 2017年12月6日
 * 下午4:12:18
 */
public class DateUtil {
	private static final Logger log = LoggerFactory.getLogger(DateUtil.class);
	private final static SimpleDateFormat sdfDay = new SimpleDateFormat("yyyy-MM-dd");
	private final static SimpleDateFormat sdfTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	/**
	 * 获取YYYY-MM-DD HH:mm:ss格式
	 *
	 * @return
	 */
	public static String getTime() {
		return sdfTime.format(new Date());
	}
	/**
	 * 获取YYYY-MM-DD HH:mm:ss格式
	 * @param date
	 * @return
	 */
	public static String getTime(Date date) {
		return sdfTime.format(date);
	}
	/**
	 * 格式化日期
	 *
	 * @return
	 */
	public static Date formatDate(String date) {
		Date result = null;
		try {
			result = sdfDay.parse(date);
		} catch (ParseException e) {
			log.error("格式化日期出错",e);
		}
		return result;
	}
	/**
	 * @param date
	 * @return
	 */
	public static Date formatTime(String date) {
		Date result = null;
		try {
			result = sdfTime.parse(date);
		} catch (ParseException e) {
			log.error("格式化时间出错",e);
		}
		return result;
	}
}

转换器实现

我们这篇文章仅实现 Date,Integer,Double 转换器,Xstream 其实,已经有 Date,Integer,Double 等Java原始类型的转换器,但处理null有问题,下面定制 Date,Integer,Double 转换器。

日期转换器

package util.converter;

import java.util.Date;

import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;

import util.DateUtil;
import util.StringHelper;

/**
 * @author donald
 * @date 2017-12-6
 * @time 下午2:55:48
 */
public class DateExtConverter extends AbstractSingleValueConverter {

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public boolean canConvert(Class type) {
		return type.isAssignableFrom(Date.class);
	}
	@Override
	public String toString(Object obj) {
		return obj != null ? DateUtil.getTime((Date)obj) : null;
	}

	@Override
	public Object fromString(String str) {
		Date date = null;
		if (StringHelper.isNotBlank(str)) {
			date = DateUtil.formatTime(str);
		}
		return date;
	}

}

Integer转换器

package util.converter;
import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;

/**
 * @author donald
 * @date 2017-12-6
 * @time 下午2:55:55
 */
public class IntegerExtConverter extends AbstractSingleValueConverter {

	@SuppressWarnings("unchecked")
	public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
		return type.isAssignableFrom(Integer.class);
	}
	@Override
	public String toString(Object obj) {
		return obj != null ? String.valueOf(obj) : null;
	}
	@Override
	public Object fromString(String str) {
		Integer obj = null;
		if (StringHelper.isNotBlank(str) && !str.equals("")) {
			obj = Integer.valueOf(str);
		}
		return obj;
	}
}

Xml工具类

在上一节,我们定制了Date,Integer,Double 转换器,我们将这些转换器注册到XStream中,具体如下:

package util;

import java.util.Map;
import java.util.Map.Entry;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

import util.converter.DateExtConverter;
import util.converter.DoubleExtConverter;
import util.converter.IntegerExtConverter;
/**
 * 对象与Xml字符串转化工具
 * @author donald
 * 2017年7月8日
 * 下午5:15:19
 */
public class XmlUtil {
	private static final XStream xstream;
	/** xml文件头*/
	public static final String XML_HEADER =  "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
	static {
		xstream = new XStream(new DomDriver("utf-8"));
		xstream.registerConverter(new DoubleExtConverter());
		xstream.registerConverter(new DateExtConverter());
		xstream.registerConverter(new IntegerExtConverter());
        xstream.autodetectAnnotations(true);
	}


	/**
	 * 转化对象为Xml字符串
	 * @param obj
	 * @return
	 */
	public static String toXml(Object obj) {
		xstream.processAnnotations(obj.getClass()); //处理XSteam注解
		return xstream.toXML(obj);
	}
	/**
	 * 转化对象为Xml字符串,并添加字符串
	 * @param obj
	 * @return
	 */
	public static String toXmlWithHeader(Object obj) {
		return XML_HEADER + toXml(obj);
	}
    /**
     * 转化XML为指定类
     * @param xmlStr
     * @param cls
     * @return
     */
	@SuppressWarnings("unchecked")
	public static <T> T toBean(String xmlStr, Class<T> clazz) {
		xstream.processAnnotations(clazz);
		T obj = (T) xstream.fromXML(xmlStr);
		return obj;
	}
    /**
     * 转化XML为指定类,并将转换别与类的映射关系
     * @param xmlStr
     * @param clazz
     * @param aliasMap,别名与类的映射,将别名转换为类
     * @return
     */
	public static <T> T toBeanWithAlias(String xmlStr, Class<T> clazz, Map<String, Class<?>> aliasMap) {
		xstream.processAnnotations(clazz);
		if(null != aliasMap && 0 < aliasMap.size()) {
			for (Entry<String, Class<?>> entry : aliasMap.entrySet()) {
				xstream.alias(entry.getKey(), entry.getValue());
			}
		}
		@SuppressWarnings("unchecked")
		T obj = (T) xstream.fromXML(xmlStr);
		return obj;
	}
}

测试

准备工作已完成,现在我们来测试一下,创建测试实体类:

package util.entity;

import java.io.Serializable;
import java.util.Date;

import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("person")
public class Person implements Serializable{

	/**
	 *
	 */
	private static final long serialVersionUID = -5680738148261277921L;
	private String name;
	private Integer age;
	private Date birthDay;
	private Double stature;

	public Person(String name, Integer age, Date birthDay, Double stature) {
		super();
		this.name = name;
		this.age = age;
		this.birthDay = birthDay;
		this.stature = stature;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Date getBirthDay() {
		return birthDay;
	}
	public void setBirthDay(Date birthDay) {
		this.birthDay = birthDay;
	}
	public Double getStature() {
		return stature;
	}
	public void setStature(Double stature) {
		this.stature = stature;
	}
}

创建测试类:

package util;

import static org.junit.Assert.*;

import java.util.Date;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import util.entity.Person;

/**
 * @author donald
 * 2017年12月6日
 * 下午9:48:29
 */
public class XmlUtilTests {
	private static final Logger log = LoggerFactory.getLogger(XmlUtilTests.class);
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testToXml() {
		Person person = new Person("donald",23,new Date(),178.6);
		String result = XmlUtil.toXmlWithHeader(person);
		log.info("person to xml:\n{}",result);
		/*
		String expXml =
		"<?xml version=\"1.0\" encoding=\"utf-8\"?>"+
		"<person>"+
		  "<name>donald</name>"+
		  "<age>23</age>"+
		  "<birthDay>2017-12-06 21:50:25</birthDay>"+
		  "<stature>178.6</stature>"+
		"</person>";
		Assert.assertEquals("转换失败", expXml, result);
		*/
	}
	@Test
	public void testToBean() {
		String orgXml =
		"<?xml version=\"1.0\" encoding=\"utf-8\"?>"+
		"<person>"+
		  "<name>donald</name>"+
		  "<age></age>"+
		  "<birthDay>2017-12-06 21:50:25</birthDay>"+
		  "<stature></stature>"+
		"</person>";
		Person person = XmlUtil.toBean(orgXml, Person.class);
		log.info("to bean person:\n{}",XmlUtil.toXmlWithHeader(person));
	}
}

运行测试类,控制输出

[INFO ] 2017-12-06 21:58:53 util.XmlUtilTests person to xml:
<?xml version="1.0" encoding="utf-8"?>
<person>
  <name>donald</name>
  <age>23</age>
  <birthDay>2017-12-06 21:58:53</birthDay>
  <stature>178.6</stature>
</person>
[INFO ] 2017-12-06 21:58:53 util.XmlUtilTests to bean person:
<?xml version="1.0" encoding="utf-8"?>
<person>
  <name>donald</name>
  <birthDay>2017-12-06 21:50:25</birthDay>
</person>

至此,xml工具类测试完毕。

单元测试和日志组件jar maven依赖:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-log4j12</artifactId>
	<version>${slf4j.version}</version>
	<scope>compile</scope>
</dependency>
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
	<scope>test</scope>
</dependency>