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());}

输出结果:

name1getIdgetUsernamesetIdsetUsername

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

2.org.apache.commons.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 propertyObject value = values.get(name); if (value != null) { return (value);} // Return a null value for a non-primitive propertyClass<?> type = getDynaProperty(name).getType(); if (!type.isPrimitive()) { return(value);} // Manufacture default values for primitive propertiesif (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.commons.beanutils从源码来看是使用HashMap来实现的.

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

自信是一个人的胆,有了这个胆,你就会所向披靡!

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

相关文章:

你感兴趣的文章:

标签云: