日常使用xstream进行xml转换的时候,会遇到实体对象中有null值的情况,默认的xstream转换遇见null值后不会生成节点xml信息,但是一般为了保证我们xml的可读和完整性,我们希望即使是null值也能够输出节点的xml,废话不说,上干货。
两个实体类:
/**
* Project Name:test
* File Name:User.java
* Package Name:dao
* Date:2014-5-16下午5:11:41
* Copyright (c) 2014, renxingchen All Rights Reserved.
*
*/
package dao;
import java.util.List;
import java.util.Set;
/**
* @ClassName: User
* @description: TODO ADD FUNCTION.
* @date: 2014-5-16 下午5:11:41
*
* @author renxingchen
* @since JDK 1.6
*/
public class User {
public User() {
}
public User(int id, String name, List<Order> orderList, Order order,
Set<Order> orderSet) {
super();
this.id = id;
this.name = name;
this.orderList = orderList;
this.order = order;
this.orderSet = orderSet;
}
private int id;
private String name;
private List<Order> orderList;
private Order order;
private Set<Order> orderSet;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public List<Order> getOrderList() {
return orderList;
}
public void setOrderList(List<Order> orderList) {
this.orderList = orderList;
}
public Set<Order> getOrderSet() {
return orderSet;
}
public void setOrderSet(Set<Order> orderSet) {
this.orderSet = orderSet;
}
}
/**
* Project Name:test
* File Name:Order.java
* Package Name:dao
* Date:2014-5-16下午5:11:41
* Copyright (c) 2014, renxingchen All Rights Reserved.
*
*/
package dao;
/**
* @ClassName: Order
* @description: TODO ADD FUNCTION.
* @date: 2014-5-16 下午5:13:09
*
* @author renxingchen
* @since JDK 1.6
*/
public class Order {
public Order() {
}
public Order(int id, String orderName) {
super();
this.id = id;
this.orderName = orderName;
}
private int id;
private String orderName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
}
自己的xstream转换器,目前可以处理包含Collection集合的对象,如果在实际使用中无法满足需求,可以对marshalSuper这个方法进行拓展即可。
/**
* Project Name:test
* File Name:MoreDataResultNullConverter.java
* Package Name:dao
* Date:2014-5-16下午5:11:41
* Copyright (c) 2014, renxingchen All Rights Reserved.
*
*/
package dao;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
/**
*
* @ClassName: MoreDataResultNullConverter
* @description: 处理含有null值对象的xstream转换器
* @date: 2014-5-19 下午6:05:12
*
* @author renxingchen
* @since JDK 1.6
*/
public class MoreDataResultNullConverter implements Converter {
@SuppressWarnings("rawtypes")
private Class currentType;
private final String clazzNames[] = { "User", "Order" };// 定义所要转换的对象及所包含的对象名称
private List<String> clazzNamesList;
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(Class type) {
currentType = type;
clazzNamesList = Arrays.asList(clazzNames);
if (clazzNamesList.contains(currentType.getSimpleName())) {
return true;
} else {
return false;
}
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
try {
marshalSuper(source, writer, context, currentType);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Object getObj(Class clazz, String nodeName, Object source)
throws Exception {
Method method = clazz.getMethod("get"
+ Character
.toUpperCase(nodeName.substring(0, 1).toCharArray()[0])
+ nodeName.substring(1));
Object obj = null;
obj = method.invoke(clazz.cast(source), new Object[0]);
return obj;
}
@SuppressWarnings({ "rawtypes" })
private void objConverter(Object source, HierarchicalStreamWriter writer,
MarshallingContext context, Class clazz, String nodeName,
Class fieldClazz) throws Exception {
Object obj = getObj(clazz, nodeName, source);
writer.startNode(nodeName);
marshalSuper(obj, writer, context, fieldClazz);
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void collectionConverter(Object source,
HierarchicalStreamWriter writer, MarshallingContext context,
Class clazz, String nodeName, Field field) throws Exception {
Type types[] = ((ParameterizedType) field.getGenericType())
.getActualTypeArguments();
Object obj = getObj(clazz, nodeName, source);
Collection collection = null;
if (field.getType().equals(List.class)) {
collection = (List) obj;
} else if (field.getType().equals(Set.class)) {
collection = (Set) obj;
}
writer.startNode(nodeName);
for (Object object : collection) {
String clazzName = ((Class) types[0]).getSimpleName();
writer.startNode(Character.toLowerCase(clazzName.substring(0, 1)
.toCharArray()[0]) + clazzName.substring(1));
marshalSuper(object, writer, context, (Class) types[0]);
writer.endNode();
}
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void basicTypeConverter(Object source,
HierarchicalStreamWriter writer, MarshallingContext context,
Class clazz, String nodeName) throws Exception {
Object obj = getObj(clazz, nodeName, source);
writer.startNode(nodeName);
writer.setValue(obj == null ? "" : obj.toString());
writer.endNode();
}
@SuppressWarnings({ "rawtypes" })
private void marshalSuper(Object source, HierarchicalStreamWriter writer,
MarshallingContext context, Class clazz) throws Exception {
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields) {
String nodeName = field.getName();
Class fieldClazz = field.getType();
if (clazzNamesList.contains(fieldClazz.getSimpleName())) {
objConverter(source, writer, context, clazz, nodeName,
fieldClazz);
} else if (Arrays.asList(fieldClazz.getInterfaces()).contains(
Collection.class)) {
collectionConverter(source, writer, context, clazz, nodeName,
field);
} else {
basicTypeConverter(source, writer, context, clazz, nodeName);
}
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
// TODO Auto-generated method stub
return null;
}
}
最后是测试类:
/**
* Project Name:wisdom-tourism
* File Name:Demo.java
* Package Name:dao
* Date:2014-5-16下午5:11:20
* Copyright (c) 2014, renxingchen All Rights Reserved.
*
*/
package dao;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;
/**
* ClassName:Demo <br/>
* Function: TODO ADD FUNCTION. <br/>
* Reason: TODO ADD REASON. <br/>
* Date: 2014-5-16 下午5:11:20 <br/>
*
* @author jason
* @version
* @since JDK 1.6
* @see
*/
public class Demo {
public static void main(String[] args) {
Order order = new Order(1, null);
Order order1 = new Order(2, null);
List<Order> orderList = new ArrayList<Order>();
Set<Order> orderSet = new HashSet<Order>();
orderList.add(order);
orderList.add(order1);
orderSet.add(order);
orderSet.add(order1);
User user = new User(1, null, orderList, order, orderSet);
XStream xStream = new XStream(new StaxDriver());
xStream.alias("user", User.class);
xStream.registerConverter(new MoreDataResultNullConverter());
String result = xStream.toXML(user);
System.err.println(result);
}
}
测试结果:
<?xml version='1.0' encoding='UTF-8'?>
<user>
<id>1</id>
<name></name>
<orderList>
<order>
<id>1</id>
<orderName></orderName>
</order>
<order>
<id>2</id>
<orderName></orderName>
</order>
</orderList>
<order>
<id>1</id>
<orderName></orderName>
</order>
<orderSet>
<order>
<id>1</id>
<orderName></orderName>
</order>
<order>
<id>2</id>
<orderName></orderName>
</order>
</orderSet>
</user>
null值属性的节点能够被输出。
仓促写成,应该还有很多问题,如果有疑问请留言交流。