• Java中JavaBean对象和Map的互相转换


    1.JavaBean转Map

    1.1.简介

    这篇博客是通过反射进行实现转换的

    在学习redis中,发现了一个知识点,就是Java对象转map,视频中的内容是通过hutool工具转换的,但是我们学习者肯定不能只通过工具来进行转换,更多的是通过这个知识点学习到他的底层是如何进行转换的。

    1.2.反射知识

    // 新建一个对象
    UserDTO userDTO = new UserDTO(1L,"zhangsan","123");
    // 通过reflect获取所有属性
    // userDTO.getClass().getDeclaredFields() // 暴力获取所有的属性字段
    for (Field field : userDTO.getClass().getDeclaredFields()) {
        // 设置暴力反射,获取私有属性
        field.setAccessible(true);
        try {
        	/**
        	field.getName() 获取属性字段的字段名称
        	field.get(userDTO)  相当于  userDTO.getField();  
        	*/
            map.put(field.getName(),field.get(userDTO));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    for (String s : map.keySet()) {
        System.out.println(s+"=="+map.get(s));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    1.3.简单转换

    @Test
        void contextLoads() {
            Map<String, Object> map = new HashMap<>();
            UserDTO userDTO = new UserDTO(1L,"zhangsan","123");
            // 通过reflect获取所有属性
            for (Field field : userDTO.getClass().getDeclaredFields()) {
                // 设置暴力反射,获取私有属性
                field.setAccessible(true);
                try {
                    map.put(field.getName(),field.get(userDTO));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            for (String s : map.keySet()) {
                System.out.println(s+"=="+map.get(s));
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1. 4.属性里面套属性转换

    实体类

    package com.sky;
    
    import com.sky.dto.UserDTO;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.List;
    
    /**
     * @author 尹稳健~
     * @version 1.0
     * @time 2022/11/9
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Clazz {
        private String ClazzName;
        @OneSelf
        List<UserDTO> userDTOList;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    自定义注解

    package com.sky;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    /**
     * @author 尹稳健~
     * @version 1.0
     * @time 2022/11/9
     */
    @Retention(RetentionPolicy.RUNTIME)
    public @interface OneSelf {
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    转换方法:

    public Map<String,Object> beanToMap(Object o){
            Map<String, Object> map = new HashMap<>();
            // 通过reflect获取所有树形
            for (Field field : o.getClass().getDeclaredFields()) {
                // 设置暴力反射,获取私有属性
                field.setAccessible(true);
                try {
                    if (field.get(o) != null){
                        Class<?> aClass = field.get(o).getClass();
                        OneSelf annotation = aClass.getAnnotation(OneSelf.class);
                        if (annotation!=null){
                            Map<String, Object> beanToMap = beanToMap(field.get(o));
                            map.put(field.getName(),beanToMap);
                        }else{
                            map.put(field.getName(),field.get(o));
                        }
                    }
    
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            return map;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    1. 5.总结

    • 就是通过自定义注解来判断是否需要递归转换
    • 嵌套的话,应该还有其他方法可以研究一下

    2.Map转JavaBean对象

    2.1.简介

    在实际项目中相信大多数人都使用过工具类,比如说commons下的和hutool工具类,但是我们只是知道如何调用这个API,而不知道他方法的底层是通过什么样的思路进行实现的。
    通过对一些底层的了解和学习,能学到更多的知识,了解底层的一些实现方式,拓展自己的思维。
    我将从下面开始介绍如何将JavaBean对象转换为Map。

    2.2.Introspector介绍

    Introspector是JDK中java.beans包下的类,它为目标JavaBean提供了一种了解原类方法、属性和事件的标准方法。通俗的说,就是可以通过Introspector构建一个BeanInfo对象,而这个BeanInfo对象中包含了目标类中的属性、方法和事件的描述信息,然后可以使用这个BeanInfo对象对目标对象进行相关操作。

    JDK原文:

    • Introspector类提供了一种标准的工具来了解目标Java Bean支持的属性,事件和方法。
    • 对于这三种信息中的每一种,Introspector将分别分析bean的类和超类,寻找显式或隐式信息,并使用该信息构建一个全面描述目标bean的BeanInfo对象。
    • 对于每个类“Foo”,如果存在相应的“FooBeanInfo”类,在查询信息时提供非空值,则显式信息可能可用。 我们首先通过获取目标bean类的完整的包限定名称并附加“BeanInfo”来形成一个新的类名称来查找BeanInfo类。 如果失败,那么我们将使用该名称的最终类名组件,并在BeanInfo包搜索路径中指定的每个包中查找该类。

    方法介绍:

    修饰符返回类型方法名称和参数描述
    staticStringdecapitalize(String name)实用方法来取一个字符串并将其转换为正常的Java变量名称大小写。
    staticvoidflushCaches()冲洗所有Introspector的内部缓存。
    staticvoidflushFromCaches(类 clz)刷新内部缓存信息给一个给定的类。
    staticBeanInfogetBeanInfo(类 beanClass)内省Java Bean并了解其所有属性,暴露的方法和事件。
    staticBeanInfogetBeanInfo(类 beanClass, 类 stopClass)内省Java bean并了解其属性,暴露的方法,低于给定的“停止”点。
    staticBeanInfogetBeanInfo(类 beanClass, 类 stopClass, int flags)对Java Bean进行内省,并了解其所有属性,暴露的方法和事件,低于给定的 stopClass点,受到一些控制 flags 。
    staticBeanInfogetBeanInfo(类 beanClass, int flags)对Java bean进行内省,并了解其所有属性,公开方法和事件,并遵守一些控制标志。
    staticString[]getBeanInfoSearchPath()获取将用于查找BeanInfo类的包名称列表。
    staticvoidsetBeanInfoSearchPath(String[] path)更改将用于查找BeanInfo类的包名称列表。

    2.3.BeanInfo介绍

    JDK原文:

    • 使用BeanInfo界面创建一个BeanInfo类,并提供关于bean的方法,属性,事件和其他功能的显式信息。
    • 在开发您的bean时,您可以实现应用任务所需的bean功能,省略其余的BeanInfo功能。
    • 它们将通过自动分析获得,通过使用低级反射的bean方法和应用标准设计模式。 您有机会通过各种描述符类提供其他bean信息。

    关键方法介绍:

    修饰符返回类型方法名称和参数描述
    PropertyDescriptor[]getPropertyDescriptors()返回bean的所有属性的描述符。

    2.4用反射实现转换

    实体类:

    package com.sky.dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class UserDTO {
        private Long id;
        private String nickName;
        private String icon;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    方法封装:
    反射知识介绍:

    // 利用反射调用构造器实例化对象
    Object object = beanClass.getDeclaredConstructor().newInstance();
    // 通过实例化对象的class对象,获取所有的字段
    Field[] fields = object.getClass().getDeclaredFields();
    // 返回属性字段的修饰符
    int mod = field.getModifiers();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    关键方法:

    public Object mapToBean(Map<String,Object> map,Class<?> beanClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            // 利用反射调用构造器实例化对象
            Object object = beanClass.getDeclaredConstructor().newInstance();
            // 通过实例化对象的class对象,获取所有的字段
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field field : fields) {
                // 返回属性字段的修饰符
                int mod = field.getModifiers();
                // 如果是静态或者final修饰的不需要添加
                if (Modifier.isStatic(mod)|| Modifier.isFinal(mod)){
                    continue;
                }
                // 暴力获取私有属性
                field.setAccessible(true);
                // 相当于object.setterField()
                field.set(object,map.get(field.getName()));
            }
            return object;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.5.利用Introspector(内省)的方式转换

    public Object mapToBean2(Map<String,Object> map,Class<?> beanClass) throws Exception{
            // 利用class对象调用构造器实例化对象
            Object object = beanClass.getDeclaredConstructor().newInstance();
            // 内省Java bean并了解其属性,暴露的方法,==简单来说就是将属性封装到了BeanInfo里面==
            BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
            // 返回bean的所有属性的描述符。
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                /**
                 * java.beans.PropertyDescriptor[
                 * name=icon; values={expert=false; visualUpdate=false; hidden=false;
                 * enumerationValues=[Ljava.lang.Object;@75c77add; required=false};
                 * propertyType=class java.lang.String; readMethod=public java.lang.String com.sky.dto.UserDTO.getIcon();
                 * writeMethod=public void com.sky.dto.UserDTO.setIcon(java.lang.String)]
                 */
                System.out.println(propertyDescriptor);
                // 获取属性的setter方法
                Method setter = propertyDescriptor.getWriteMethod();
                if (setter!=null){
                    // 获取值
                    Object o = map.get(propertyDescriptor.getName());
                    if (o!=null){
                        // 利用反射将属性赋值
                        setter.invoke(object,o);
                    }
                }
            }
            return object;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    2022.07.19 随机数字python
    【ESD专题】2.ESD防护及保护器件(电介质和压敏电阻)
    轻重链剖分+启发式合并专题
    #力扣:136. 只出现一次的数字@FDDLC
    【仿牛客网笔记】 Spring Boot进阶,开发社区核心功能-私信列表
    windows中运行项目中.sh和kaggle安装与配置
    超声波传感器(CHx01) 学习笔记 Ⅵ - 原始数据
    蓝桥杯官网填空题(方格计数)
    企业文件传输使用网盘好还是大文件传输软件好?
    组件化与插件化
  • 原文地址:https://blog.csdn.net/weixin_46073538/article/details/127776470