【问题标题】:Spring boot JsonMappingException: Object is nullSpring Boot JsonMappingException:对象为空
【发布时间】:2019-07-11 16:26:33
【问题描述】:

我有一个返回 net.sf.json.JSONObject 的@RestController:

@PostMapping("/list")
public JSONObject listStuff(HttpServletRequest inRequest, HttpServletResponse inResponse) {
    JSONObject json = new JSONObject();
    ...
    return json;
}

当 JSONObject 包含空引用时,会抛出以下异常:

Could not write JSON: Object is null; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Object is null (through reference chain: net.sf.json.JSONObject[\"list\"]->net.sf.json.JSONArray[0]->net.sf.json.JSONObject[\"object\"]->net.sf.json.JSONNull[\"empty\"])"

这是我们现在正在清理的遗留代码,在某些时候我们将摆脱显式 JSON 操作,但这将是一个巨大的变化,现在我只想摆脱异常。 我尝试了以下解决方案:

  1. 在 Spring 的 Object Mapper 中定义 Include.NON_NULL - 所以这段代码在我的 WebMvcConfigurationSupportClass 中:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) 
{
    ObjectMapper webObjectMapper = objectMapper.copy();
    webObjectMapper.setSerializationInclusion(Include.NON_NULL);
    converters.add(new MappingJackson2HttpMessageConverter(webObjectMapper)); 
}
  1. 在 application.yml 中设置以下属性: spring.jackson.default-property-inclusion=non_null
  2. 检查 com.fasterxml.jackson 的版本 - 在依赖关系树中找到的唯一版本是 2.9.7。

以上都没有帮助。

关于如何告诉 Spring 忽略 net.sf.json.JSONObjects 中的空值有什么建议吗?

【问题讨论】:

  • 你也试过spring.jackson.default-property-inclusion=NON_ABSENT吗?请注意,这是NON_ABSENT 而不是NON_NULL
  • 用 NON_ABSENT 和 NON_EMPTY 尝试了你的建议 - 仍然没有工作。
  • net.sf.json.JSONObject 类来自的库的名称和版本是什么?
  • &lt;groupId&gt;net.sf.json-lib&lt;/groupId&gt; &lt;artifactId&gt;json-lib&lt;/artifactId&gt;&lt;version&gt;2.4&lt;/version&gt;

标签: json spring spring-boot jackson


【解决方案1】:

Include.NON_NULL 不起作用,因为 JSONNull 代表 null 但它不是 null 本身。来自documentation

JSONNull 等价于 JavaScript 调用 null 的值,而 Java 的 null 等价于 JavaScript 调用的值 未定义。

这个对象被实现为Singleton,它有两个方法:isArrayisEmpty,其中isEmpty 是有问题的,因为会抛出异常。下面 sn-p 显示了它的实现:

public boolean isEmpty() {
   throw new JSONException("Object is null");
}

最好的方法是为JSONNull 类型定义NullSerializer。下面的示例显示了我们如何配置它:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        SimpleModule netSfJsonModule = new SimpleModule("net.sf.json");
        netSfJsonModule.addSerializer(JSONNull.class, NullSerializer.instance);

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.registerModule(netSfJsonModule);

        JSONObject object = new JSONObject();
        object.accumulate("object", JSONNull.getInstance());

        JSONArray jsonArray = new JSONArray();
        jsonArray.add(object);

        JSONObject json = new JSONObject();
        json.accumulate("list", jsonArray);

        System.out.println(mapper.writeValueAsString(json));
    }
}

上面的代码打印:

{
  "list" : [ {
    "object" : null
  } ]
}

另见:

  1. Maven: missing net.sf.json-lib
  2. How do you override the null serializer in Jackson 2.0?

【讨论】:

  • 听起来很合理,尽管它没有帮助。我添加了一个配置类:@Configuration public class JacksonConfiguration { @Bean @Primary public ObjectMapper objectMapper() { SimpleModule netSfJsonModule = new SimpleModule("net.sf.json"); netSfJsonModule.addSerializer(JSONNull.class, NullSerializer.instance); ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); mapper.registerModule(netSfJsonModule); return mapper;
  • @Tirlipirli,我不确定这个 bean 是否会被使用。您是否尝试过使用configureMessageConverters 方法配置它,就像您的问题一样?我知道注册自定义ObjectMapper 可能有问题。请尝试:In Spring Boot, adding a custom converter by extending MappingJackson2HttpMessageConverter seems to overwrite the existing converter
  • @Tirlipirli 或 Custom Jackson deserializer does not get registered in SpringCustomizing HttpMessageConverters with Spring Boot and Spring MVC。我知道,当MappingJackson2HttpMessageConverter 已存在于转换器列表中时,有时会出现覆盖问题。
  • 看起来 objectMapper() 方法被调用 - 没有结果,configureMessageConverters(...) 根本没有被调用。
  • @Tirlipirli,这很奇怪。您可以尝试将consumesproduces 设置为application/json 吗?
【解决方案2】:

这不是理想的解决方案,而是一种解决方法。由于覆盖默认映射器/转换器行为不起作用,因此我更改了 JSONObject 的结构,因此在其生成过程中添加了以下行:

listElt.put("object", "");

产生: { "list" : [ { "object" : "" } ] }

只有当我对此字段的值不感兴趣时​​才可以这样做 - 我不感兴趣。 我个人更喜欢@Michał Ziober 的解决方案——它优雅而通用。不幸的是对我不起作用。

【讨论】:

    猜你喜欢
    • 2015-05-31
    • 1970-01-01
    • 2017-08-06
    • 1970-01-01
    • 2017-10-29
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-22
    相关资源
    最近更新 更多