一、前言

國慶假期臨近,工作動力不強。所以寫幾篇之前專案中自己用到的一些可能有用的東西分享出來。

今天分享的是Xml與javaBean互轉的自定義實現。

先說幾種我知道的Xml與javaBean互轉的方式:

1、可以利用StringBuilder執行拼接,這樣比較費時且複用性低

2、利用JAXB、jackson等一些公開API呼叫進行轉換,這樣最方便最簡單

3、利用Dom4j實現

這三種一般來說肯定優先選第二種。

但是出於學習的目的。我在之前的專案中自己利用Dom4j完成xml與javaBean的互轉。

由於使用場景還不多,程式碼健壯性目前有待完善。後續使用在更多場景下會一步一步優化完善,如果有朋友有一些優化建議

歡迎在評論區指出。

**二、公共類 ReflectDTO **

這個介面這裡主要作用是一個標識作用.

如果需要控制類中某些屬性無需轉換。可以加一些註解之類的來控制,由於我沒有這種需求所以沒有實現這功能。

需要轉換的物件來實現這個介面,在處理過程中會將實現該介面的類資訊轉換

import java.io.Serializable;

/**
* @author hhb
* @date :2021/8/20 14:23
*/
public interface ReflectDTO extends Serializable {
}

三、Xml轉JavaBean

3.1、方法入口。首先 利用Dom4j 將String格式的xml轉化成Document型別的物件,然後通過遞迴、反射實現轉化

    /**
* 將Xml格式的字串轉換為java物件
* @param xml
* @param cls
* @return
* @throws DocumentException
* @throws IllegalAccessException
*/
public static <T> T parseXml(String xml,Class<T> cls) throws DocumentException,IllegalAccessException {
//xml格式字串轉Dom4j的Document
Document document = DocumentHelper.parseText(xml);
//遞迴處理子元素
return (T)handleElement(document.getRootElement(), cls,null,null);
}

3.2、遞迴方法。遞迴處理Document元素,將element裡面的text匹配上物件的屬性並賦值

    /**
* 遞迴處理元素
* @param root
* @param rootClz
* @param rootObj
* @param rootField
* @return
* @throws IllegalAccessException
*/
private static Object handleElement(Element root, Class rootClz, Object rootObj,Field rootField) throws IllegalAccessException {
//建立物件公共方法
Object fieldObj = creatObj(rootClz);
List<Element> elements = root.elements();
//獲取帶轉換類已宣告的屬性
Field[] fields = rootClz.getDeclaredFields();
for (Element e:elements){
//細節處理,後續可進一步完善屬性可能的型別
handleDetail(fields,e,fieldObj);
}
if (null!=rootObj&&null!=rootField){
rootField.set(rootObj,fieldObj);
}
return fieldObj;
}

3.3、 基礎方法。根據物件的class資訊生成新的物件,還有根據Element的名稱匹配物件中

對應的相應屬性資訊。


/**
* 根據類資訊生成物件
* @param cls
* @return
*/
private static Object creatObj(Class cls){
try {
return cls.getConstructor().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
} /**
* Documet元素標籤匹配物件屬性
* @param fields
* @param name
* @return
*/
private static Field matchFields(Field[] fields, String name) {
for (Field field: fields){
if (field.getName().equals(name)){
return field;
}
}
return null;
}

3.4、 處理核心方法。主要是根據物件屬性的型別採取對應的處理方式目前已實現的有,

實現了ReflectDTO介面的物件、String、List。後面如果還有其他型別可以

自己按照已有示例進行擴充套件


/**
* 處理核心
* @param fields
* @param e
* @param fieldObj
* @throws IllegalAccessException
*/
private static void handleDetail(Field[] fields,Element e,Object fieldObj) throws IllegalAccessException {
//匹配屬性,沒匹配上直接返回
Field field=matchFields(fields,e.getName());
if (null==field){
return;
}
field.setAccessible(true);
Class<?> fieldType = field.getType();
//如果是List
if (fieldType.equals(List.class)&&field.getGenericType() instanceof ParameterizedType){
List list = handleListDetail(e, field);
field.set(fieldObj,list);
return;
}
//獲得屬性值
Object childFieldValue = creatObj(fieldType);
//如果是String
if (fieldType.equals(String.class)){
field.set(fieldObj,e.getText());
}
//todo 這裡還可以擴充套件,比如BigDecimal、LocalDateTime、Double等等
//需要轉換的物件
if (childFieldValue instanceof ReflectDTO){
Object o=handleElement(e,fieldType,fieldObj,field);
field.set(fieldObj,o);
}
}

3.5、處理特殊方法。如果待生成屬性是list時的一些處理方法,主要有獲取List裡面的物件的實際型別方法,

處理List屬性時的明細方法。

    /**
* 列表型別處理明細
* @param listElement
* @param field
* @return
* @throws IllegalAccessException
*/
private static List handleListDetail(Element listElement,Field field) throws IllegalAccessException {
ArrayList objList = new ArrayList<>();
Class<?> classInList = getClassInList(field.getGenericType());
for (Element e: listElement.elements()){
Object objInList = handleElement(e, classInList, null, null);
objList.add(objInList);
}
return objList;
} /**
* 獲得List裡面的物件型別
* @param fieldType
* @return
*/
private static Class<?> getClassInList(Type fieldType){
ParameterizedType paramType = (ParameterizedType) fieldType;
Type[] genericTypes = paramType.getActualTypeArguments();
if (genericTypes != null && genericTypes.length > 0) {
if (genericTypes[0] instanceof Class<?>) {
return (Class<?>) genericTypes[0];
}
}
return null;
}

四、 javaBean轉Xml的實現

由於該篇篇幅較長,這個實現將放在下一篇進行說明.