利用Java反射机制完成XML到对象的解析

    技术2022-05-11  79

    对于一些小批量的数据,如果采用数据库来存取的话,未免有点大题小作,使用XML文件是个不错的方法,尤其是在一些Web应用中,经常需要缓存一部分数据,如果将这些数据形成XML文件,解析后放入一个Hashtable,那就能大大加快访问的速度。

    由于工作的需要,写了一个解析工具,将XML解析成相应的对象列表。以下是源代码,希望对大家有所帮助,更希望大家帮我来改进这个工具。

     

    package  com.sp.util; /* *    author:hingwu *  email:hing3@163.com *  QQ:550598 *  MSN:hing3wu@hotmail.com(很少开) */ import  java.io.FileInputStream; import  java.io.InputStream; import  java.lang.reflect.Method; import  java.util.ArrayList; import  java.util.Date; import  java.util.List; import  javax.xml.parsers.DocumentBuilder; import  javax.xml.parsers.DocumentBuilderFactory; import  org.w3c.dom.Document; import  org.w3c.dom.Element; import  org.w3c.dom.NodeList; import  exceptions.MyException; public   class  ParseXMLToObject  {    public ParseXMLToObject(){}        @SuppressWarnings("unchecked")    public List getObject(String name,String path,String className){        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();        dbf.setIgnoringElementContentWhitespace(true);        DocumentBuilder db=null;        Document doc=null;        InputStream is=null;        try {            List list=new ArrayList();            db=dbf.newDocumentBuilder();            is=new FileInputStream(this.getClass().getResource(path).getPath());            doc=db.parse(is);            //根据要取的对象名称获取相应的节点列表            NodeList nodes=doc.getElementsByTagName(name);            if(nodes==null){                throw new MyException("null nodes with tagName "+name);            }            for(int i=0;i<nodes.getLength();i++){                Element node=(Element) nodes.item(i);                Class cls=Class.forName(className);                Object obj=cls.newInstance();                //获取节点下的所有子节点                NodeList childs=node.getChildNodes();                if(childs==null){                    throw new MyException("null childs! "+node);                }                for(int j=0;j<childs.getLength();j++){                    if(!childs.item(j).getNodeName().equals("#text")){                        Element child=(Element)childs.item(j);                        String childName=child.getNodeName();                        String type=child.getAttribute("type");                        String value=child.getAttribute("value");                        Object valueObj=typeConvert(type,value);                        String methodName="set"+Character.toUpperCase(childName.charAt(0))+childName.substring(1);                        System.out.println("methodName="+methodName+", class="+Class.forName(type));                        Method method=cls.getMethod(methodName, Class.forName(type));                        method.invoke(obj, new Object[]{valueObj});                    }                }                list.add(obj);            }            return list;                    } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();            return null;        }    }        //此方法用于将一个字符串转换为相应的数据类型    @SuppressWarnings("deprecation")    public Object typeConvert(String className,String value){        if(className.equals("java.lang.String")){            return value;        }        else if(className.equals("java.lang.Integer")){            return Integer.valueOf(value);        }        else if(className.equals("java.lang.Long")){            return Long.valueOf(value);        }        else if(className.equals("java.lang.Boolean")){            return Boolean.valueOf(value);        }        else if(className.equals("java.util.Date")){            return new Date(value);        }        else if(className.equals("java.lang.Float")){            return Float.valueOf(value);        }        else if(className.equals("java.lang.Double")){            return Double.valueOf(value);        }else return null;    }}

    Subject类的代码:

    package  com.sp.pojo; public   class  Subject  {    private String port;    private String servletName;    public String getPort() {        return port;    }    public void setPort(String port) {        this.port = port;    }    public String getServletName() {        return servletName;    }    public void setServletName(String servletName) {        this.servletName = servletName;    }    public Subject(){}    @Override    public String toString() {        // TODO Auto-generated method stub        return port+","+servletName;    }    }

     

     

    附上我的XML文件

    <? xml version="1.0" encoding="UTF-8" ?> < xml-body >      < subjects >          < port  type ="java.lang.String"  value ="4587" />          < servletName  type ="java.lang.String"  value ="com.sp.servlets.Route"   />      </ subjects >          < subjects >          < port  type ="java.lang.String"  value ="5687" />          < servletName  type ="java.lang.String"  value ="com.sp.servlets.Route"   />      </ subjects >          < security >          < userName  type ="java.lang.String"  value ="gogo" />          < password  type ="java.lang.String"  value ="gogo"   />          </ security > </ xml-body >

     

     

    自己写了一个测试类进行测试

     

    /** *    author:hingwu *  email:hing3@163.com *  QQ:550598 *  MSN:hing3wu@hotmail.com(很少开)  * * 上午11:44:27 */ package  com.sp.test; import  java.util.Iterator; import  java.util.List; import  com.sp.util.ParseXMLToObject; public   class  TestParse  {    public static void main(String[] args){        ParseXMLToObject pxt=new ParseXMLToObject();//        List list=(List)pxt.getObject("security","/cache.xml","com.sp.pojo.Security");        List list=(List)pxt.getObject("subjects","/cache.xml","com.sp.pojo.Subject");        Iterator it=list.iterator();        while(it.hasNext()){            System.out.println(it.next());        }            }}

     

    由于我的这个工具主要是为了缓存数据来使用的,我同时还完成了缓存类Cache的代码:

     

    package  com.sp.util; import  java.io.File; import  java.util.Hashtable; public   class  Cache  {    //cache用来放置各种需要缓存的数据    private static Hashtable cache=new Hashtable();    //lastModifyTime用于维护配置文件的最后修改时间,从而确定是直接从Cache读数据还是需要重新解析配置文件    private static long lastModifyTime;        public Object getObject(String name,String path,String parseClass,String className){        //如果配置文件被修改过则直接解析文件,否则直接从cache中取得相应的对象        if(checkModifyTime(path)){            System.out.println("get Object from file");            return getObjectFromFile(name,path,className);        }        return getObjectFromCache(name);    }        //直接从缓存中获取相应的对象    public Object getObjectFromCache(String name){        System.out.println("get Object from cache");        return cache.get(name);    }        //解析配置文件获取相应的对象    @SuppressWarnings("unchecked")    public Object getObjectFromFile(String name,String path,String className){        String key="key";        synchronized(key){            ParseXMLToObject pxt=new ParseXMLToObject();            Object obj=pxt.getObject(name, path, className);            cache.put(name, obj);            return obj;        }    }            //判断配置文件是否被修改过    public boolean checkModifyTime(String path){        String absPath=this.getClass().getResource(path).getPath();        long time=(new File(absPath)).lastModified();        if(lastModifyTime==0L||time>lastModifyTime){            lastModifyTime=time;            return true;        }        return false;    }}

     

    每次通过Cache去获取Hashtable中的数据时,会先判断XML文件有没有被修改过,如果没有修改,则直接返回数据,有修改则解析XML文件后返回数据。

    为了测试Cache类,专门写了一个Test类:

     

    /** *    author:hingwu *  email:hing3@163.com *  QQ:550598 *  MSN:hing3wu@hotmail.com(很少开)  * * 下午02:04:10 */ package  com.sp.test; import  java.util.Iterator; import  java.util.List; import  com.sp.util.Cache; public   class  TestCache  {    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        for(int i=0;i<10;i++){            System.out.println(""+i+"次获取缓存数据:");            Cache cache=new Cache();            List list=(List)cache.getObject("subjects","/cache.xml""com.sp.util.ParseXMLToObject""com.sp.pojo.Subject");            Iterator it=list.iterator();            while(it.hasNext()){                System.out.println(it.next());            }            try {                Thread.sleep(3000);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }}

    这种缓存策略有个好处,那就是在应用运行的时候,我们可以随时修改XML文件,而不需要重启应用或重新布署。


    最新回复(0)