Gson对Map中值为null的字段转换为空字符串输出

简介: 之前我写过一篇文章《Gson对字符串null的字段转换为空字符串输出》,有个兄弟评论说:定义返回的对象,code,msg,object data类型 data类型里面如果是List的map好像还是转不了。这次写一下关于Gson对Map中值为null的字段转换为空字符串输出。


问题背景

之前我写过一篇文章《Gson对字符串null的字段转换为空字符串输出》,有个兄弟评论说:定义返回的对象,code,msg,object data类型 data类型里面如果是List的map好像还是转不了。。

image-20211020230606185.png

上图代码的maps输出结果是:[{"id":"123"},{"id":"123"},{"id":"123"}]

看了上面的代码,不知道其他同学有什么想法?

我发现还是有人没有理解原理,如果不知道为什么,这时候debug源码很快就可以获得答案。

解析GSON适配器

Gson有自己适配器,所有map都会走默认的MapTypeAdapterFactory类。

在这个类里面write方法中,对value的判断调用valueTypeAdapter.write(out, entry.getValue());方法。代码如下:

@Overridepublicvoidwrite(JsonWriterout, Map<K, V>map) throwsIOException {
if (map==null) {
out.nullValue();
return;
      }
if (!complexMapKeySerialization) {
out.beginObject();
for (Map.Entry<K, V>entry : map.entrySet()) {
out.name(String.valueOf(entry.getKey()));
valueTypeAdapter.write(out, entry.getValue());
        }
out.endObject();
return;
      }
//...}

因为map的泛型在开始时并不知道key和value的类型是什么,所以在MapTypeAdapterFactory类初始化的时候,valueAdapter实际上是ObjectTypeAdapter方法。我们看下具体write方法:

@Overridepublicvoidwrite(JsonWriterout, Objectvalue) throwsIOException {
if (value==null) {
out.nullValue();
return;
    }
TypeAdapter<Object>typeAdapter= (TypeAdapter<Object>) gson.getAdapter(value.getClass());
if (typeAdapterinstanceofObjectTypeAdapter) {
out.beginObject();
out.endObject();
return;
    }
typeAdapter.write(out, value);
  }

因为value == null,所以最后调用JsonWriter.nullValue();

publicJsonWriternullValue() throwsIOException {
if (deferredName!=null) {
if (serializeNulls) {
writeDeferredName();
      } else {
deferredName=null;
returnthis; // skip the name and the value      }
    }
beforeValue();
out.write("null");
returnthis;
  }

到这里大家就明白了吧,我们没有配置serializeNulls,这里的serializeNulls == false,所以后面分支的注释已经说了:如果对于null值,会把它的name置空,跳过,也就是最后不输出。

问题根因大家知道了,解决办法应该有好几个:

(1)最常用的就是自定义一个map的adapter,让Gson启动加载,上篇文章自定义的string的适配器不是map的适配器,所以是不起作用的。

(2)重写MapTypeAdapterFactory类。

(3)改写JsonWriter类。

因为Gson很多类都是final的,无法继承覆写,还是使用第一个比较简单。

下面是我写的自定义map适配器:

publicclassMyMapTypeAdapter<K, V>extendsTypeAdapter<Map<K, V>>{
@Overridepublicvoidwrite(JsonWriterout, Map<K, V>map) throwsIOException    {
if (map==null)
        {
out.nullValue();
return;
        }
out.beginObject();
for (Map.Entry<K, V>entry : map.entrySet())
        {
out.name(String.valueOf(entry.getKey()));
// 核心代码在这里,如果value是null,输出空字符串Objectvalue= (entry.getValue() ==null) ?"" : entry.getValue();
newGson().getAdapter(Object.class).write(out, value);
        }
out.endObject();
return;
    }
@OverridepublicMap<K, V>read(JsonReadervar1) throwsIOException    {
// TODO Auto-generated method stubreturnnull;
    }
}

运行结果[{"name":"","id":"123"},{"name":"","id":"123"},{"name":"","id":"123"}]

gson.jpg


到这里,就解决了Map的value中为空就不输出的问题。


思考

上面有个细节,就是为啥Gson不对ObjectTypeAdapter中的null值提供写为""的方法?

因为我们常说的null其实是一种像量子态的引用类型,你可以说它没有类型,但是你又可以把它转为任何类型。

Gson不知道你传给它的null到底是(String)null,还是(Integer)null,也许String类型的null想变成"",也许Integer类型的null就想变成0。所以自由权还是给使用者,自己定义吧。

如果有人使用阿里的fastjson,对于map的null值处理也要自定义filter才行,默认的SerializerFeature.WriteNullStringAsEmpty不行。

备注:本文使用的 Gson 版本为 gson-2.5


我是Pandas,专注Java编程实用技术分享,微信公众号:Java实用技术手册\

关注可了解更多java技能和互联网面试技巧。问题或建议,请公众号留言。\

如果你觉得这篇文章对你有帮助,欢迎一键三连

相关文章
|
6月前
|
SQL Java 数据库连接
updateByPrimaryKeySelective()方法因字段为null导致的更新不成功问题解决办法
为了让这个解决方案更容易融入到现有系统中,其实现应该尽量简单且无缝,避免重复代码,并提高代码复用性。结合上述方法中提供的策略,应可以解决在使用 `updateByPrimaryKeySelective()`方法时因字段为null导致的更新不成功问题。请根据实际业务需求和上下文选择最合适的方案。这样的解决方案能够达到更佳的代码质量和维护性。
553 14
|
存储 JSON BI
关于建表字段是否该使用not null这个问题你怎么看?
V哥分享了在数据库设计中使用 `NOT NULL` 的重要性及应用场景。关键字段如用户名和邮箱应设为 `NOT NULL` 以确保数据完整性;可选字段如中间名和个人资料图片允许 `NULL` 提供更多灵活性。`NULL` 还可用于表示未知状态,如未发货的订单。外键设计需根据业务逻辑决定是否使用 `NOT NULL`。此外,`NOT NULL` 可优化查询性能,但在扩展性和数据兼容性方面,允许 `NULL` 更具优势。结合业务需求和数据统计,合理使用 `NOT NULL` 可确保数据完整性和灵活性。
296 3
|
Java 测试技术
Java系列之判断字符串是为空或者null
这篇文章介绍了如何在Java中使用`isEmpty()`方法判断字符串是否为空或`null`,并提供了相应的测试用例来演示其用法。
|
存储 JavaScript Java
Java中未被初始化的字符串打印出“null”?
在Java中,未初始化的`String`变量默认值为`null`。打印此类变量时输出“null”,是因为`PrintStream`类中的`print`方法特别处理了`null`值,将其转换为字符串“null”。从JDK 17开始,`println`方法通过`String.valueOf`间接实现相同功能。当拼接包含`null`的字符串时,如`s1 + &quot;BLACK&quot;`,结果为“nullBLACK”,这是因为字符串构建过程中`StringBuilder`的`append`方法将`null`转换为“null”。
274 2
|
Java 数据库连接 数据库
mybatis plus 更新值为null的字段
mybatis plus 更新值为null的字段
363 7
|
存储 分布式计算 DataWorks
MaxCompute产品使用合集之要存储用户的下单所有产品,然后查询时要进行产品分组的,一般这种字段要使用ARRAY还是MAP
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
分布式计算 DataWorks 数据可视化
MaxCompute产品使用问题之mongo离线同步导致null的字段不显示该怎么办
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
384 1
|
SQL 关系型数据库 MySQL
mysql不等于<>取特定值反向条件的时候字段有null值或空值读取不到数据
对于数据库开发的专业人士来说,理解NULL的特性并知道如何正确地在查询中处理它们是非常重要的。以上所介绍的技巧和实例可以帮助你更精准地执行数据库查询,并确保数据的完整性和准确性。在编写代码和设计数据库结构时,牢记这些细节将有助于你避免许多常见的错误,提高数据库应用的质量与性能。
545 0
|
SQL 分布式计算 大数据
MaxCompute产品使用合集之启用hive兼容的时候,某个字段是null,是否会把这个字段当成空白连起来
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
消息中间件 安全 Java
高德面试:为什么Map不能插入null?
在 Java 中,Map 是属于 java.util 包下的一个接口(interface),所以说“为什么 Map 不能插入 null?”这个问题本身问的不严谨。Map 部分类关系图如下: ![image.png](https://cdn.nlark.com/yuque/0/2024/png/92791/1717578225132-241fa833-180d-41ab-95eb-3d7cd1118633.png#averageHue=%233f3424&clientId=u395c5adf-4577-4&from=paste&height=687&id=u98d6a0bc&originHeig
216 1