文章目录
正文
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;
}
}
}