上次遗留下来的XMLUtil的问题

Posted 韩思明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了上次遗留下来的XMLUtil的问题相关的知识,希望对你有一定的参考价值。

·在上周留下了一个关于XMLUtil的问题,问题大概是这样的,需要通过读取一个XML文件,然后在内存中生成一个对应的javaBean。之前写的那个很是糟糕,照着一个XML去写了一个"Util",拓展性,可维护性几乎为0,所有的东西全都写死,完全就写了一个"不伦不类"的"Util",很是郁闷,点击查看之前的代码,所以痛定思痛,打算在本周对上次的Util进行重写,一直拖到今天才花了几个小时写好,不得不感叹我的拖延至之严重!

·下面贴出代码,先是两个实体类

Student(学生类)

package com.taoyuan.entity.custom;

/**
 * @ClassName: Student
 * @Description: TODO Student实体类设计
 * @author: Han
 * @date: 2016-3-31 下午4:54:04
 */
public class Student {
    
    private int id;
    private String name;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        
        return "this student`s id is " + this.id + " and name is " + this.name;
    }
}

Class(班级类)可以明显看到两个类是关联关系,在Class类中含有一个Student的集合

package com.taoyuan.entity.custom;

import java.util.List;


/**
 * @ClassName: Class
 * @Description: TODO Class班级实体类设计
 * @author: Han
 * @date: 2016-3-31 下午4:58:21
 */
public class Class {
    
    private int id;
    private String className;
    private List<Student> student;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
    public List<Student> getStudents() {
        return student;
    }
    public void setStudents(List<Student> student) {
        this.student = student;
    }
    
    @Override
    public String toString() {
        
        return "This class`s id is " + this.id + " and name is " + this.className
                + "\\t\\nit`s students are " + this.student;
    }
}

XML文件

<?xml version="1.0" encoding="UTF-8"?>
<Entity>
    <Class classPath="com.taoyuan.entity.custom.Class">
        
        <Int name="id">1</Int>
        <String name="className">软件工程</String>
        <Student name="student" type="list">
            
            <!-- Student数组 -->
            <Student classPath="com.taoyuan.entity.custom.Student">
                <Int name="id">1</Int>
                <String name="name">李明</String>
            </Student>
            <Student  classPath="com.taoyuan.entity.custom.Student">
                <Int name="id">2</Int>
                <String name="name">狗蛋</String>
            </Student>
        </Student>
    </Class>
</Entity>

XMLUtil利用反射,递归等实现的Util,较之前有了很大的改动,再也不用对着一个Util狂改,把通用性将到了0...现在只需要修改XML和Java实体类就可以了

package com.taoyuan.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * @ClassName: XMLUtil
 * @Description: TODO XML工具类
 * @author: Han
 * @date: 2016-3-22 下午3:09:03
 */
public class XMLUtil {
    

    /**
     * @Title: toEntity
     * @Description: TODO 将XML文件转换为一个entity
     * @param xmlPath
     * @return
     * @throws Exception
     * @return: Object
     */
    public static Object toEntity(String xmlPath) throws Exception{
        
        //初始化,将XML文件读入内存,生成Document
        Document _document = init(xmlPath);
        
        //获取根目录节点
        Element _rootEle = _document.getRootElement();
        String _rootName = "";
        
        if(_rootEle != null){
            
            //根目录节点名字
            _rootName = _rootEle.getName();
        }
        
        if(!_rootName.equals("Entity")){
            
            throw new Exception("请确认根节点名字是否为Entity");
        }
        
        List<Element> elements = _rootEle.elements();
        
        //在Entity节点中无子节点
        if(elements.size() == 0){
            
            return null;
        }
        
        return getEntity(elements.get(0));
    }

    /**
     * 获取根据节点Element获取对应的Entity
     * @param element
     * @return
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    @SuppressWarnings("rawtypes")
    private static Object getEntity(Element element)
            throws ClassNotFoundException, InstantiationException,
            IllegalAccessException {
        
        //获取classPath
        String _classPath = element.attributeValue("classPath");
        
        //获取Class的字节码文件
        Class _clazz = Class.forName(_classPath);
        //根据字节码文件进行实例化
        Object _object = _clazz.newInstance();
        
        Field[] _fields = _clazz.getDeclaredFields();
        
        setMember(_object, element, _fields);
        
        return _object;
    }

    /**
     * 设置成员变量
     * @param object
     * @param element
     * @param fields 成员变量数组
     */
    private static void setMember(Object object, Element element, Field[] fields) {
        
        //获取当前Element获得的子节点迭代器
        Iterator<Element> _elements = element.elementIterator();
        while(_elements.hasNext()){
            
            Element _childElement = _elements.next();
            
            
            //当前正在设置的成员变量
            Field _field = null;
            //获取变量类型
            String _type = _childElement.getName();
            
            //获取变量名
            String _name = _childElement.attributeValue("name");
            //获取变量值
            String _value = _childElement.getTextTrim();
            
            //找到当前正在设置的成员变量
            for(int i = 0;i < fields.length;i ++ ){
                
                if(fields[i].getName().equals(_name)){
                    
                    _field = fields[i];
                    break;
                }
            }
            
            if(_field == null){
                
                throw new RuntimeException("没找到该成员变量" + _name);
            }
            
            //此时可以访问私有成员变量
            _field.setAccessible(true);
            
            if(!setBaseTypeMember(object, _field, _type, _value)){
                
                //当前成员变量不是基本类型,则为引用类型成员变量
                setReferenceTypeMember(_childElement, object,  _field);
            }
        }
    }

    /**
     * 设置引用类型成员变量
     * @param element
     * @param object
     * @param field
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static void setReferenceTypeMember(Element element, Object object,  Field field) {
        
        try {
            //若为list,则表示当前元素为一个list集合
            String _memberType = element.attributeValue("type");
            
            if(_memberType.equals("list")){
                
                List _list = new ArrayList();
                
                Iterator<Element> _iterator = element.elementIterator();
                while(_iterator.hasNext()){
                    
                    Element _childEle = _iterator.next();
                    
                    //递归获取该元素,并加入集合中
                    Object _entity = getEntity(_childEle);
                    _list.add(_entity);
                }
                
                field.set(object, _list);
                return;
            }

            
            //单元素的引用类型
            Object _entity = getEntity(element);
            field.set(object, _entity);
        } catch (Exception e) {
            
            throw new RuntimeException(e);
        }
    }

    /**
     * 设置基本类型成员变量
     * @param object
     * @param field
     * @param type
     * @param value
     * @return
     */
    private static boolean setBaseTypeMember(Object object, Field field,
            String type, String value) {
        
        try {
            if(type.equals("Int")){
                
                //int型成员变量
                field.setInt(object, Integer.parseInt(value));
            }else if(type.equals("Double")){

                //double型成员变量
                field.setDouble(object, Double.parseDouble(value));
            }else if(type.equals("Float")){

                //float型成员变量
                field.setFloat(object, Float.parseFloat(value));
            }else if(type.equals("Long")){

                //long型成员变量
                field.setLong(object, Long.parseLong(value));
            }else if(type.equals("Char")){

                //char型成员变量
                field.setChar(object, value.charAt(0));
            }else if(type.equals("String")){

                //string型成员变量
                field.set(object, value);
            }else{
                
                return false;
            }
        } catch (Exception e) {
            
            throw new RuntimeException(e);
        }
        
        return true;
    }

    /**
     * @Title: init
     * @Description: TODO 初始化,将XML读入内存
     * @param xmlPath
     * @return Document节点
     * @throws FileNotFoundException
     * @return: Document
     */
    private static Document init(String xmlPath) throws FileNotFoundException {
        
        //获取XML文件路径.是根据当前classPath去寻找,例如文件a.xml是放在根目录下,则需要输入的路径便是a.xml
        //还有另外一种方法是通过class.getResource("/" + xmlPath)效果是一样的
        //关于java中的路径问题还是没有搞得很清楚,下来还需要多看
        String _filePath = XMLUtil.class.getClassLoader().getResource(xmlPath).getPath();
        
        File _file = new File(_filePath);
        
        //如果文件存在
        if(_file.exists()){
            
            //利用dom4j返回该XML的document
            SAXReader _reader = new SAXReader();
            
            try {
                
                Document _document = _reader.read(_file);
                
                return _document;
                
            } catch (DocumentException e) {
                
                e.printStackTrace();
            }
        }else{
            
            throw new FileNotFoundException("您输入的XML文件地址未查到");
        }
        
        return null;
    }
    
}

测试方法

 

    @Test
    public void testXMLUtil() throws Exception{
        
        System.out.println(XMLUtil.toEntity("Class.xml"));
    }

 

结果输出

 

测试结果

Ok,测试成功

代码已经更新至GitHub

·总结一下:

1.下回再也不写那么逗的Util了,每次写Util之前先思考思考如何才能写成一个自己以后还能用到的真正的工具类。

2.对于这个版本自己还是有一些不满意的地方,每个成员变量我都是在XML文件里面声明了它的类型,比如<String ...>,既然我都已经通过反射拿到了成员变量的数组,为什么不用成员变量对象去判断它的类型呢??这个是可以改进的地方。

3.这次变量命名和注释相较于上一次已经有了很大的进步,自己还是比较满意的。

4.有什么理由可以不努力呢??哈哈

 

以上是关于上次遗留下来的XMLUtil的问题的主要内容,如果未能解决你的问题,请参考以下文章

Ubuntu 16.04安装 sogou 遗留下的问题

删除以前系统遗留下来的文件(比如Windows文件夹)时提示没有权限怎么办

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

无法为 com.adobe.adept.client.XMLUtil 的受信任 CA 设置证书

Android-XmlUtil工具类

“千年虫”是什么东西?一个在计算机诞生之初,遗留下的巨大 BUG!