cglib与xstream结合构造webservice的xml格式的入参返参的动态生成
在做项目的时候遇到这样一个问题,需要与另一个系统进行Webservice通信,通信的入参、返参均是XML格式的,如下:
<PARAM>
<DET_FLAG>1</DET_FLAG>
<IO_TASK_NO>4413051710269522</IO_TASK_NO>
</PARAM>
但是这样的接口很多,而且大部分都是简单的几个属性,所以不想为每一种入参和返参都新建一个POJO类,于是就想到用Cglib动态生成类,然后再利用Xstream进行转换。
首先从网上摘了一段代码,如下:
package com.nari.component.xmlconvertor; import java.util.Iterator; import java.util.Map; import java.util.Set; import net.sf.cglib.beans.BeanGenerator; import net.sf.cglib.beans.BeanMap; public class CglibBean { public Object object = null; public BeanMap beanMap = null; public CglibBean() { super(); } public CglibBean(Map<String,?> propertyMap) throws Exception { this.object = generateBean(propertyMap); this.beanMap = BeanMap.create(this.object); } public void setValue(String property, Object value) { beanMap.put(property, value); } public Object getValue(String property) { return beanMap.get(property); } public Object getObject() { return this.object; } private Object generateBean(Map<String,?> propertyMap) throws Exception { BeanGenerator generator = new BeanGenerator(); Set<String> keySet = propertyMap.keySet(); for (Iterator<String> i = keySet.iterator(); i.hasNext();) { String key = i.next(); //修改为获取属性的Class类型 提高兼容性 generator.addProperty(key, propertyMap.get(key).getClass()); } return generator.create(); } }
这段代码就是生成了一个BeanGenerator,没什么好看的,网上一堆一堆的解释,不过将generator.addProperty的参数修改为了propertyMap.get(key).getClass()),以适应自己的需求,而且需要注意的问题是如果是web运行环境,一定要排查下依赖的jar包是否有冲突。
然后,就是写自己的转换类了,先看下面的代码,这个是将给定的Map转换为XML格式的String
package com.nari.component.xmlconvertor; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import com.thoughtworks.xstream.XStream; public class XMLConvertor { public static String convertor(Map<String,?> map,String type) throws Exception { //实例化CglibBean CglibBean bean = new CglibBean(map); //为字段赋值,如果不赋值则xml中就没有这个字段 for(String mapkey : map.keySet()){ bean.setValue(mapkey, map.get(mapkey)); System.out.println(mapkey + " = " + map.get(mapkey)); } //定制xml格式 Object object = bean.getObject(); Class<?> clazz = object.getClass(); Field[] fields = clazz.getDeclaredFields(); XStream x = new XStream(); //修改头为PARAM x.alias(type, object.getClass()); //alias属性为对应的属性名 for (int i = 0; i < fields.length; i++) { x.aliasField(fields[i].getName().substring(12,fields[i].getName().length()), object.getClass(), fields[i].getName()); } //返回转换好的xml文件 String xml = x.toXML(object); //不知对方接受的xml文件是否要去除空格,如果需要则可使用下面注释掉的方法 //xstream有bug,当参数中含有下划线的时候会转换为双下划线,这里做简单处理 return xml.replaceAll("__", "_"); } }
注释都在类里面,需要注意的是一些xstream的alian的问题,仔细看下,没啥东西。
其次,是将给定的XML格式字符串转换为自己需要的MAP,代码如下:
package com.nari.component.xmlconvertor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Map; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; public class StringConvertor { public static Map<String,String> convertor(Map<String,String> map,String xml,String type) throws Exception { CglibBean bean = new CglibBean(map); Object obj = bean.getObject(); Class<?> clazz = obj.getClass(); XStream xs = new XStream (new DomDriver()); xs.alias(type, clazz); Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { xs.aliasField(fields[i].getName().substring(12,fields[i].getName().length()), clazz, fields[i].getName()); } Object obj2 = (Object)xs.fromXML(xml); Class<?> clazz2 = obj2.getClass(); Method[] m3 = clazz2.getDeclaredMethods(); for(Method method :m3){ if(method.getName().indexOf("get")>-1){ String methodName = method.getName(); System.out.println(methodName); String value = (String)method.invoke(obj2, new Object[0]); String key = methodName.substring(3,methodName.length()); map.put(key, value); } } return map; } }
其实就是一个动态类的转换,注意字段的对应关系就行了。
最后 ,是一个测试类,这里有一些xfire客户端的东西,可以删掉
package com.nari.webservice.client; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import com.nari.component.xfireclient.XFireClient; import com.nari.component.xmlconvertor.StringConvertor; import com.nari.component.xmlconvertor.XMLConvertor; public class TestClient { public static void main(String args[]) throws Exception{ String IO_TASK_NO = "4413051710269522"; String DET_FLAG = "1"; Object[] params = new Object[]{IO_TASK_NO,DET_FLAG}; Map<String,String> m = new HashMap<String,String>(); m.put("IO_TASK_NO", "4413051710269522"); m.put("DET_FLAG", "1"); String s = ""; try { s = XMLConvertor.convertor(m, "PARAM"); System.out.println(s); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } Map<String,String> ma1 = new HashMap<String,String>(); ma1.put("IO_TASK_NO", ""); ma1.put("DET_FLAG", ""); ma1 = StringConvertor.convertor(ma1, s, "PARAM"); System.out.println(ma1.get("IO_TASK_NO")); System.out.println(ma1.get("DET_FLAG")); XFireClient client = new XFireClient(); Object[] backXml = client.callService("setInputTask", params); String backString = (String)backXml[0]; } }
其实,这里的入参和返参都是最基本的XML格式,没有内部属性,没有内部集合,用上面两个工具类足够了,下面的这个测试类提供了对复杂XML格式的动态转换,仅仅作为一个demo,代码如下:
package com.nari.component.xmlconvertor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.thoughtworks.xstream.XStream; public class TestXStream { public static void main(String args[]) throws Exception{ //collection demo List<Object> list = new ArrayList<Object>(); //不知道什么原因,这里new的虚拟类设置不进去值,可以用下面反射的方法想办法按照一定的规则去赋值,这个是特殊用法,一般不用,这里做兼容性支持 //原因已经找到,是因为在MAP中使用了关键字,这点估计后台截取的时候会导致类似问题,尽量避免关键字,否则可能需要反射调用,开销很大!! for(int iii = 0;iii<2; iii++){ Map<String,String> map01 = new HashMap<String,String>(); map01.put("ASD1", "asd1"); map01.put("CWE", "asd2"); map01.put("ASD3", "asd3"); CglibBean innerBean11 = new CglibBean(map01); for(String mapkey : map01.keySet()){ innerBean11.setValue(mapkey, map01.get(mapkey)); } Map<String,String> dymaMap = new HashMap<String,String>(); dymaMap.put("XXXX", "AAS"); dymaMap.put("WWWW", "ASD"); dymaMap.put("WEWEW", "dsa"); CglibBean dymaBean = new CglibBean(dymaMap); for(String mapkey : dymaMap.keySet()){ dymaBean.setValue(mapkey, dymaMap.get(mapkey)); } list.add(innerBean11.getObject()); list.add(dymaBean.getObject()); Object objo = dymaBean.getObject(); Class<?> clazz = objo.getClass(); Field[] testfield = clazz.getDeclaredFields(); Method[] m = clazz.getDeclaredMethods(); for(Method method :m){ if(method.getName().indexOf("get")>-1){ String s = (String)method.invoke(objo, new Object[0]); System.out.println("从虚拟类中中取出的值为 : " + s); } } } //内部属性demo Map<String,String> map0 = new HashMap<String,String>(); map0.put("ASD1", "asd1"); map0.put("ASD2", "asd2"); map0.put("ASD3", "asd3"); CglibBean innerBean1 = new CglibBean(map0); for(String mapkey : map0.keySet()){ innerBean1.setValue(mapkey, map0.get(mapkey)); } Object innerBean1Obj = innerBean1.getObject(); Class<?> clazz3 = innerBean1Obj.getClass(); Method[] m3 = clazz3.getDeclaredMethods(); for(Method method :m3){ if(method.getName().indexOf("get")>-1){ String s = (String)method.invoke(innerBean1Obj, new Object[0]); System.out.println("22222从虚拟类中中取出的值为 : " + s); } } //原始 Map<String,Object> map = new HashMap<String,Object>(); map.put("TEST1", "testValue1"); map.put("TEST2", "testValue2"); map.put("TEST3", innerBean1.getObject()); map.put("TEST4", list); CglibBean bean = new CglibBean(map); for(String mapkey : map.keySet()){ bean.setValue(mapkey, map.get(mapkey)); } Object object = bean.getObject(); XStream xstream = new XStream(); Class<?> clazz = object.getClass(); Field[] fields = clazz.getDeclaredFields(); //别名 xstream.alias("ROOT", clazz); for (int i = 0; i < fields.length; i++) { //简化的别名 String aliasName = fields[i].getName().substring(12,fields[i].getName().length()); xstream.aliasField(aliasName, object.getClass(), fields[i].getName()); //如果不是String类型的则表明是Object的具体对象 //如果是List if(bean.getValue(aliasName) instanceof ArrayList){ xstream.addImplicitCollection(clazz, fields[i].getName()); ArrayList arraylist = (ArrayList)bean.getValue(aliasName); for(Object objectBean : arraylist){ Class<?> clazzList = objectBean.getClass(); Field[] fieldsList = clazzList.getDeclaredFields(); xstream.alias(aliasName, clazzList); Method[] methods = clazzList.getDeclaredMethods(); for(Method m : methods){ if(m.getName().indexOf("set")>-1){ // m.invoke(objectBean, new Object[]{"tt!!!"}); } } for (int j = 0; j < fieldsList.length; j++) { // String s = fieldsList[j].getName() ; String aliasNameInner1 = fieldsList[j].getName().substring(12,fieldsList[j].getName().length()); xstream.aliasField(aliasNameInner1, clazzList, fieldsList[j].getName()); xstream.useAttributeFor(clazzList,fieldsList[j].getName()); } } System.out.println(aliasName + " 是List"); } //如果是String else if(bean.getValue(aliasName) instanceof String){ System.out.println(aliasName + " 是String"); } //如果是内部类 else { System.out.println(aliasName + " 是单独的类"); Class<?> clazzInner = bean.getValue(aliasName).getClass(); Field[] fieldsInner = clazzInner.getDeclaredFields(); for (int ii = 0; ii < fieldsInner.length; ii++) { String aliasNameInner = fieldsInner[ii].getName().substring(12,fieldsInner[ii].getName().length()); xstream.aliasField(aliasNameInner, clazzInner, fieldsInner[ii].getName()); xstream.useAttributeFor(clazzInner,fieldsInner[ii].getName()); } } xstream.useAttributeFor(object.getClass(),fields[i].getName()); } System.out.println(xstream.toXML(object)); } }
引入上面相关类后可以直接运行,运行结果如下:
<ROOT TEST1="testValue1" TEST2="testValue2">
<TEST3 ASD2="asd2" ASD3="asd3" ASD1="asd1"/>
<TEST4 ASD3="asd3" ASD1="asd1" CWE="asd2"/>
<TEST4 WEWEW="dsa" WWWW="ASD" XXXX="AAS"/>
<TEST4 ASD3="asd3" ASD1="asd1" CWE="asd2"/>
<TEST4 WEWEW="dsa" WWWW="ASD" XXXX="AAS"/>
</ROOT>
对于复杂XML转换为动态对象的工具类暂时没有写,以后补上
相关推荐
CGLib,全称为Code Generation Library,是一个强大的高性能的代码生成库,它在运行期扩展Java类与实现Java接口。在Java编程中,我们有时需要在运行时动态地创建或修改类,CGLib就是为此目的而设计的。它广泛应用于...
与JDK动态代理不同,CGLIB并不依赖于接口,而是直接对类进行增强。它使用ASM库在内存中构建新的字节码,生成的目标类会继承自原始类。因此,对于没有实现接口的类,CGLIB可以提供动态代理功能。 性能方面,CGLIB...
本压缩包文件提供了两个示例项目,分别展示了JDK动态代理和CGLib动态代理的实现,帮助我们理解这两种技术的工作原理以及它们生成的class文件结构。 首先,我们来详细了解JDK动态代理。JDK动态代理基于Java的接口...
cglib生成的代理的class
在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...
CGlib则是Java动态代理的一种实现方式,尤其是在不提供接口的情况下,它通过生成目标类的子类来实现动态代理。 在Java中,JDK自带的动态代理机制是基于接口的,如果被代理的类没有实现任何接口,那么就无法使用JDK...
在实际应用中,CGLib通常与AOP框架结合使用,如Spring AOP,它可以拦截并增强方法的执行,实现如日志记录、事务管理、权限控制等功能。同时,由于CGLib不需要目标类实现接口,因此对于那些无法修改源代码的第三方库...
与JDK动态代理不同,CGLIB并不依赖接口,而是通过字节码技术生成一个被代理类的子类来实现。这使得CGLIB能够代理没有实现接口的类。CGLIB的核心是ASM库,它能直接操作字节码生成新的类。在Spring中,如果目标类没有...
CGLIB(Code Generation Library)是Java中一个高性能的代码生成库,常用于实现动态代理,尤其在Spring框架中被广泛应用。本文将深入探讨CGLIB的工作原理、使用方式以及源码分析。 CGLIB是一个强大的高性能的代码...
CGLIB介绍与原理(部分节选自网络) 一、什么是CGLIB? CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要...
动态代理和CGLIB在Java开发中扮演着重要的角色,特别是在实现面向切面编程(AOP)和增强对象功能方面。动态代理允许我们在不修改原始代码的情况下,为已有对象添加额外的功能,比如日志记录、性能监控等。而CGLIB...
与JDK动态代理不同,CGLIB不依赖于接口,而是通过继承目标类来创建代理对象。 1. **CGLIB核心组件**:主要包括`Enhancer`、`Callback`和`MethodInterceptor`。`Enhancer`是增强对象的主要工具,`Callback`是一系列...
总的来说,CGLib和ASM库的结合,为Java开发提供了一个强大而灵活的工具,允许我们在运行时动态生成和修改类,极大地增强了代码的灵活性和可扩展性。在Spring框架中,它们是实现AOP代理不可或缺的部分,特别是在处理...
CGlib(Code Generation Library)是一个强大的高性能的代码生成库,它主要用于在运行期扩展Java类与实现Java接口。这个库最初由Evan Schooler创建,后来成为Apache软件基金会的一个项目,并且被广泛应用在各种开源...
CGlib,全称为Code Generation Library,是一个强大的Java代码生成库,广泛用于动态代理、AOP(面向切面编程)框架以及性能优化等场景。它通过字节码技术为类创建子类,从而实现对目标类的功能增强。在Java中,由于...
然而,如果目标类没有可访问的无参构造函数或者实现过多接口,Cglib可能会遇到问题。 在实际开发中,Cglib常与Spring AOP结合使用,通过`@Transactional`注解实现事务管理。当一个方法被标记为`@Transactional`时,...
CGLib是Java编程语言中的一个库...总的来说,CGLib和ASM的结合为Java开发提供了强大的动态类生成和字节码操作能力,极大地扩展了Java编程的可能性。通过熟练掌握这两个库,开发者可以构建出更灵活、更高效的应用程序。
CGLib动态代理是一种在Java编程中实现动态代理的技术,它主要通过字节码操作库ASM来生成目标类的子类,从而实现对目标类的方法拦截和增强。在Java中,当我们需要在运行时动态地创建对象并扩展其功能时,CGLib是一个...
CGlib是Java编程语言中的一个库,主要用于生成子类,以提供方法拦截和动态代理功能。它是对Bytecode Generation Library(字节码生成库)的一个封装,能够在运行时动态创建新类和对象,广泛应用于AOP(面向切面编程...