1.應用場景
之前對接三方平臺遇到一個參數(shù)名稱是變化的,然后我就想到了動態(tài)javabean怎么生成,其實是我想多了,用個map就輕易解決了,但還是記錄下動態(tài)屬性添加的實現(xiàn)吧。
2.引入依賴
- <!--使用cglib 為javabean動態(tài)添加屬性-->
- <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;
- }
- /**
- * 根據(jù)屬性生成對象
- *
- * @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("動態(tài)屬性名", "動態(tài)屬性值");
- }};
- FinalPicBaseReqDto finalPicBaseReqVo = (FinalPicBaseReqDto) PicBeanAddPropertiesUtil.getTarget(entity, addProperties);
- System.out.println(JSON.toJSONString(finalPicBaseReqVo));
- }
可以看到實體類只有兩個屬性,但是最終是動態(tài)添加進去了新的屬性。
聲明:代碼也是前人造的輪子,歡迎各位拿去使用,解決實際生產(chǎn)中遇到的相似場景問題
補充:JavaBean動態(tài)添加刪除屬性
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());
- }
輸出結(jié)果:
- name1
- getId
- getUsername
- setId
- setUsername
從輸出結(jié)果可以看出最后生成的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));
- }
輸入結(jié)果:
- 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是怎么實現(xiàn)的,直接看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來實現(xiàn)的.
3.總結(jié)
用cglib動態(tài)刪除添加屬性時,雖然obj里有getUsername這個方法,卻不能obj.getUsername()這樣直接調(diào)用,想得到username的值只能通過beanMap.get("username")獲取.
org.apache.commons.beanutils從源碼來看是使用HashMap來實現(xiàn)的.
兩種方式從操作角度來說和使用Map的區(qū)別不大.只是它們都提供了復制屬性的工具方法.
原文鏈接:https://www.jianshu.com/p/cc1014e71e8a