【Java工具类】Java对象与Map对象相互转换工具类(忽略空值、解决Intege数据转换为对象的Long型数据报错问题、转换LocalDateTime为时间戳)

文章介绍了使用CGLIB库在Java中实现Bean和Map之间的转换,包括基本转换、处理空值和时间类型的特殊处理。重点在于处理Integer/BigInteger与Long类型转换以及LocalDateTime转数字时间戳的情况。
摘要由CSDN通过智能技术生成

文章目录


正文

        Java对象和Map对象转换的方式有很多,比如:手动一个一个赋值(额... ...)、使用反射的方式(实现较为麻烦)、使用第三方工具类(如hutool、commons.beanutils等)、使用cglib(Sping、SpringBoot中已集成)。这里提供一种基于CGLIB编写的一个bean转map的一个工具类。

注:非Spring、SpringBoot项目需导cglib包:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version> <!-- 这里根据需求指定不同的版本 -->
</dependency>

 一、 Map转Bean

        最基础转换:

/**
 * bean转map
 *
 * @param object object
 * @return map
 */
public static Map<String, Object> toMap(Object object) {
    HashMap<String, Object> map = new HashMap<>();
    if (object != null) {
        BeanMap beanMap = BeanMap.create(object);
        beanMap.keySet().stream().forEach(key -> {
            map.put((String) key, beanMap.get(key));
        });
    }
    return map;
}

         是否忽略空值:

/**
 * bean转map
 *
 * @param object object
 * @param isIgnoreNull 是否忽略空值
 * @return map
 */
public static Map<String, Object> toMap(Object object, boolean isIgnoreNull) {
    HashMap<String, Object> map = new HashMap<>();
    if (object != null) {
        BeanMap beanMap = BeanMap.create(object);
        beanMap.keySet().stream().forEach(key -> {
            Object value = beanMap.get(key);
            if (isIgnoreNull && value == null) {
                return;
            }
            map.put((String) key, value);
        });
    }
    return map;
}

         LocalDateTime转数字时间戳:

/**
 * bean转map
 *
 * @param object object
 * @param isIgnoreNull 是否忽略空值
 * @param isFormat 是否格式化时间为时间戳
 * @return map
 */
public static Map<String, Object> toMap(Object object, boolean isIgnoreNull, boolean isFormat) {
    HashMap<String, Object> map = new HashMap<>();
    if (object != null) {
        BeanMap beanMap = BeanMap.create(object);
        beanMap.keySet().stream().forEach(key -> {
            Object value = beanMap.get(key);
            
            // 空值是否空值
            if (isIgnoreNull && value == null) {
                return;
            }
            
            // 是否时间类转换
            if (value instanceof LocalDateTime && isFormat) {
                value = ((LocalDateTime) value).atZone(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli();
            }
            map.put((String) key, value);
        });
    }
    return map;
}

二、Bean转Map

/**
 * map转bean
 *
 * @param map map
 * @param clazz 对象类型
 * @return object
 * @param <T> t
 */
public static <T> T toBean(Map map, Class<T> clazz) {
    T bean = null;
    try {
        bean = clazz.getDeclaredConstructor().newInstance();
        BeanMap beanMap = BeanMap.create(bean);
        
        beanMap.keySet().stream().forEach(paramName -> {
            Object value = map.get(paramName);
            if (value != null) {
                Class<?> paramType = beanMap.getPropertyType((String) paramName);
                
                // Integer、BigInteger转Long
                if (paramType.equals(Long.class) && value instanceof Integer) {
                    
                    // 若map中的数据类型为Integer、而对象中相应的数据类型为Long时:
                    value = ((Integer) value).longValue();
                    
                } else if (paramType.equals(Long.class) && value instanceof BigInteger) {
                    
                    // 若map中的数据类型为BigInteger、而对象中相应的数据类型为Long时
                    value = ((BigInteger) value).longValue();
                }
                
                // Long型纯数字时间戳转LocalDateTime
                if (paramType.equals(LocalDateTime.class) && value instanceof Long) {
                    value = Instant.ofEpochMilli((Long) value).atZone(ZoneId.of("Asia/Shanghai")).toLocalDateTime();
                }
                
                beanMap.put(paramName, value);
            }
        });
    } catch (Exception e) {
        log.info(e.getMessage());
    }
    return bean;
}

为什么需要解决map中的Integer、BigInteger数据和实体类中Long型字段不匹配的问题呢?

        是因为在使用redisTemplate与redis进行交换时,序列化器默认会根据redis中的value值自动匹配最佳的数据类型并反序列化为数据。当一个实体类以Hash的方式传入redis,再从redis中取出时得到一个map集合,原Long型值在这个新取出的map集合中可能会被反序列化为Integer、BigInteger等其他数据类型,从而无法被原实体类接收。因此需要在map转bean的过程中进行判断并转换数据类型。


三、测试

        这里随便创建了一个实体类用于测试:

@Data
public class MyTest {
    private String name;
    private Integer number;
    private List<?> list;
    private LocalDateTime time;
}

        测试:

@Test
void BeanMapUtilTest() {
    MyTest myTest = new MyTest();
    myTest.setName("Tom");
    myTest.setNumber(1145);
    myTest.setList(List.of("111", "222", "333"));
    myTest.setTime(LocalDateTime.now());
    System.out.println("实体类对象: " + myTest);
    
    Map<String, Object> map = BeanMapUtil.toMap(myTest, true);
    System.out.println("转换为Map: " + map);
    
    MyTest bean = BeanMapUtil.toBean(map, MyTest.class);
    System.out.println("转换为对象: " + bean);
}

         输出结果:

        成功!


四、完整代码:

//package...

import org.springframework.cglib.beans.BeanMap;

import java.math.BigInteger;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.Map;

public class BeanMapUtils {
    
    /**
     * bean转map
     *
     * @param object object
     * @return map
     */
    public static Map<String, Object> toMap(Object object) {
        try {
            HashMap<String, Object> map = new HashMap<>();
            if (object != null) {
                BeanMap beanMap = BeanMap.create(object);
                beanMap.keySet()
                       .stream()
                       .forEach(key -> {
                           map.put((String) key, beanMap.get(key));
                       });
            }
            return map;
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * bean转map
     *
     * @param object       object
     * @param isIgnoreNull 是否忽略空值
     * @return map
     */
    public static Map<String, Object> toMap(Object object, boolean isIgnoreNull) {
        try {
            HashMap<String, Object> map = new HashMap<>();
            if (object != null) {
                BeanMap beanMap = BeanMap.create(object);
                beanMap.keySet()
                       .stream()
                       .forEach(key -> {
                           Object value = beanMap.get(key);
                           if (isIgnoreNull && value == null) {
                               return;
                           }
                           map.put((String) key, value);
                       });
            }
            return map;
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * bean转map
     *
     * @param object       object
     * @param isIgnoreNull 是否忽略空值
     * @param isFormat     是否格式化时间为时间戳
     * @return map
     */
    public static Map<String, Object> toMap(Object object, boolean isIgnoreNull, boolean isFormat) {
        HashMap<String, Object> map = new HashMap<>();
        if (object != null) {
            BeanMap beanMap = BeanMap.create(object);
            beanMap.keySet()
                   .stream()
                   .forEach(key -> {
                       Object value = beanMap.get(key);
                       
                       // 空值是否空值
                       if (isIgnoreNull && value == null) {
                           return;
                       }
                       
                       // 是否时间类转换
                       if (value instanceof LocalDateTime && isFormat) {
                           value = ((LocalDateTime) value).atZone(ZoneId.of("Asia/Shanghai"))
                                                          .toInstant()
                                                          .toEpochMilli();
                       }
                       map.put((String) key, value);
                   });
        }
        return map;
    }
    
    /**
     * map转bean
     *
     * @param map   map
     * @param clazz 对象类型
     * @param <T>   t
     * @return object
     */
    public static <T> T toBean(Map map, Class<T> clazz) {
        try {
            T bean = clazz.getDeclaredConstructor()
                          .newInstance();
            BeanMap beanMap = BeanMap.create(bean);
            
            beanMap.keySet()
                   .stream()
                   .forEach(paramName -> {
                       Object value = map.get(paramName);
                       if (value != null) {
                           Class<?> paramType = beanMap.getPropertyType((String) paramName);
                           
                           // Integer、BigInteger转Long
                           if (paramType.equals(Long.class) && value instanceof Integer) {
                               
                               // 若map中的数据类型为Integer、而对象中相应的数据类型为Long时:
                               value = ((Integer) value).longValue();
                               
                           } else if (paramType.equals(Long.class) && value instanceof BigInteger) {
                               
                               // 若map中的数据类型为BigInteger、而对象中相应的数据类型为Long时
                               value = ((BigInteger) value).longValue();
                           }
                           
                           // Long型纯数字时间戳转LocalDateTime
                           if (paramType.equals(LocalDateTime.class) && value instanceof Long) {
                               value = Instant.ofEpochMilli((Long) value)
                                              .atZone(ZoneId.of("Asia/Shanghai"))
                                              .toLocalDateTime();
                           }
                           
                           beanMap.put(paramName, value);
                       }
                   });
            return bean;
        } catch (Exception e) {
            return null;
        }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狐笙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值