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.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 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.commons.beanutils从源码来看是使用HashMap来实现的.

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

(0)

相关推荐

  • java通过cglib动态生成实体bean的操作

    maven依赖: <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.3</version> </dependency> <dependency> <groupId>cglib</groupId> <artifa

  • Java 如何从spring容器中获取注入的bean对象

    1.使用场景 控制层调用业务层时,控制层需要拿到业务层在spring容器中注入的对象 2.代码实现 import org.apache.struts2.ServletActionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.suppo

  • 浅析Java中Apache BeanUtils和Spring BeanUtils的用法

    # 前言 在我们实际项目开发过程中,我们经常需要将不同的两个对象实例进行属性复制,从而基于源对象的属性信息进行后续操作,而不改变源对象的属性信息,比如DTO数据传输对象和数据对象DO,我们需要将DO对象进行属性复制到DTO,但是对象格式又不一样,所以我们需要编写映射代码将对象中的属性值从一种类型转换成另一种类型. # 对象拷贝 在具体介绍两种 BeanUtils 之前,先来补充一些基础知识.它们两种工具本质上就是对象拷贝工具,而对象拷贝又分为深拷贝和浅拷贝,下面进行详细解释. # 什么是浅拷贝和

  • spring boot拦截器注入不了java bean的原因

    一.如何实现拦截器 在Spring Boot项目中,拦截器经常被用来做登陆验证,日志记录等操作.拦截器是Spring提供的,所以可以将拦截器注成bean,由IOC容器来管理.实现拦截器的方式很简单,主要由以下两个步骤: 自定义拦截器类实现HandlerInterceptor接口 自定义WebMvc配置类实现WebMvcConfigurer接口,添加自定义拦截器类 简要实现代码如下: 自定义拦截器 LoginInterceptor: public class LoginInterceptor im

  • Java反射 JavaBean对象自动生成插入,更新,删除,查询sql语句操作

    通过反射根据提供的表名.POJO类型.数据对象自动生成sql语句. 如名为 User 的JavaBean与名为 user 的数据库表对应,可以提供一个封装有数据的User对象user,根据user中含有的数据自动生成sql语句. 1.生成插入语句(插入user中包含的非空数据的语句): String insertSql = getInsertSql("user", User.class, user); 2.生成更新语句(user中id不能为空): String updateSql =

  • Java Bean与Map之间相互转化的实现方法

    概述 Apache的BeanUtils Bean工具类很强大,基本涵盖了Bean操作的所有方法.这里的话我们就讲讲两个方面,一是Bean covert to Map,二是Map covert to Bean:Bean转Map其实利用的是Java的动态性-Reflection技术,不管是什么Bean通过动态解析都是可以转成Map对象的,但前提条件是field需要符合驼峰命名不过这也是写码规范,另一个条件就是每个field需要getter.setter方法.而Map转Bean一样也是通过Reflec

  • java 动态生成bean的案例

    最近做一个需求,需求中的bean只用于生成一次json使用,所以想通过配置来动态的生成,查了一下,java还真有这个实现. java动态的生成javabean,只能生成属性和对应的set/get方法,不能生成其他的方法. import org.assertj.core.internal.cglib.beans.BeanGenerator; import org.assertj.core.internal.cglib.beans.BeanMap; import java.lang.reflect.

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

    1.应用场景 之前对接三方平台遇到一个参数名称是变化的,然后我就想到了动态javabean怎么生成,其实是我想多了,用个map就轻易解决了,但还是记录下动态属性添加的实现吧. 2.引入依赖 <!--使用cglib 为javabean动态添加属性--> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId>

  • Javascript 创建类并动态添加属性及方法的简单实现

    JavaScript 是一种很强的面向对象的语言,支持创建实例之后再添加属性和方法,虽然是小技巧,用的时候容易忘记,今天写了一个很小的例子,记录在这里,仅供参考. function MyClass() { //This function is same as a constructer alert("New Object Created"); } //Creating Object var MyObject = new MyClass (); NewObject.prototype =

  • 在python的类中动态添加属性与生成对象

    本文将通过一下几个方面来一一进行解决 1.程序的主要功能 2.实现过程 3.类的定义 4.用生成器generator动态更新每个对象并返回对象 5.使用strip 去除不必要的字符 6.rematch匹配字符串 7.使用timestrptime提取字符串转化为时间对象 8.完整代码 程序的主要功能 现在有个存储用户信息的像表格一样的文档:第一行是属性,各个属性用逗号(,)分隔,从第二行开始每行是各个属性对应的值,每行代表一个用户.如何实现读入这个文档,每行输出一个用户对象呢? 另外还有4个小要求

  • Java为实体类动态添加属性的方法详解

    目录 添加依赖 代码 测试 可以给已有实体类动态的添加字段并返回新的实体对象,不影响原来的实体对象结构. 添加依赖 <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>commons

  • 浅谈java中为什么实体类需要实现序列化

    当客户端访问某个能开启会话功能的资源,web服务器就会创建一个HTTPSession对象,每个HTTPSession对象都会占用一定的内存,如果在同一个时间段内访问的用户太多,就会消耗大量的服务器内存,为了解决这个问题我们使用一种技术:session的持久化. 什么是session的持久化? web服务器会把暂时不活动的并且没有失效的HTTPSession对象转移到文件系统或数据库中储存,服务器要用时在把他们转载到内存. 把Session对象转移到文件系统或数据库中储存就需要用到序列化: jav

  • java反射遍历实体类属性和类型,并赋值和获取值的简单方法

    实例如下: import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Date; /** * 获取实体类型的属性名和类型 * @param model 为实体类 * @author kou 为传入参数 */ public class GetModelNameAndType { public

  • Python实现动态给类和对象添加属性和方法操作示例

    本文实例讲述了Python实现动态给类和对象添加属性和方法操作.分享给大家供大家参考,具体如下: 动态给类和对象添加属性 定义一个Person类 class Person(object): def __init__(self, name): self.name = name 给对象添加属性 # 创建2个Person,分别为p1,p2 p1 = Person('amy') print(p1.name) p1.age = 10 # 给p1对象添加属性 print(p1.age) # 输出10 p2

  • java序列化对象根据不同配置动态改变属性名的方法

    目录 实现方式 实现过程 自定义注解一:MyParamName 自定义注解二:NameEle 手写MyNameFilter,实现fastjson的NameFilter 实体类,属性上添加自定义注解 运行主方法测试 参考 使用场景:自己项目对接多个外部系统,各个外部系统使用的字段并没有统一,所以要根据不同系统动态的输出序列化数据,使适应各个系统的要求 实现方式 使用自定义注解和fastjson实现需求 fastjson的NameFilter的作用:序列化时,属性名变成自己指定的名称 实现过程 自定

  • Python实现动态添加属性和方法操作示例

    本文实例讲述了Python实现动态添加属性和方法操作.分享给大家供大家参考,具体如下: # -*- coding:utf-8 -*- #!python3 class Person(): def __init__(self, name, age): self.name = name self.age = age p1 = Person('ff', '28') print(p1.name, p1.age) # 给实例对象动态添加sex属性 p1.sex = 'female' print(p1.sex

  • JS实现给对象动态添加属性的方法

    本文实例讲述了JS实现给对象动态添加属性的方法.分享给大家供大家参考,具体如下: 在工作用要用到给jd对象动态添加属性的要求,在网上找到了一种解决方式,实例如下: 1.demo var aa="maker"; var bb=123; var lists={}; eval("lists."+aa+"="+bb); eval('('+"lists."+aa+"="+bb+')'); console.log(li

随机推荐