天天看点

使用反射技术,实现XML与对象相互转换(自己封装的超类,相互学习)

       对于网上的各种将XML同对象相互转换的方法比较多,但是如果对方给你提供的XML并非标准的XML格式,恐怕就只能自己封装方法了。作者在调用某票务公司提供的接口时,由于其返回XML流存在不标准的结构,因此自己写了个超类,继承于这个超类的所有对象可以调用toXml()、toObject(String xml)实现互转。

      通过反射技术实现,如有不足之处,欢迎批评指正,非常感谢!

注意:

      1、转换对象的属包含常见类型,如超类未涉及,请自行添加。

  List/Integer(int)/String/Double(double)/Float(float)/Date/Long(long)/Short(short)/Byte(byte)/该类的子类

      2、代码中的一些“未知”类

      (1)ServiceException:自定义的运行时异常,请自行添加

      (2)DateUtil:时间格式化工具,请自行封装

      (3)StringUtil:字符串工具,使用到的方法:判断Object是否为空

      3、需引入的包

<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->

<dependency>

    <groupId>commons-lang</groupId>

    <artifactId>commons-lang</artifactId>

    <version>2.6</version>

</dependency>

<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->

<dependency>

    <groupId>dom4j</groupId>

    <artifactId>dom4j</artifactId>

    <version>1.6.1</version>

</dependency>

      4、代码中存在与作者接受的业务相关内容,请自行处理(去掉红框中的判断逻辑)

使用反射技术,实现XML与对象相互转换(自己封装的超类,相互学习)

上代码:

      1、接口

/**
 * 实现此接口的对象可以和XML相互转换
 * @author WolfShadow
 * @date 2018年11月19日
 */
public interface Convertible {

	String toXml();
	
	<T> T toObject(String xml);
}
           

      2、超类

import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

//TODO 请自行添加这几个类或使用其他方式取代
import com.***.ServiceException;
import com.***.DateUtil;
import com.***.StringUtil;
import com.***.Convertible;

/**
 * 可与XML相互转换的超类
 * 此类的所有子类可实现与XML互相转换
 * 终极优化:子类不再需要重写该2方法,转换对象的属包含常见类型,如超类未涉及,请自行添加
 * List/Integer(int)/String/Double(double)/Float(float)/Date/Long(long)/Short(short)/Byte(byte)/该类的子类
 * 
 * @author WolfShadow
 * @date 2018年11月15日
 */
public class ConvertibleObject implements Convertible{

	@Override
	public String toString() {
		return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
	}

	 /**
	 * 通用将当前对象(this)转换成XML串,不包含<?xml version="1.0" encoding="UTF-8"?>
	 * @return
	 * @auther WolfShadow
	 * @date 2018年11月30日
	 */
	@Override
	public String toXml() {
		StringBuffer sBuffer = new StringBuffer();
		Class<? extends ConvertibleObject> class1 = this.getClass();
		/**
		 * 按照**提供的XML文档规范,类名首字母小写作为一个节点
		 */
		String name = class1.getSimpleName();
		name = name.replaceFirst(".", name.substring(0, 1).toLowerCase());
		sBuffer.append("<").append(name).append(">");
		
		Field[] fields = class1.getDeclaredFields();
		String fieldName = null;
		Object value = null;
		try {
			for(Field field : fields){//通过反射机制遍历类的所有属性及值
				fieldName = field.getName();
				Class<?> type = field.getType();
				field.setAccessible(true);
				
				if(type.equals(List.class)){//1.List属性
					// 判断List的成员是否是Convertible实现类
					ParameterizedType genericType = (ParameterizedType)field.getGenericType();
					Type[] arguments = genericType.getActualTypeArguments();
					
					Class<?> class2 = Class.forName(arguments[0].toString().replaceFirst("class ", ""));
					Class<?> superclass = class2.getSuperclass();
					
					if (superclass != null && superclass.equals(ConvertibleObject.class)) {//子类
						List<ConvertibleObject> list = (List<ConvertibleObject>)field.get(this);
						if (list == null) {
							continue;
						}
						sBuffer.append("<").append(fieldName).append(">");
						for(ConvertibleObject object : list){
							if (object != null) {
								sBuffer.append(object.toXml());
							}
						}
					}else {
						sBuffer.append(this.getFieldValue(field,class2));
					}
					sBuffer.append("</").append(fieldName).append(">");
				}else {
					//2.ConvertibleObject 子类
					Class<?> superclass = type.getSuperclass();
					if (superclass != null && superclass.equals(ConvertibleObject.class)) {//子类
						ConvertibleObject object = (ConvertibleObject)field.get(this);
						if (object != null) {
							sBuffer.append(object.toXml());
						}
					}else{//3.其他简单类型
						value = this.getFieldValue(field,type);//统一获取属性值的方法
						if (value == null) {
							continue;
						}
						sBuffer.append("<").append(fieldName).append(">");
						sBuffer.append(value);
						sBuffer.append("</").append(fieldName).append(">");
					}
				}
			}
		} catch (Exception e) {
			throw new ServiceException("class: "+this+" 转换成XML字符串时出错!");
		}
		
		sBuffer.append("</").append(name).append(">");
		return sBuffer.toString();
	}

	 /**
	 * 将XML转换成当前对象(this)
	 * @param xml
	 * @return
	 * @auther WolfShadow
	 * @date 2018年11月30日
	 */
	@Override
	public <T> T toObject(String xml) {
		if (!this.verifyXML(xml)) {
			return null;
		}
		Class<? extends ConvertibleObject> class1 = this.getClass();
		/**
		 * 按照**提供的XML文档规范,类名首字母小写作为一个节点
		 */
		String name = class1.getSimpleName();
		name = name.replaceFirst(".", name.substring(0, 1).toLowerCase());
		
		Field[] fields = class1.getDeclaredFields();
		String fieldName = null;
		String value = null;
		
		SAXReader reader = new SAXReader();
		Document document = null;
		try {
			document = reader.read(new StringReader(xml));//读取XML流为Document
			Element root = document.getRootElement();
			
			Element fieldE = null;
			for(Field field : fields){//通过反射机制遍历类的所有属性
				fieldName = field.getName();
				
				Class<?> type = field.getType();
				field.setAccessible(true);
				
				if(type.equals(List.class)){//1.List属性
					// 本可通用的方法,但因为**返回的XML存在不统一的情况,因此对products属性对应的XML需要特殊处理
					List<Element> elements = null;
					if ("products".equals(fieldName)) {
						elements = root.elements("product");
					}else{
						Element element = root.element(fieldName);
						elements = element.elements();
					}
					
					if (elements == null || elements.size() < 1) {
						continue;
					}
					
					// 判断List的成员是否是Convertible实现类
					ParameterizedType genericType = (ParameterizedType)field.getGenericType();
					Type[] arguments = genericType.getActualTypeArguments();
					
					Class<?> class2 = Class.forName(arguments[0].toString().replaceFirst("class ", ""));
					Class<?> superclass = class2.getSuperclass();
					
					List<Object> list = new ArrayList<>();
					if (superclass != null && superclass.equals(ConvertibleObject.class)) {//子类
						
						Object instance = class2.newInstance();
						Method method = class2.getMethod("toObject", String.class);
						Method method2 = class2.getMethod("isEmpty");
						Object invoke = null;
						for(Element e : elements){
							instance = method.invoke(instance, e.asXML());
							invoke = method2.invoke(instance);
							if (invoke != null && Boolean.FALSE.equals(invoke)) {
								list.add(instance);
							}
						}
					}else{
						for(Element e : elements){
							list.add(e.getStringValue());
						}
					}
					field.set(this, list);
				}else {
					fieldE = root.element(fieldName);
					if (fieldE == null) {
						continue;
					}
					//2.ConvertibleObject子类
					Class<?> superclass = type.getSuperclass();
					if (superclass != null && superclass.equals(ConvertibleObject.class)) {//子类
						Object instance = type.newInstance();
						Method method = type.getMethod("toObject", String.class);
						Method method2 = type.getMethod("isEmpty");
						Object invoke = null;
						instance = method.invoke(instance, fieldE.asXML());
						invoke = method2.invoke(instance);
						if (invoke != null && Boolean.FALSE.equals(invoke)) {
							field.set(this, instance);
						}
					}else{//其他普通类型
						value = fieldE.getStringValue();
						if (StringUtil.isNullOrEmpty(value)) {
							continue;
						}
						this.setField(field, value, type);
					}
					
				}
			}
			return (T) this;//强制转换成其子类
		} catch (ServiceException e) {
			throw e;
		} catch (Exception e) {
			throw new ServiceException("class: "+this+" 转换XML字符串为对象时出错!");
		}
	}
	
	 /**
	 * 常用类型属性值的设置
	 * @param field
	 * @param valueObj
	 * @auther WolfShadow
	 * @date 2018年11月22日
	 */
	public void setField(Field field, String value, Class<?> classType){
		//field.setAccessible(true);
		
		try {
			if (classType.equals(Integer.class) || classType.equals(int.class)) {
				field.set(this, Integer.parseInt(value));
			}else if (classType.equals(Long.class) || classType.equals(long.class)) {
				field.set(this, Long.parseLong(value));
			}else if (classType.equals(Short.class) || classType.equals(short.class)) {
				field.set(this, Short.parseShort(value));
			}else if (classType.equals(Float.class) || classType.equals(float.class)) {
				field.set(this, Float.parseFloat(value));
			}else if (classType.equals(Double.class) || classType.equals(double.class)) {
				field.set(this, Double.parseDouble(value));
			}else if (classType.equals(Byte.class) || classType.equals(byte.class)) {
				field.set(this, Byte.parseByte(value));
			}else if (classType.equals(String.class)) {
				field.set(this, value.toString());
			}else if (classType.equals(Date.class)) {
				int length = value.length();
				if (length == 10) {//YYYY-MM-dd
					value += " 00:00:00";
				}else if (length == 16) {//YYYY-MM-dd HH:mm
					value += ":00";
				}else {
				}
				field.set(this, DateUtil.str2Date(value));
			}else if (classType.equals(Boolean.class) || classType.equals(boolean.class)) {
				field.set(this, Boolean.parseBoolean(value));
			}else if (classType.equals(Object.class)) {
				field.set(this, value);
			}else {//如果未考虑到的属性类型,这里抛出异常
				throw new ServiceException("基础置换类不支持此种属性的转换");
			}
		} catch (ServiceException e) {
			throw e;
		} catch (Exception e) {
			throw new ServiceException("class: "+this+" 转换XML字符串为对象时出错!");
		}
	}
	/**
	 * 常用类型属性值的获取
	 * @param field
	 * @param valueObj
	 * @auther WolfShadow
	 * @date 2018年11月22日
	 */
	public String getFieldValue(Field field, Class<?> type){
		//field.setAccessible(true);
		try {
			Object valueObj = field.get(this);
			if (StringUtil.isNullOrEmpty(valueObj)) {
				return null;
			}
			if (type.equals(Integer.class) || type.equals(int.class)) {
			}else if (type.equals(Long.class) || type.equals(long.class)) {
			}else if (type.equals(Short.class) || type.equals(short.class)) {
			}else if (type.equals(Float.class) || type.equals(float.class)) {
			}else if (type.equals(Double.class) || type.equals(double.class)) {
			}else if (type.equals(Byte.class) || type.equals(byte.class)) {
			}else if (type.equals(String.class)) {
			}else if (type.equals(Date.class)) {
				
				//只处理时间格式
				return DateUtil.date2Str((Date)valueObj);
				
			}else if (type.equals(Boolean.class) || type.equals(boolean.class)) {
			}else if (type.equals(Object.class)) {
			}else {//如果未考虑到的属性类型,这里抛出异常
				//throw new ServiceException("基础置换类不支持此种属性的转换");
			}
			
			return valueObj.toString();
		} catch (ServiceException e) {
			throw e;
		} catch (Exception e) {
			throw new ServiceException("class: "+this+" 转换XML字符串为对象时出错!");
		}
	}
	 /**
	 * 默认情况下不需要做XML判断,但是在解析原始(标准)XML时需要重写该方法判断解析的XML是否合法
	 * @param xml
	 * @return
	 * @auther WolfShadow
	 * @date 2018年11月23日
	 */
	public boolean verifyXML(String xml){
		//return xml.startsWith(xmlheader) || xml.startsWith(xmlheader_low);
		return true;
	}
	
	 /**
	 * 对象为空
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @auther WolfShadow
	 * @date 2018年11月23日
	 */
	public boolean isEmpty() throws IllegalArgumentException, IllegalAccessException{
		Class<? extends ConvertibleObject> class1 = this.getClass();
		Field[] fields = class1.getDeclaredFields();
		Object object = null;
		for(Field field : fields){
			try {
				field.setAccessible(true);
				object = field.get(this);
			} catch (Exception e) {
				object = null;
			}
			if (!StringUtil.isNullOrEmpty(object)) {
				return false;
			}
		}
		return true;
	}
}
           

继续阅读