使用Dom4j、反射自定义实现xml与java对象互转
一、前言
国庆假期临近,工作动力不强。所以写几篇之前项目中自己用到的一些可能有用的东西分享出来。
今天分享的是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的实现
由于该篇篇幅较长,这个实现将放在下一篇进行说明.
使用Dom4j、反射自定义实现xml与java对象互转的更多相关文章
- xml和java对象互转:JAXB注解的使用详解
		
先看工具类: import org.slf4j.Logger; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; ...
 - 不规矩的xml与JAVA对象互相转换的小技巧-使用Marshaller
		
摘要:将XML文档与JAVA对象互转是很常见的需求,如果XML定义很规整这很好实现.然而在现实中“不规矩”的XML可能更常见,Marshaller便无能为力了吗?下面是一个小技巧,调整一下思维便能重用 ...
 - XStream轻松转换xml和java对象
		
首先引入所需的jar: xstream-1.4.9.xpp3_min-1.1.4c.dom4j-1.6.1, 或用maven管理jar包时在pom.xml中添加: <!-- https://mv ...
 - XML 和 java对象相互转换
		
XML 和 java对象相互转换 博客分类: XML 和 JSON 下面使用的是JDK自带的类,没有引用任何第三方jar包. Unmarshaller 类使客户端应用程序能够将 XML 数据转换为 ...
 - Java&Xml教程(十一)JAXB实现XML与Java对象转换
		
JAXB是Java Architecture for XML Binding的缩写,用于在Java类与XML之间建立映射,能够帮助开发者很方便的將XML和Java对象进行相互转换. 本文以一个简单的例 ...
 - Java&Xml教程(十一)JAXB实现XML与Java对象转换
		
JAXB是Java Architecture for XML Binding的缩写,用于在Java类与XML之间建立映射,可以帮助开发人员非常方便的將XML和Java对象进行相互转换. 本文以一个简单 ...
 - Json与Java对象互转之Gson学习
		
Json与Java对象互转之Gson学习 请尊重他人的劳动成果.转载请注明出处:Json与Java对象互转之Gson学习 我曾在<XML,Object,Json转换之浅析Xstr ...
 - json、xml和java对象之间的转化
		
其实从面相对象的角度来理解这个问题,就会很清晰.java中的一切皆对象即把世间万物(Everything in the world)看做java对象,任何处理不了的问题都可以先转化成java对象在做处 ...
 - 使用XStream是实现XML与Java对象的转换(6)--持久化
		
九.持久化 在第八节的示例中,当我们操作一组对象时,我们可以指定Writer.OutputStream来写出序列化后的XML数据,我们还可以指定Reader.InputStream来读取序列化后的XM ...
 
随机推荐
- C#---OleDbHelper
			
/// <summary> /// OleDbServer数据访问帮助类 /// </summary> public sealed class OleDbHelper { pu ...
 - HttpURLconnection的介绍
			
一,HttpURLconnection的介绍 在Android开发中网络请求是最常用的操作之一, Android SDK中对HTTP(超文本传输协议)也提供了很好的支持,这里包括两种接口: 1.标准J ...
 - 【java虚拟机】内存分配与回收策略
			
作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/6557473.html 前言 对象的内存分配,往大的方向上讲,就是在堆上分配,少数情况下也可能会直接分配在老 ...
 - 互斥锁(Lock)
			
转载至:https://www.cnblogs.com/dolphin0520/p/3923167.html 一.synchronized的缺陷 synchronized是java中的一个关键字,也就 ...
 - Navicate 连接阿里云MySQL(两种方式及原理讲解)
			
Navicate 连接阿里云(两种方式及原理讲解) 一.直连方式(通过3306端口) 1.概述 2. 环境准备 3.操作及讲解 二.使用SSH通道 1.概述 2.环境准备 3.操作及讲解 如果对你有帮 ...
 - Linux下用gdb 调试、查看代码堆栈
			
Linux中用gdb 查看代码堆栈的信息 core dump 一般是在segmentation fault(段错误)的情况下产生的文件,需要通过ulimit来设置才会得到的. 调试的话输入: gd ...
 - 在ubuntu18.04上部署项目时遇到的问题总结
			
因为在实验室中,有几台空闲的机子,我便选了一台准备做一个本地的服务器,因为买的阿里云学生机和之前用于FQ的机子感觉都不太顺手,阿里的学生机配置稍低,FQ用的服务器延迟太高.开始在centos和ubun ...
 - springcloud<seata配置文件解释及其说明>
			
出现如下错误时: Could not found property service.disableGlobalTransaction, try to use default value instead ...
 - ES6——类表达式
			
//类表达式 const Person1 = class{ constructor(){ console.log('aa') } } //也可以跟上类名P,但是变量P在class外部是访问不到的,在c ...
 - Hutool中那些常用的工具类和方法
			
Hutool中那些常用的工具类和方法 Hutool是一个Java工具包,它帮助我们简化每一行代码,避免重复造轮子.如果你有需要用到某些工具方法的时候,不妨在Hutool里面找找,可能就有.本文将对Hu ...