好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Java cglib为实体类(javabean)动态添加属性方式

1.应用场景

之前对接三方平台遇到一个参数名称是变化的,然后我就想到了动态javabean怎么生成,其实是我想多了,用个map就轻易解决了,但还是记录下动态属性添加的实现吧。

2.引入依赖

<!--使用cglib 为javabean动态添加属性--> <dependency> <groupId> commons-beanutils </groupId> <artifactId> commons-beanutils </artifactId> <version> 1.9.3 </version> </dependency> <dependency> <groupId> cglib </groupId> <artifactId> cglib-nodep </artifactId> <version> 3.2.4 </version> </dependency>

3.代码如下

import com . freemud . waimai . menu . dpzhcto . dto . DynamicBean ; import com . google . common . collect . Maps ; import org . apache . commons . beanutils . PropertyUtilsBean ; import java . beans . PropertyDescriptor ; import java . util . Map ; public class PicBeanAddPropertiesUtil { public static Object getTarget ( Object dest , Map < String , Object > addProperties ) { // get property map PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean (); PropertyDescriptor [] descriptors = propertyUtilsBean . getPropertyDescriptors ( dest ); Map < String , Class > propertyMap = Maps . newHashMap (); for ( PropertyDescriptor d : descriptors ) { if (! "class" . equalsIgnoreCase ( d . getName ())) { propertyMap . put ( d . getName (), d . getPropertyType ()); } } // add extra properties addProperties . forEach (( k , v ) -> propertyMap . put ( k , v . getClass ())); // new dynamic bean DynamicBean dynamicBean = new DynamicBean ( dest . getClass (), propertyMap ); // add old value propertyMap . forEach (( k , v ) -> { try { // filter extra properties if (! addProperties . containsKey ( k )) { dynamicBean . setValue ( k , propertyUtilsBean . getNestedProperty ( dest , k )); } } catch ( Exception e ) { e . printStackTrace (); } }); // add extra value addProperties . forEach (( k , v ) -> { try { dynamicBean . setValue ( k , v ); } catch ( Exception e ) { e . printStackTrace (); } }); Object target = dynamicBean . getTarget (); return target ; } } import net . sf . cglib . beans . BeanGenerator ; import net . sf . cglib . beans . BeanMap ; import java . util . Map ; public class DynamicBean { /** * 目标对象 */ private Object target ; /** * 属性集合 */ private BeanMap beanMap ; public DynamicBean ( Class superclass , Map < String , Class > propertyMap ) { this . target = generateBean ( superclass , propertyMap ); this . beanMap = BeanMap . create ( this . target ); } /** * bean 添加属性和值 * * @param property * @param value */ public void setValue ( String property , Object value ) { beanMap . put ( property , value ); } /** * 获取属性值 * * @param property * @return */ public Object getValue ( String property ) { return beanMap . get ( property ); } /** * 获取对象 * * @return */ public Object getTarget () { return this . target ; } /** * 根据属性生成对象 * * @param superclass * @param propertyMap * @return */ private Object generateBean ( Class superclass , Map < String , Class > propertyMap ) { BeanGenerator generator = new BeanGenerator (); if ( null != superclass ) { generator . setSuperclass ( superclass ); } BeanGenerator . addProperties ( generator , propertyMap ); return generator . create (); } } public static void main ( String [] args ) { FinalPicBaseReqDto entity = new FinalPicBaseReqDto (); entity . setAppKey ( "eee" ); entity . setContent ( "222" ); Map < String , Object > addProperties = new HashMap () {{ put ( "动态属性名" , "动态属性值" ); }}; FinalPicBaseReqDto finalPicBaseReqVo = ( FinalPicBaseReqDto ) PicBeanAddPropertiesUtil . getTarget ( entity , addProperties ); System . out . println ( JSON . toJSONString ( finalPicBaseReqVo )); }

可以看到实体类只有两个属性,但是最终是动态添加进去了新的属性。

声明:代码也是前人造的轮子,欢迎各位拿去使用,解决实际生产中遇到的相似场景问题

补充:JavaBean动态添加删除属性

1.cglib

BeanGenerator beanGenerator = new BeanGenerator (); beanGenerator . addProperty ( "id" , Long . class ); beanGenerator . addProperty ( "username" , String . class ); Object obj = beanGenerator . create (); BeanMap beanMap = BeanMap . create ( obj ); BeanCopier copier = BeanCopier . create ( User . class , obj . getClass (), false ); User user = new User (); user . setId ( 1L ); user . setUsername ( "name1" ); user . setPassword ( "123" ); copier . copy ( user , obj , null ); System . out . println ( beanMap . get ( "username" )); Class clazz = obj . getClass (); Method [] methods = clazz . getDeclaredMethods (); for ( int i = 0 ; i < methods . length ; i ++) { System . out . println ( methods [ i ]. getName ()); }

输出结果:

name1 getId getUsername setId setUsername

从输出结果可以看出最后生成的obj只有id和username两个属性

2.org.apache测试数据mons.beanutils

DynaProperty property = new DynaProperty ( "id" , Long . class ); DynaProperty property1 = new DynaProperty ( "username" , String . class ); BasicDynaClass basicDynaClass = new BasicDynaClass ( "user" , null , newDynaProperty []{ property , property1 }); BasicDynaBean basicDynaBean = new BasicDynaBean ( basicDynaClass ); User user = new User (); user . setId ( 1L ); user . setUsername ( "name1" ); user . setPassword ( "123" ); BeanUtils . copyProperties ( basicDynaBean , user ); Map < String , Object > map = basicDynaBean . getMap (); Iterator < String > it = map . keySet (). iterator (); while ( it . hasNext ()) { String key = it . next (); System . out . println ( key + ":" + map . get ( key )); }

输入结果:

id : 1username : name1

查看BasicDynaBean与BasicDynaClass之间的关系

DynaBean的源码

public interface DynaBean { public boolean contains ( String name , String key ); public Object get ( String name ); public Object get ( String name , int index ); public Object get ( String name , String key ); public DynaClass getDynaClass (); public void remove ( String name , String key ); public void set ( String name , Object value ); public void set ( String name , int index , Object value ); public void set ( String name , String key , Object value ); }

主要是接口的定义

再来看看BasicDynaBean是怎么实现的,直接看public Object get(String name);

/** * Return the value of a simple property with the specified name. * * @param name Name of the property whose value is to be retrieved * @return The property's value * * @exception IllegalArgumentException if there is no property * of the specified name */ public Object get ( String name ) { // Return any non-null value for the specified property Object value = values . get ( name ); if ( value != null ) { return ( value ); } // Return a null value for a non-primitive property Class <?> type = getDynaProperty ( name ). getType (); if (! type . isPrimitive ()) { return ( value ); } // Manufacture default values for primitive properties if ( type == Boolean . TYPE ) { return ( Boolean . FALSE ); } else if ( type == Byte . TYPE ) { return ( new Byte (( byte ) 0 )); } else if ( type == Character . TYPE ) { return ( new Character (( char ) 0 )); } else if ( type == Double . TYPE ) { return ( new Double ( 0.0 )); } else if ( type == Float . TYPE ) { return ( new Float (( float ) 0.0 )); } else if ( type == Integer . TYPE ) { return ( new Integer ( 0 )); } else if ( type == Long . TYPE ) { return ( new Long ( 0 )); } else if ( type == Short . TYPE ) { return ( new Short (( short ) 0 )); } else { return ( null ); } }

从以上代码可以看出是在values里取值的

/** * The set of property values for this DynaBean, keyed by property name. */ protected HashMap < String , Object > values = new HashMap < String , Object >();

其实是用HashMap来实现的.

3.总结

用cglib动态删除添加属性时,虽然obj里有getUsername这个方法,却不能obj.getUsername()这样直接调用,想得到username的值只能通过beanMap.get("username")获取.

org.apache测试数据mons.beanutils从源码来看是使用HashMap来实现的.

两种方式从操作角度来说和使用Map的区别不大.只是它们都提供了复制属性的工具方法.

原文链接:https://HdhCmsTestjianshu测试数据/p/cc1014e71e8a

查看更多关于Java cglib为实体类(javabean)动态添加属性方式的详细内容...

  阅读:17次