Mutual conversion between JavaBean object and Map in Java

1. JavaBean to Map

1.1. Introduction

This blog is implemented through reflection conversion

In learning redis, I found a knowledge point, which is to convert Java objects to maps. The content in the video is converted through the hutool tool, but we learners must not only use tools to convert, but more to learn through this knowledge point How to convert to his bottom layer.

1.2. Reflective Knowledge

// 新建一个对象
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.3. Simple conversion

@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. 4. Set attribute conversion in attribute

Entity class

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;
}

custom annotation

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 {
    
    
}

Conversion method:

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. 5. Summary

  • It is to judge whether recursive conversion is required through custom annotations
  • If it is nested, there should be other methods to study

2.Map to JavaBean object

2.1. Introduction

In actual projects, I believe that most people have used tool classes, such as commons and hutool tool classes, but we only know how to call this API, and don't know what kind of thinking is used to implement the bottom layer of other methods.
Through the understanding and learning of some bottom layers, you can learn more knowledge, understand some implementation methods of the bottom layer, and expand your thinking.
I'll start with how to convert a JavaBean object to a Map from below.

2.2. Introduction to Introspector

Introspector is a class under the java.beans package in the JDK, which provides a standard method for the target JavaBean to understand the original class methods, properties and events. In layman's terms, you can build a BeanInfo object through Introspector, and this BeanInfo object contains the description information of the properties, methods and events in the target class, and then you can use this BeanInfo object to perform related operations on the target object.

JDK original text:

  • The Introspector class provides a standard tool to understand the properties, events and methods supported by the target Java Bean.
  • For each of these three types of information, Introspector will analyze the bean's class and superclass separately, looking for explicit or implicit information, and use that information to build a BeanInfo object that fully describes the target bean.
  • For each class "Foo", explicit information may be available if a corresponding "FooBeanInfo" class exists, providing a non-null value when querying for information. We first look up the BeanInfo class by taking the full package-qualified name of the target bean class and appending "BeanInfo" to form a new class name. If that fails, then we use the final class name component of that name and look for the class in each package specified in the BeanInfo package search path.

Method introduction:

Modifier return type Method name and parameters describe
static String decapitalize(String name) Utility method to take a string and convert it to normal Java variable name case.
static void flushCaches() Flush all Introspector's internal caches.
static void flushFromCaches(class <?> clz) Flush internal cached information for a given class.
static BeanInfo getBeanInfo(class<?> beanClass) Introspect a Java Bean and learn about all its properties, exposed methods and events.
static BeanInfo getBeanInfo(class<?> beanClass, class<?> stopClass) Introspects a Java bean and understands its properties, exposed methods, below a given "stopping" point.
static BeanInfo getBeanInfo(class<?> beanClass, class<?> stopClass, int flags) Introspects a Java Bean and learns about all its properties, exposed methods and events, below a given stopClass point, subject to some controlling flags.
static BeanInfo getBeanInfo(类<?> beanClass, int flags) Introspect a Java bean and understand all its properties, exposed methods and events, and obey some control flags.
static String[] getBeanInfoSearchPath() Get a list of package names that will be used to look up BeanInfo classes.
static void setBeanInfoSearchPath(String[] path) Change the list of package names that will be used to look up BeanInfo classes.

2.3.BeanInfo Introduction

JDK original text:

  • Use the BeanInfo interface to create a BeanInfo class and provide explicit information about the bean's methods, properties, events, and other functionality.
  • When developing your bean, you implement the bean functionality needed for the application tasks, omitting the rest of the BeanInfo functionality.
  • They will be obtained through automatic analysis, by using low-level reflective bean methods and by applying standard design patterns. You have the opportunity to provide additional bean information through various descriptor classes.

Key method introduction:

Modifier return type Method name and parameters describe
none PropertyDescriptor[] getPropertyDescriptors() Returns descriptors for all properties of the bean.

2.4 Transformation with reflection

Entity class:

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;
}

Method Encapsulation:
Reflection Knowledge Introduction:

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

key method:

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;
    }

2.5. Using Introspector (introspection) to convert

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;
    }

Guess you like

Origin blog.csdn.net/weixin_46073538/article/details/127776470