因业务需要在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; }