在java中,解析、分装xml是一件非常“麻烦”的事。我们常常需要写大量的代理来解析不同的XML文件,然后将解析结果赋值给相关对象,便于更好的使用;或者将相关对象转换成XML格式进行输出。为了减去这繁琐的操作,笔者通过反射、注解的功能来实现 XML 与 JAVA对象 的相互转换。
同时,可能存在协议的变动,某些xml标签可能不在返回,这里也提供通过注解,快速屏蔽bean中某些属性的解析和分装。大大提高了转换的灵活度,以及便于最小程度的改动现有代码。
XML ——> bean
/**
* 解析xml
* @param c 目标对象的Class类
* @param parentObj 对象的父类,主要用于将对象set到父类中。即,递归地将c目标对象中的各个属性对象进行set操作,使c目标对象属性值为解析结果。
* @param isCollection 是否是Collection。如果目标对象包含Collection,则定义Class的时候,需要将Collection初始化
* @param element 当前对象的Xml层对应的Element
* @return 封装好的c对象实例
* @throws Exception
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Object parseXml(Class c, Object parentObj, boolean isCollection, Element element)
throws Exception
{
Object currentObj = null;
Element currentElement = element;
if (parentObj == null)
{
currentObj = c.newInstance();
}
else if(isCollection)
{
currentObj = parentObj;
}
else
{
//通过c获取className,并将className对象set到parentObj中
String[] strs = c.getName().split("\\.");
strs = strs[strs.length - 1].split("\\$");
String className = strs[strs.length - 1];
element = currentElement.element(className.toUpperCase());
if(element == null)
{
throw new Exception("parseXml Error. target:" + className + " is not exists");
}
currentObj = c.newInstance();
String setMethod = "set" + className.substring(0, 1).toUpperCase() + className.substring(1);
Method method = parentObj.getClass().getDeclaredMethod(setMethod, c);
method.invoke(parentObj, new Object[]{currentObj});
}
Field[] fieldArray = c.getDeclaredFields();
for (Field field : fieldArray)
{
//若属性标示为无需解析,则continue
if(field.isAnnotationPresent(XmlTransformAnnotation.class))
{
XmlTransformAnnotation xmlAnnotation = (XmlTransformAnnotation)field.getAnnotation(XmlTransformAnnotation.class);
String isParse = xmlAnnotation.value();
if(XmlTransformAnnotation.FLASE.equals(isParse))
{
continue;
}
}
Class basicType = getBasicType(field.getType());
if (basicType != null)
{
//属性为基本类型(包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean)
//解析属性xml标签,并将解析结果赋值到currentObj中
String setMethod = "set" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
Method method = c.getDeclaredMethod(setMethod, field.getType());
Element fieldElement = element.element(field.getName().toUpperCase());
if(fieldElement != null)
{
String value = fieldElement.getText();
Object fieldObj = basicType.getConstructor(String.class).newInstance(value);
method.invoke(currentObj, fieldObj);
}
else
{
throw new Exception("parseXml Error. target:" + field.getName() + " is not exists");
}
}
else
{
if (isCollection(field.getType()))
{
//Collection解析
String getMethodStr = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
String setMethodStr = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
Method getMethod = c.getDeclaredMethod(getMethodStr);
Collection collection = getCollectionByClass(field.getType());
Method setMethod = c.getDeclaredMethod(setMethodStr, field.getType());
setMethod.invoke(currentObj, collection);
//正式返回类型的type对象。例如:java.util.List<com.bayern.xml.example.entity.req.StaffBindReqBody$Staffs>
Type returnType = getMethod.getGenericReturnType();
//ParameterizedType : Comparable<? super T> , Collection符合该类型格式,例如Collection<String>。
if (returnType instanceof ParameterizedType)
{
ParameterizedType t = (ParameterizedType) returnType;
//getActualTypeArguments():返回表示此类型实际类型参数的 Type 对象的数组。
//因为List、Set泛型中只有一个参数,所以直接通过[0]获取。
Type pType = t.getActualTypeArguments()[0];
//Collection的泛型对象
Class pc = Class.forName(((Class) pType).getName());
Method addMethod = field.getType().getDeclaredMethod("add", Object.class);
List<Element> elementList = element.elements(field.getName().toUpperCase());
for(Element pcElement : elementList) {
Object parameterObj = pc.newInstance();
addMethod.invoke(collection, new Object[]{parameterObj});
parseXml(pc, parameterObj, true, pcElement);
}
}
}
else
{
//对象解析
parseXml(field.getType(), currentObj, false, currentElement);
}
}
}
return currentObj;
}
/**
* 解析xml
* @param c 目标对象的Class类
* @param parentObj 对象的父类,主要用于将对象set到父类中。即,递归地将c目标对象中的各个属性对象进行set操作,使c目标对象属性值为解析结果。
* @param isCollection 是否是Collection。如果目标对象包含Collection,则定义Class的时候,需要将Collection初始化
* @param element 当前对象的Xml层对应的Element
* @return 封装好的c对象实例
* @throws Exception
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Object parseXml(Class c, Object parentObj, boolean isCollection, Element element)
throws Exception
{
Object currentObj = null;
Element currentElement = element;
if (parentObj == null)
{
currentObj = c.newInstance();
}
else if(isCollection)
{
currentObj = parentObj;
}
else
{
//通过c获取className,并将className对象set到parentObj中
String[] strs = c.getName().split("\\.");
strs = strs[strs.length - 1].split("\\$");
String className = strs[strs.length - 1];
element = currentElement.element(className.toUpperCase());
if(element == null)
{
throw new Exception("parseXml Error. target:" + className + " is not exists");
}
currentObj = c.newInstance();
String setMethod = "set" + className.substring(0, 1).toUpperCase() + className.substring(1);
Method method = parentObj.getClass().getDeclaredMethod(setMethod, c);
method.invoke(parentObj, new Object[]{currentObj});
}
Field[] fieldArray = c.getDeclaredFields();
for (Field field : fieldArray)
{
//若属性标示为无需解析,则continue
if(field.isAnnotationPresent(XmlTransformAnnotation.class))
{
XmlTransformAnnotation xmlAnnotation = (XmlTransformAnnotation)field.getAnnotation(XmlTransformAnnotation.class);
String isParse = xmlAnnotation.value();
if(XmlTransformAnnotation.FLASE.equals(isParse))
{
continue;
}
}
Class basicType = getBasicType(field.getType());
if (basicType != null)
{
//属性为基本类型(包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean)
//解析属性xml标签,并将解析结果赋值到currentObj中
String setMethod = "set" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
Method method = c.getDeclaredMethod(setMethod, field.getType());
Element fieldElement = element.element(field.getName().toUpperCase());
if(fieldElement != null)
{
String value = fieldElement.getText();
Object fieldObj = basicType.getConstructor(String.class).newInstance(value);
method.invoke(currentObj, fieldObj);
}
else
{
throw new Exception("parseXml Error. target:" + field.getName() + " is not exists");
}
}
else
{
if (isCollection(field.getType()))
{
//Collection解析
String getMethodStr = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
String setMethodStr = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
Method getMethod = c.getDeclaredMethod(getMethodStr);
Collection collection = getCollectionByClass(field.getType());
Method setMethod = c.getDeclaredMethod(setMethodStr, field.getType());
setMethod.invoke(currentObj, collection);
//正式返回类型的type对象。例如:java.util.List<com.bayern.xml.example.entity.req.StaffBindReqBody$Staffs>
Type returnType = getMethod.getGenericReturnType();
//ParameterizedType : Comparable<? super T> , Collection符合该类型格式,例如Collection<String>。
if (returnType instanceof ParameterizedType)
{
ParameterizedType t = (ParameterizedType) returnType;
//getActualTypeArguments():返回表示此类型实际类型参数的 Type 对象的数组。
//因为List、Set泛型中只有一个参数,所以直接通过[0]获取。
Type pType = t.getActualTypeArguments()[0];
//Collection的泛型对象
Class pc = Class.forName(((Class) pType).getName());
Method addMethod = field.getType().getDeclaredMethod("add", Object.class);
List<Element> elementList = element.elements(field.getName().toUpperCase());
for(Element pcElement : elementList) {
Object parameterObj = pc.newInstance();
addMethod.invoke(collection, new Object[]{parameterObj});
parseXml(pc, parameterObj, true, pcElement);
}
}
}
else
{
//对象解析
parseXml(field.getType(), currentObj, false, currentElement);
}
}
}
return currentObj;
}
bean ——>XML
/**
* 封装xml
* @param c 目标对象Class类
* @param currentObj 被转换对象
* @param flag 是否需要xml头及root标签
* @return 解析后的xml
* @throws Exception
* @throws NoSuchMethodException
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static String packageXml(Class c, Object currentObj, boolean flag) throws Exception
{
if(currentObj == null)
{
return "";
}
StringBuffer xml = new StringBuffer();
if(flag)
{
xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
String[] strs = c.getName().split("\\.");
xml.append("<").append(strs[strs.length-1].toUpperCase()).append(">");
}
Field[] fieldArray = c.getDeclaredFields();
for(Field field : fieldArray)
{
if(field.isAnnotationPresent(XmlTransformAnnotation.class))
{
XmlTransformAnnotation xmlAnnotation = field.getAnnotation(XmlTransformAnnotation.class);
if(XmlTransformAnnotation.FLASE.equals(xmlAnnotation.value()))
{
continue;
}
}
Class basicType = getBasicType(field.getType());
if (basicType != null)
{
//分装基本类型(包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean)
xml.append("<").append(field.getName().toUpperCase()).append(">");
String setMethod = "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
Method method = c.getDeclaredMethod(setMethod);
String value = method.invoke(currentObj) != null ? method.invoke(currentObj).toString() : "";
xml.append(value);
xml.append("</").append(field.getName().toUpperCase()).append(">");
}
else
{
if (isCollection(field.getType()))
{
//分装Collection
String getMethod = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
Method method = c.getDeclaredMethod(getMethod);
Object collectionObj = method.invoke(currentObj);
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType)
{
ParameterizedType t = (ParameterizedType) returnType;
Type pType = t.getActualTypeArguments()[0];
Class pc = Class.forName(((Class) pType).getName());
Collection collection = (Collection)collectionObj;
if(collection != null)
{
for(Iterator iter = collection.iterator(); iter.hasNext();)
{
Object subObj = iter.next();
xml.append("<").append(field.getName().toUpperCase()).append(">");
String subXml = packageXml(pc, subObj, false);
xml.append(subXml);
xml.append("</").append(field.getName().toUpperCase()).append(">");
}
}
}
}
else
{
//分装对象
String[] strs = field.getName().split("\\.");
strs = strs[strs.length - 1].split("\\$");
String className = strs[strs.length - 1];
xml.append("<").append(className.toUpperCase()).append(">");
String getMethod = "get" + className.substring(0, 1).toUpperCase() + className.substring(1);
Method method = c.getDeclaredMethod(getMethod);
Object subObj = method.invoke(currentObj);
String subXml = packageXml(field.getType(), subObj, false);
xml.append(subXml);
xml.append("</").append(className.toUpperCase()).append(">");
}
}
}
if(flag)
{
String[] strs = c.getName().split("\\.");
xml.append("</").append(strs[strs.length-1].toUpperCase()).append(">");
}
return xml.toString();
}
/**
* 封装xml
* @param c 目标对象Class类
* @param currentObj 被转换对象
* @param flag 是否需要xml头及root标签
* @return 解析后的xml
* @throws Exception
* @throws NoSuchMethodException
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static String packageXml(Class c, Object currentObj, boolean flag) throws Exception
{
if(currentObj == null)
{
return "";
}
StringBuffer xml = new StringBuffer();
if(flag)
{
xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
String[] strs = c.getName().split("\\.");
xml.append("<").append(strs[strs.length-1].toUpperCase()).append(">");
}
Field[] fieldArray = c.getDeclaredFields();
for(Field field : fieldArray)
{
if(field.isAnnotationPresent(XmlTransformAnnotation.class))
{
XmlTransformAnnotation xmlAnnotation = field.getAnnotation(XmlTransformAnnotation.class);
if(XmlTransformAnnotation.FLASE.equals(xmlAnnotation.value()))
{
continue;
}
}
Class basicType = getBasicType(field.getType());
if (basicType != null)
{
//分装基本类型(包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean)
xml.append("<").append(field.getName().toUpperCase()).append(">");
String setMethod = "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
Method method = c.getDeclaredMethod(setMethod);
String value = method.invoke(currentObj) != null ? method.invoke(currentObj).toString() : "";
xml.append(value);
xml.append("</").append(field.getName().toUpperCase()).append(">");
}
else
{
if (isCollection(field.getType()))
{
//分装Collection
String getMethod = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
Method method = c.getDeclaredMethod(getMethod);
Object collectionObj = method.invoke(currentObj);
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType)
{
ParameterizedType t = (ParameterizedType) returnType;
Type pType = t.getActualTypeArguments()[0];
Class pc = Class.forName(((Class) pType).getName());
Collection collection = (Collection)collectionObj;
if(collection != null)
{
for(Iterator iter = collection.iterator(); iter.hasNext();)
{
Object subObj = iter.next();
xml.append("<").append(field.getName().toUpperCase()).append(">");
String subXml = packageXml(pc, subObj, false);
xml.append(subXml);
xml.append("</").append(field.getName().toUpperCase()).append(">");
}
}
}
}
else
{
//分装对象
String[] strs = field.getName().split("\\.");
strs = strs[strs.length - 1].split("\\$");
String className = strs[strs.length - 1];
xml.append("<").append(className.toUpperCase()).append(">");
String getMethod = "get" + className.substring(0, 1).toUpperCase() + className.substring(1);
Method method = c.getDeclaredMethod(getMethod);
Object subObj = method.invoke(currentObj);
String subXml = packageXml(field.getType(), subObj, false);
xml.append(subXml);
xml.append("</").append(className.toUpperCase()).append(">");
}
}
}
if(flag)
{
String[] strs = c.getName().split("\\.");
xml.append("</").append(strs[strs.length-1].toUpperCase()).append(">");
}
return xml.toString();
}
辅助方法
/**
* 判断Class的类型是不是基本类型。基本类型包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean
* 如果是基本类型则返回对应的Class,否则返回null
* @param type
* @return
*/
@SuppressWarnings("rawtypes")
private static Class getBasicType(Class type)
{
if (String.class.equals(type))
{
return String.class;
}
else if (Integer.class.equals(type))
{
return Integer.class;
}
else if (Byte.class.equals(type))
{
return Byte.class;
}
else if (Short.class.equals(type))
{
return Short.class;
}
else if (Long.class.equals(type))
{
return Long.class;
}
else if (Float.class.equals(type))
{
return Float.class;
}
else if (Double.class.equals(type))
{
return Double.class;
}
else if (Character.class.equals(type))
{
return Character.class;
}
else if (Boolean.class.equals(type))
{
return Boolean.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_BOOLEAN))
{
return Boolean.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_BYTE))
{
return Byte.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_CHAR))
{
return Character.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_DOUBLE))
{
return Double.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_FLOAT))
{
return Float.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_INT))
{
return Integer.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_SHORT))
{
return Short.class;
}
return null;
}
/**
* 判断Class是不是Collection类型,这里之判断了List、Set两种
* @param type
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
private static boolean isCollection(Class type) throws Exception
{
//isAssignableFrom(Class<?> cls)判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。
if(List.class.isAssignableFrom(type)) {
return true;
} else if(Set.class.isAssignableFrom(type)) {
return true;
}
return false;
}
/**
* 根据class获取Collection
* @param type Collection对应的Class
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
private static Collection getCollectionByClass(Class type) throws Exception
{
Collection collection = null;
if(type.isInterface()) {
List list = new ArrayList();
Set set = new HashSet();
//isInstance(Object obj)判定指定的 Object 是否与此 Class 所表示的对象赋值兼容。
if (type.isInstance(list))
{
collection = list;
}
else if(type.isInstance(set))
{
collection = set;
}
}else {
collection = (Collection)type.newInstance();
}
return collection;
}
/**
* 判断Class的类型是不是基本类型。基本类型包括:String、Integer、Byte、Short、Long、Float、Double、Character、Boolean、int、byte、short、long、float、double、char、boolean
* 如果是基本类型则返回对应的Class,否则返回null
* @param type
* @return
*/
@SuppressWarnings("rawtypes")
private static Class getBasicType(Class type)
{
if (String.class.equals(type))
{
return String.class;
}
else if (Integer.class.equals(type))
{
return Integer.class;
}
else if (Byte.class.equals(type))
{
return Byte.class;
}
else if (Short.class.equals(type))
{
return Short.class;
}
else if (Long.class.equals(type))
{
return Long.class;
}
else if (Float.class.equals(type))
{
return Float.class;
}
else if (Double.class.equals(type))
{
return Double.class;
}
else if (Character.class.equals(type))
{
return Character.class;
}
else if (Boolean.class.equals(type))
{
return Boolean.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_BOOLEAN))
{
return Boolean.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_BYTE))
{
return Byte.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_CHAR))
{
return Character.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_DOUBLE))
{
return Double.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_FLOAT))
{
return Float.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_INT))
{
return Integer.class;
}
else if(type.getName().equals(Constant.BASIC_TYPE_SHORT))
{
return Short.class;
}
return null;
}
/**
* 判断Class是不是Collection类型,这里之判断了List、Set两种
* @param type
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
private static boolean isCollection(Class type) throws Exception
{
//isAssignableFrom(Class<?> cls)判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。
if(List.class.isAssignableFrom(type)) {
return true;
} else if(Set.class.isAssignableFrom(type)) {
return true;
}
return false;
}
/**
* 根据class获取Collection
* @param type Collection对应的Class
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
private static Collection getCollectionByClass(Class type) throws Exception
{
Collection collection = null;
if(type.isInterface()) {
List list = new ArrayList();
Set set = new HashSet();
//isInstance(Object obj)判定指定的 Object 是否与此 Class 所表示的对象赋值兼容。
if (type.isInstance(list))
{
collection = list;
}
else if(type.isInstance(set))
{
collection = set;
}
}else {
collection = (Collection)type.newInstance();
}
return collection;
}
完整代码链接: