天天看點

使用反射技術,實作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;
	}
}
           

繼續閱讀