JavaBeanToMap
标签:shm arraylist 没有 sim 重写 declared 友好 vcc types
背景
java接口返json时,会有字段为空,客户端不希望有为null的字段。
实现
方法一 使用统一json配置
- 程序启动方法继承 WebMvcConfigurerAdapter , 重写 configureMessageConverters 。
- 使用该方法遇到的问题:
- ① 在使用过程中遇到map或者list值出现类似
{"$ref":"$.data.list[0].batchInfo"}
的值。
网上搜索该现象为循环引用,解决方法可使用SerializerFeature.DisableCircularReferenceDetect。
循环引用:当一个对象包含另一个对象时,fastjson就会把该对象解析成引用。引用是通过$ref标示的,下面介绍一些引用的描述
"$ref":".." 上一级 "$ref":"@" 当前对象,也就是自引用 "$ref":"$" 根对象" $ref":"$.children.0" 基于路径的引用,相当于 root.getChildren().get(0)
- ② 基础对象(Integer、String、List、Map等)可以不输出null,但java实体类确不知道如何才能输出为{}。另外如果map的key为Integer,输出则也为数字(不使用该方法时json格式化会带引号,即为字符串),postman认为输出不可格式化,这块不知道是否会对客户端产生影响。
- 由于问题2未解决,故此方法未使用。
public class AppLauncher extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(AppLauncher.class);
}
@Override
public void configureMessageConverters(List> converters) {
super.configureMessageConverters(converters); // 不知道这句有什么用
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteMapNullValue, // 空map转{}
SerializerFeature.WriteNullNumberAsZero, // 空Integer转0
SerializerFeature.WriteNullStringAsEmpty, // 空String转""
SerializerFeature.WriteNullListAsEmpty // 空List转[]
);
// 处理中文乱码问题
List fastMediaTypes = new ArrayList();
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastConverter.setSupportedMediaTypes(fastMediaTypes);
fastConverter.setFastJsonConfig(fastJsonConfig);
//处理字符串, 避免直接返回字符串的时候被添加了引号——不知道这句有什么用
StringHttpMessageConverter smc = new StringHttpMessageConverter(Charset.forName("UTF-8"));
converters.add(smc);
}
}
方法二 针对部分可能为空的数据手动转map
- 该方法比较low,场景使用比较有限。但由于目前背景中,能确定只有几个对象可能为null,其他一定不为null。故可采用。
- 具体实现方式:1. 初始化赋值。2. 代码层面对map/list赋值过程中注意,如果为空则不赋值。(初始化已经为空map/list了)。3. 部分实体类使用工具类转为map。
- 使用内省方法处理的工具类如下:
关于内省和JavaBeanInfo的理解可参考(不是我的文章)
https://nicky-chen.github.io/2018/03/13/introspector/
public class ConvertUtil {
/**
* java对象转map
*/
public static Map javaBeanToMap(Object obj) {
if (obj == null) {
return MapUtils.emptyMap();
}
try {
// 通过intropestor分析出字节码对象的信息beaninfo
// 如果不想把父类的属性也列出来的话,那getBeanInfo的第二个参数填写父类的信息
// BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass(), Object.class);
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
// 通过调用getPro....方法获取对象的属性描述器
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
// 网上找的代码中没有判空,点进源码中看了下注释,是可能为空的,所以此处做判空校验
// 实现类 SimpleBeanInfo 直接返的null,其他实现类返的数组
if (propertyDescriptors == null || propertyDescriptors.length map = new HashMap(propertyDescriptors.length);
for (PropertyDescriptor property : propertyDescriptors) {
String key = property.getName();
// 过滤掉class属性
if (key.compareToIgnoreCase("class") == 0) {
continue;
}
Method getter = property.getReadMethod();
Object value;
if (getter != null) {
value = getter.invoke(obj);
if (value == null) {
value = MapUtils.emptyMap();
}
} else {
value = MapUtils.emptyMap();
}
map.put(key, value);
}
return map;
} catch (Exception e) {
log.error("javaBeanToMap failed : {}", e.getMessage());
return MapUtils.emptyMap();
}
}
}
- 在这之前用了个比较low的方法,这里面是反射获取的类的所有方法,然后获取属性名的时候是根据get切割来的,众所周知,get方法会把属性名首字母大写,于是又有了把首字母转为小写各种切割拼接,感觉很不友好,所以用了上面的方法。low方法如下:
public class ConvertUtil {
public static Map javaBeanToMap(Object obj) {
// 这里map初始化还不能设置初始值,因为不知道设为几,不友好
Map map = new HashMap();
List methods = getAllMethods(obj);
for (Method m : methods) {
String methodName = m.getName();
if (methodName.startsWith("get")) {
try {
//获取属性名,首字母小写
String propertyName = methodName.substring(3);
propertyName = (new StringBuilder()).append(Character.toLowerCase(propertyName.charAt(0)))
.append(propertyName.substring(1)).toString();
if (Objects.isNull(m.invoke(obj))) {
map.put(propertyName, MapUtils.emptyMap());
} else {
map.put(propertyName, m.invoke(obj));
}
} catch (Exception e) {
log.error("javaBeanToMap failed : {}", e.getMessage());
return MapUtils.emptyMap();
}
}
}
return map;
}
/**
* 获取obj中的所有方法
*/
private static List getAllMethods(Object obj) {
List methods = new ArrayList();
Class> clazz = obj.getClass();
while (!clazz.getName().equals("java.lang.Object")) {
methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
clazz = clazz.getSuperclass();
}
return methods;
}
}
JavaBeanToMap
标签:shm arraylist 没有 sim 重写 declared 友好 vcc types
原文地址:https://www.cnblogs.com/code-to-world/p/11010369.html
评论