阅读 912

Cglib应用:基于Map动态生成JavaBean对象

这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战

再某些特殊的场景下,存在手动创建java类的case,比如我有个需求,希望根据简单的Map对象,来生成一个对应的Java bean,可以怎么整?

针对这个而典型的场景,先考虑是否有现成可用的开源工具类来实现,比如我们经常接触到cglib,它可以动态生成代理对象,那么生成Java Bean也没有什么问题

接下来我们看一下使用cglib来创建bean的方式

1. cglib动态创建bean

首先添加cglib的依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>[3.3.0,)</version>
</dependency>
复制代码

接下来的bean创建,主要是借助 BeanGenereator + BeanMap来实现

创建Java Bean对象,主要借助 BeanGenerator来完成,需要根据传入的Map中value的类型,来定义生成对象的属性类型

private Object instanceObject(Map<String, Object> map) {
    Map<String, Class> properties = new HashMap<>(map.size());
    for (Map.Entry<String, Object> entry : map.entrySet()) {
        properties.put(entry.getKey(), entry.getValue().getClass());
    }
    // 根据属性生成实体bean
    return generateBean(properties);
}

private Object generateBean(Map<String, Class> propertyMap) {
    //根据一组属性名和属性值的类型,动态创建Bean对象
    BeanGenerator generator = new BeanGenerator();
    Set keySet = propertyMap.keySet();
    for (Iterator i = keySet.iterator(); i.hasNext(); ) {
        String key = (String) i.next();
        generator.addProperty(key, (Class) propertyMap.get(key));
    }
    return generator.create();  //创建Bean
}
复制代码

上面这两个方法,就实现了根据Map来创建java bean对象;此时bean对象已经生成,成员属性也都指定了,但是还没有初始化value

接下来的value设置,则利用BeanMap来处理

private void initObject(Map<String, Object> map) {
    //用实体Bean创建BeanMap,用于获取和设置value
    // 这个object就是上面生成的实体类
    beanMap = BeanMap.create(this.object);
    for (Map.Entry<String, Object> entry : map.entrySet()) {
        beanMap.put(entry.getKey(), entry.getValue());
    }
}
复制代码

如果我们希望获取这个object中的成员值,同样也是借助BeanMap来实现(因为新生成的JavaBean并没有赋予相应的get/set方法)

public Object getValue(String key) {
    return beanMap.get(key);
}
复制代码

接下来将上面的代码封装一下,并给一个测试

public class CglibBean {
    private Object object = null;
    private BeanMap beanMap = null;

    public CglibBean(Map<String, Object> map) {
        this.object = instanceObject(map);
        initObject(map);
    }

    private Object instanceObject(Map<String, Object> map) {
        Map<String, Class> properties = new HashMap<>(map.size());
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            properties.put(entry.getKey(), entry.getValue().getClass());
        }
        // 根据属性生成实体bean
        return generateBean(properties);
    }

    private void initObject(Map<String, Object> map) {
        //用实体Bean创建BeanMap,用于获取和设置value
        beanMap = BeanMap.create(this.object);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            beanMap.put(entry.getKey(), entry.getValue());
        }
    }

    /**
     * 得到该实体bean对象
     *
     * @return
     */
    public Object getObject() {
        return this.object;
    }

    public Object getValue(String key) {
        return beanMap.get(key);
    }

    private Object generateBean(Map<String, Class> propertyMap) {
        //根据一组属性名和属性值的类型,动态创建Bean对象
        BeanGenerator generator = new BeanGenerator();
        Set keySet = propertyMap.keySet();
        for (Iterator i = keySet.iterator(); i.hasNext(); ) {
            String key = (String) i.next();
            generator.addProperty(key, (Class) propertyMap.get(key));
        }
        return generator.create();  //创建Bean
    }


    public static void main(String[] args) throws IllegalAccessException { // 设置类成员属性
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", 123);
        map.put("name", "hello");
        map.put("now", new Date());

        CglibBean bean = new CglibBean(map);
        // 获得bean的实体
        Object object = bean.getObject();
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field f: fields) {
            f.setAccessible(true);
            System.out.println("field: " + f.getName() + " = " + f.get(object));
        }

        System.out.println("----------------");
        System.out.println(bean.getValue("id"));
    }
}

复制代码

接下来我们看一下测试输出

field: $cglib_prop_now = Fri Aug 20 16:29:00 CST 2021
field: $cglib_prop_name = hello
field: $cglib_prop_id = 123
----------------
123
复制代码

II. 其他

1. 一灰灰Blogliuyueyi.github.io/hexblog

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

  • 微博地址: 小灰灰Blog
  • QQ: 一灰灰/3302797840
  • 微信公众号:一灰灰blog
文章分类
后端
文章标签