`
elfasd
  • 浏览: 100429 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

cglib与xstream结合构造webservice的xml格式的入参返参的动态生成

    博客分类:
  • xml
阅读更多

       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动态生成java类

    CGLib,全称为Code Generation Library,是一个强大的高性能的代码生成库,它在运行期扩展Java类与实现Java接口。在Java编程中,我们有时需要在运行时动态地创建或修改类,CGLib就是为此目的而设计的。它广泛应用于...

    CGLIB 和 JDK生成动态代理类的区别

    与JDK动态代理不同,CGLIB并不依赖于接口,而是直接对类进行增强。它使用ASM库在内存中构建新的字节码,生成的目标类会继承自原始类。因此,对于没有实现接口的类,CGLIB可以提供动态代理功能。 性能方面,CGLIB...

    输出JDK和CGLib动态代理产生的class文件.zip

    本压缩包文件提供了两个示例项目,分别展示了JDK动态代理和CGLib动态代理的实现,帮助我们理解这两种技术的工作原理以及它们生成的class文件结构。 首先,我们来详细了解JDK动态代理。JDK动态代理基于Java的接口...

    cglib生成的代理class

    cglib生成的代理的class

    浅谈JDK动态代理与CGLIB代理去区别

    在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...

    cglib动态代理介绍

    CGlib则是Java动态代理的一种实现方式,尤其是在不提供接口的情况下,它通过生成目标类的子类来实现动态代理。 在Java中,JDK自带的动态代理机制是基于接口的,如果被代理的类没有实现任何接口,那么就无法使用JDK...

    cglib实现动态代理依赖jar包

    在实际应用中,CGLib通常与AOP框架结合使用,如Spring AOP,它可以拦截并增强方法的执行,实现如日志记录、事务管理、权限控制等功能。同时,由于CGLib不需要目标类实现接口,因此对于那些无法修改源代码的第三方库...

    jdk与cglib动态代理与底层实现

    与JDK动态代理不同,CGLIB并不依赖接口,而是通过字节码技术生成一个被代理类的子类来实现。这使得CGLIB能够代理没有实现接口的类。CGLIB的核心是ASM库,它能直接操作字节码生成新的类。在Spring中,如果目标类没有...

    动态代理cglibjar包和源码

    CGLIB(Code Generation Library)是Java中一个高性能的代码生成库,常用于实现动态代理,尤其在Spring框架中被广泛应用。本文将深入探讨CGLIB的工作原理、使用方式以及源码分析。 CGLIB是一个强大的高性能的代码...

    cglib.jar下载

    CGLIB介绍与原理(部分节选自网络) 一、什么是CGLIB? CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要...

    动态代理和cglib例子

    动态代理和CGLIB在Java开发中扮演着重要的角色,特别是在实现面向切面编程(AOP)和增强对象功能方面。动态代理允许我们在不修改原始代码的情况下,为已有对象添加额外的功能,比如日志记录、性能监控等。而CGLIB...

    Jdk动态代理和cglib动态代理原理

    与JDK动态代理不同,CGLIB不依赖于接口,而是通过继承目标类来创建代理对象。 1. **CGLIB核心组件**:主要包括`Enhancer`、`Callback`和`MethodInterceptor`。`Enhancer`是增强对象的主要工具,`Callback`是一系列...

    cglib及其依赖包

    总的来说,CGLib和ASM库的结合,为Java开发提供了一个强大而灵活的工具,允许我们在运行时动态生成和修改类,极大地增强了代码的灵活性和可扩展性。在Spring框架中,它们是实现AOP代理不可或缺的部分,特别是在处理...

    cglib,字节码生成库是生成和转换Java字节码的高级API。它被aop、测试、数据访问框架用来生成动态代理对象和拦截字段访问。.zip

    CGlib(Code Generation Library)是一个强大的高性能的代码生成库,它主要用于在运行期扩展Java类与实现Java接口。这个库最初由Evan Schooler创建,后来成为Apache软件基金会的一个项目,并且被广泛应用在各种开源...

    cglib的依赖包

    CGlib,全称为Code Generation Library,是一个强大的Java代码生成库,广泛用于动态代理、AOP(面向切面编程)框架以及性能优化等场景。它通过字节码技术为类创建子类,从而实现对目标类的功能增强。在Java中,由于...

    Cglib动态代理需要用到的jar包

    然而,如果目标类没有可访问的无参构造函数或者实现过多接口,Cglib可能会遇到问题。 在实际开发中,Cglib常与Spring AOP结合使用,通过`@Transactional`注解实现事务管理。当一个方法被标记为`@Transactional`时,...

    cglib动态代理用到的两个包

    CGLib是Java编程语言中的一个库...总的来说,CGLib和ASM的结合为Java开发提供了强大的动态类生成和字节码操作能力,极大地扩展了Java编程的可能性。通过熟练掌握这两个库,开发者可以构建出更灵活、更高效的应用程序。

    cglib动态代理

    CGLib动态代理是一种在Java编程中实现动态代理的技术,它主要通过字节码操作库ASM来生成目标类的子类,从而实现对目标类的方法拦截和增强。在Java中,当我们需要在运行时动态地创建对象并扩展其功能时,CGLib是一个...

    cglib动态代理相关包

    CGlib是Java编程语言中的一个库,主要用于生成子类,以提供方法拦截和动态代理功能。它是对Bytecode Generation Library(字节码生成库)的一个封装,能够在运行时动态创建新类和对象,广泛应用于AOP(面向切面编程...

Global site tag (gtag.js) - Google Analytics