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

本文介绍了如何在Java中动态为实体类添加属性,包括使用CGLIB的BeanGenerator和Apache Commons BeanUtils的方法。通过示例展示了如何创建动态JavaBean并设置值,以及对比了两种方法的实现方式和使用注意事项。
摘要由CSDN通过智能技术生成

1.应用场景

fb400464a9b1b0269adda97625e29257.png

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

2.引入依赖

commons-beanutils

commons-beanutils

1.9.3

cglib

cglib-nodep

3.2.4

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 addProperties) {

// get property map

PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();

PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(dest);

Map 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 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 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 addProperties = new HashMap() {{

put("动态属性名", "动态属性值");

}};

FinalPicBaseReqDto finalPicBaseReqVo = (FinalPicBaseReqDto) PicBeanAddPropertiesUtil.getTarget(entity, addProperties);

System.out.println(JSON.toJSONString(finalPicBaseReqVo));

}

82139ab9aaa501aa3d63ffbe9834f457.png

8838e08a43d79555044e969b58ba2f08.png

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

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

补充: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.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 map = basicDynaBean.getMap();

Iterator it = map.keySet().iterator();while (it.hasNext()) { String key = it.next();

System.out.println(key + ":" + map.get(key));

}

输入结果:

id:1username:name1

查看BasicDynaBean与BasicDynaClass之间的关系

b4b857158b3d3a15badc79cad74296ae.png

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 values = new HashMap();

其实是用HashMap来实现的.

3.总结

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

org.apache.commons.beanutils从源码来看是使用HashMap来实现的.

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

Java中的cglib库可以用于动态生成Java类,可以通过cglib为一个原始对象添加属性并赋值。下面是一个简单的工具类,可以为一个对象添加属性并赋值: ```java import net.sf.cglib.beans.BeanGenerator; import net.sf.cglib.core.NamingPolicy; import net.sf.cglib.core.Predicate; import net.sf.cglib.core.Visibility; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; public class CglibUtils { /** * 为一个对象动态添加属性 * * @param target 原始对象 * @param fieldName 属性名 * @param value 属性值 * @return 新对象,新对象包含原始对象的所有属性和新添加属性 */ public static Object addField(Object target, String fieldName, Object value) { // 创建一个BeanGenerator对象,用于动态生成Java类 BeanGenerator generator = new BeanGenerator(); // 设置要生成的Java类的父类,即原始对象的类 generator.setSuperclass(target.getClass()); // 添加属性属性名为fieldName,属性值类型为value的类型 generator.addProperty(fieldName, value.getClass()); // 使用默认的命名策略生成类名 generator.setNamingPolicy(new NamingPolicy() { @Override public String getClassName(String s, String s1, Object o, Predicate predicate) { return target.getClass().getSimpleName() + "$$" + fieldName + "$$" + o.hashCode(); } }); // 创建新的Java类,并实例化对象 Object newObject = generator.create(); // 获取新对象的属性名和值,构造属性名和值的Map Map<String, Object> properties = new HashMap<String, Object>(); properties.put(fieldName, value); for (java.beans.PropertyDescriptor property : java.beans.Introspector.getBeanInfo(newObject.getClass()).getPropertyDescriptors()) { String propertyName = property.getName(); if (!"class".equals(propertyName)) { try { Object propertyValue = property.getReadMethod().invoke(target); properties.put(propertyName, propertyValue); } catch (Exception e) { // ignore exception } } } // 使用BeanUtils的populate方法,将属性名和值的Map中的所有属性值赋值给新对象 try { org.apache.commons.beanutils.BeanUtils.populate(newObject, properties); } catch (Exception e) { // ignore exception } return newObject; } } ``` 使用示例: ```java public class Main { public static void main(String[] args) { // 创建一个Person对象 Person person = new Person("张三", 18); System.out.println("原始对象:" + person); // 为Person对象添加属性,并赋值 Object newObject = CglibUtils.addField(person, "email", "zhangsan@qq.com"); System.out.println("新对象:" + newObject); } } ``` 输出结果: ``` 原始对象:Person{name='张三', age=18} 新对象:Person$$email$$-2086562992@6d5380c2{name='张三', age=18, email='zhangsan@qq.com'} ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值