因业务需要在Android端解析.net后台接口传递的XML,由于Android精简了jdk,无法使用原生XMLDecoder,因此选择了XStream实现。
C#后台使用原生XmlSerializer序列化
public static string Serialize(object data)
{
string result = string.Empty;
try
{
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer xml = new XmlSerializer(data.GetType());
xml.Serialize(ms, data);
byte[] arr = ms.ToArray();
result = Encoding.UTF8.GetString(ms.ToArray());
ms.Close();
}
}
catch (Exception ex)
{
throw;
}
return result;
}
移动端使用XStream对接口返回的XML进行解析,注意的是如果序列化的实体类中的字段包含其它实体类,解析时需要为其设置对应类的别名,下面通过反射获取这些类
/**
* XML 反序列化
*
* @param xmlStr XML 字符串
* @param classes alias
*/
public static T decode(String xmlStr, Class... classes) {
XStream xStream = new XStream(new DomDriver());
//这里添加子节点bean的别名
for (Class clazz : classes) {
xStream.alias(clazz.getSimpleName(), clazz);
}
//忽略未知节点
xStream.ignoreUnknownElements();
//因为需要将C# decimal类型转换为Java BigDecimal,这里需要对空值进行处理
xStream.registerConverter(new BigDecimalConverter() {
@Override
public Object fromString(String str) {
if (str == null || str.trim().length() == 0) {
return null;
} else {
return new BigDecimal(str);
}
}
});
//添加类型安全配置,这里允许访问bean包下所有类
xStream.allowTypesByWildcard(new String[]{"bean.**"});
Object obj = xStream.fromXML(xmlStr);
try {
return (T) obj;
} catch (ClassCastException e) {
e.printStackTrace();
return null;
}
}
通过反射获取实体类本身包含的其它实体类
/**
* 查找 Class 包含的所有 bean
* 如果 Class 本身也是 Bean, 返回的 Set 会包含它本身
*
* @param clazz clz
* @return class set
*/
public static Set getAllBeanTypes(Class clazz) {
if (clazz == null) {
return null;
}
Set types = new HashSet<>();
Class c = getBeanClassByName(clazz.getSimpleName());
if (c != null) {
types.add(c);
}
for (Class tempClz = clazz; tempClz != Object.class; tempClz = tempClz.getSuperclass()) {
Field[] fields = tempClz.getDeclaredFields();
for (Field field : fields) {
if (field.getType() == List.class) {
Type type = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
if (getBeanClassByName(((Class) type).getSimpleName()) != null) {
types.add(((Class) type));
types.addAll(getAllBeanTypes(((Class) type)));
}
} else if (getBeanClassByName(field.getType().getSimpleName()) != null) {
types.add(field.getType());
types.addAll(getAllBeanTypes(field.getType()));
}
}
}
return types;
}
public static Class getBeanClassByName(String name){
Class clazz = null;
try {
clazz = Class.forName("bean." + name);
} catch (ClassNotFoundException e) {
//no need to print.
}
return clazz;
}
