Xstream处理XML⽣成中null值的复杂情况
前⼀段时间和Xstream打过交道,发现Xstream在⽀持json以及XML⽅⾯还是相当强⼤的。提供annotation注解,可以在JavaBean中完成对xml节点、属性的描述。在根据xsd转换为Xstream模型之后,希望利⽤Xstream来⽣成XML并且满⾜XSD要求。例如:
package nju.software.ExecutionInterfaces.service.XstreamModels;
l.bind.annotation.XmlAccessType;
l.bind.annotation.XmlAccessorType;
l.bind.annotation.XmlElement;
l.bind.annotation.XmlRootElement;
l.bind.annotation.XmlType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"userId",
"infoCode",
"departId"
})
@XmlRootElement(name = "info")
@XStreamAlias("info")
@Annotation(documentation="信息")
public class Info {
@XmlElement(name = "user_id")
@XStreamAlias("user_id")
@Annotation(documentation="⽤户ID")
protected int userId;
@XmlElement(name = "info_code", required = true)
@XStreamAlias("info_code")
@Annotation(documentation="信息密码")
protected String infoCode;
@XmlElement(name = "depart_id", required = true, type = Integer.class, nillable = true)
@XStreamAlias("depart_id")
@Annotation(documentation="部门ID")
protected Integer departId;
}
根据XSD⽣成的模型加上Xstream注解。利⽤xStream中toXML()⽅法将Model转换成XML字符串。预想是仅仅使⽤processAnnotations ⽅式注⼊注解就⾃动将XML中节点名称写好。但是⽣成的XML却⽆法通过XSD的验证。经过检查发现是xsd中类型设置的原因。⽐如departId字段。required = true, type = Integer.class, nillable = true,表⽰为Integer类型且可为空。但是当真正将值设为空时⼜通不过验证。因为XSD在检查数字类型的时候需要⾄少写⼀个0。<depart_id/>或者<depart_id></depart_id>都不⾏。于是想到了使⽤Xstream中的Converter接⼝。在园⼦⾥也看到了有关nullConverter的说明。在其基础上进⾏了修改。
import flect.Field;
import flect.Method;
import java.math.BigDecimal;
DecimalFormat;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.verters.Converter;
import com.verters.MarshallingContext;
import com.verters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
public class NullConverter implements Converter {
@SuppressWarnings("unchecked")
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
if (null == source)
return;
Class cType = Class();
Field[] fields = DeclaredFields();
if (source instanceof List) {
List list = (List) source;
for (Object obj : list) {
XStreamAlias alias = Class().getAnnotation(XStreamAlias.class);
if (alias != null) {bigdecimal转换为integer
writer.startNode(alias.value());
marshal(obj, writer, context);
}else {
marshal(obj, writer, context);
}
}
} else {
for (Field field : fields) {
//获得get⽅法
String temp1 = "get"
+ Name().substring(0, 1).toUpperCase()
+ Name().substring(1);
Method m = null;
try {
m = Method(temp1, null);
} catch (SecurityException e1) {
e1.printStackTrace();
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
}
String methodName = m.getName();
if (methodName.indexOf("get") != -1 && methodName != "getClass") {
boolean isBaseType = ReturnType());
String name = methodName.substring(3);
Object o = null;
try {
o = m.invoke(source, null);
} catch (Exception e) {
e.printStackTrace();
}
//递归打出基础类型值
if (isBaseType) {
writer.startNode(getAliasByNameAndType(name, cType).value());
writeData(o, m.getReturnType(), writer);
} else {
XStreamAlias alias = getAliasByNameAndType(name, cType);
if (alias == null) {
marshal(o, writer, context);
} else {
writer.startNode(alias.value());
marshal(o, writer, context);
}
}
}
}
}
}
/**
* 根据Name和类获得Xstream注解
* @param name
* Name
* @param cType
* 类
* @return
* XStreamAlias
*/
private XStreamAlias getAliasByNameAndType(String name,Class<?> cType){
String temp = name.substring(0, 1).toLowerCase()
+ name.substring(1);
Field f = null;
try {
f = DeclaredField(temp);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
XStreamAlias alias = f.getAnnotation(XStreamAlias.class);
return alias;
}
/**
* 改写输出XML
* @param o
* @param ReturnType
* @param writer
*/
private void writeData(Object o,Class<?> ReturnType,HierarchicalStreamWriter writer) {
//如果是数字类型的话就要预设为0⽽不能为空
if (isNumValueType(ReturnType)) {
if (o == null) {
writer.setValue("0");
}else if (ReturnType.equals(Double.class)||ReturnType.equals(double.class)||ReturnType.equals(BigDecimal.class)) { DecimalFormat df = new DecimalFormat("#.##");
writer.setValue(df.format(o));
}else {
writer.String());
}
} else {
writer.setValue(o == null ? "" : o.toString());
}
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
return null;
}
public boolean canConvert(Class type) {
return true;
}
/**
* 判断是否为基本类型
* @param type
* @return
* boolean
*/
private boolean isBaseType(Class<?> type) {
if (type.equals(Integer.class) || type.equals(Double.class)
|| type.equals(String.class) || type.equals(Boolean.class)
|| type.equals(Long.class) || type.equals(Short.class)
|| type.equals(Byte.class) || type.equals(Float.class)
|| type.equals(BigDecimal.class) || type.equals(int.class)
|| type.equals(float.class) || type.equals(long.class)
|| type.equals(double.class) || type.equals(short.class)
|| type.equals(boolean.class) || type.equals(byte.class)) {
return true;
}
return false;
}
/**
* 判断是否为数字类型
* @param type
* @return
* boolean
*/
public boolean isNumValueType(Class<?> type) {
if (type.equals(Integer.class) || type.equals(Double.class)
|| type.equals(Long.class) || type.equals(Short.class)
|| type.equals(Float.class) || type.equals(BigDecimal.class)
|| type.equals(int.class) || type.equals(float.class)
|| type.equals(long.class) || type.equals(double.class)
|| type.equals(short.class)) {
return true;
}
return false;
}
}
基本思想还是利⽤递归的思想,主要修改有这么⼏点:
1打出⼀个类中属性XML节点的⽅式。原始⽅式是通过拼接出get⽅法,便利获得属性上的Xstream注解⽣成。但是这样⽣成不能保证属性的顺序,于是改成getAliasByNameAndType⽅法中⾸先获得属性。根据属性拼接get⽅法。
2由于需求原因增加了数字类型的判断,并在输出时也做了判断。
这是第⼀次在园⼦⾥发随笔,写的不好但是是想从现在开始记录⾃⼰的学习⽣活。想养成写博客的习惯。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论