gpt4 book ai didi

java - Jackson 在对丢失的属性(property)进行反序列化期间抛出 NPE

转载 作者:行者123 更新时间:2023-12-02 11:34:08 25 4
gpt4 key购买 nike

我在尝试反序列化 JSON 时仍然遇到 NPE。如果属性丢失,我希望设置默认值(0/null)。这是我的 Spring Boot 配置 bean:

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
jsonConverter.setObjectMapper(objectMapper());
return jsonConverter;
}

ObjectMapper objectMapper() {
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(ProductBasicDto.class, new ProductDeserializer());

ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);

mapper.registerModule(simpleModule);
return mapper;
}

我的自定义解串器:

@Override
public ProductBasicDtoWrapper deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
System.out.println(node.get("id").asLong()); // here it throws NPE
return null; // ignore that, just for testing
}

json:

{
"name": "js",
"category": "CoNiFer"
}

和执行:

java.lang.NullPointerException: null
at api.product.infrastructure.ProductDeserializer.deserialize(ProductDeserializer.java:19)
at api.product.infrastructure.ProductDeserializer.deserialize(ProductDeserializer.java:14)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3072)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:235)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:223)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:206)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:157)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:130)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:870)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:776)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:881)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855)
  1. 如何避免此 NPE?
  2. 如果属性(如本例中的 id)丢失,是否可以在解串器中不进行显式检查的情况下放入 0/null 值?

编辑:添加了一些代码示例

假设这是我的 DTO 类:

class MyDto implements Serializable {
private final String firstName;
private final String lastName;
}

现在我正在创建我的自定义映射器:

@Override
public ProductBasicDtoWrapper deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException,
JsonProcessingException {
objectMapper.convertValue(jsonNode, MyDto.class);

...

现在我决定向 MyDto 添加额外的 Integer:

    class MyDto implements Serializable {
private final String firstName;
private final String lastName;
private final Integer age;
}

这很棒,不需要更改任何其他内容(在我的映射器类中)。但假设我得到了这种 json

 {
"firstName": "name"
}

现在它会抛出 NPE。所以想法是检查映射器中的值是否为空。让我们开始吧:

@Override
public ProductBasicDtoWrapper deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException,
JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
node.get("firstName") == null ?
node.get("lastName") == null ?
node.get("age") == null ?

}

好吧,现在可以了,现在假设我向 DTO 类添加了一个属性

class MyDto implements Serializable {
private final String firstName;
private final String lastName;
private final Integer age;
private final String card;

}

问题是,在这种情况下,我还必须更改我的映射器类,因为未处理第四个参数。

最佳答案

该行返回 null

node.get("id") // returns null when property is not defined

因为该属性显然没有在 JSON 中定义。您可以通过多种方式解决您的问题,但在使用 get(name) 以及 asLong、asString 等方法之一时,您始终必须检查 null,或者仅检查该属性是否定义为有(名称)

您还可以使用辅助函数

public static Long getLong(JsonNode node, String name) {
if (node.get(name) != null && node.get(name).isLong()) {
return node.get(name).asLong();
} else {
return null;
}
}

你可以返回null,或者抛出异常,如果返回null你应该小心,稍后再处理。

然后用它来打印变量或未定义时为 null。

System.out.println(getLong(node, "id"));

编辑(根据编辑的问题):

当您配置对象映射器时,您可以使用配置方法指定它的严格程度,您可以使用 DeserializationFeature 枚举来指示它何时应该失败以及何时不应该失败。

在这里您可以看到每个功能及其用途: https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/DeserializationFeature.html

现在,如果类中的属性名称和 json 匹配,您可以将 json 转换为 dto 对象,如下所示:

ObjectMapper mapper = new ObjectMapper() // object mapper with wanted properties
.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES,

mapper.readValue(json, MyDto.class);

这里您只需要创建映射器(不需要反序列化器),然后将其转换为目标类。

如果类和 json 中有不同的名称,则必须使用注释 @JsonProperty 并指定名称。

可能出现的问题:

现在,我在 DTO 中看到您使用了最终属性,当您使用它们时,您必须创建一个带参数的构造函数,并且不能创建一个空构造函数(至少没有事先指定它的值),这个空构造函数对于 java POJO 是必需的,并且由对象映射器在内部使用。

所以你的 DTO 应该是这样的:

class MyDto implements Serializable {
private String firstName;
private String lastName;
private Integer age;
// empty constructor (only necessary when another constructor is specified)
// getters and setters
}

如果您仍然需要使用 Immutable 对象而不是 POJO,您可以创建如下所示的类:

class MyDto implements Serializable {
private final String firstName;
private final String lastName;
private final Integer age;
@JsonCreator
MyDto(@JsonProperty("firstName") String firstName,
@JsonProperty("lastName") String lastName,
@JsonProperty("age") Integer age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
// getters
}

使用映射器

使用上面的 POJO 类和对象映射器,您可以执行以下操作:

MyDto myDto1 = mapper.readValue("{\"firstName\": \"name\"}", MyDto.class); // object with firstName defined, lastName and age are null
MyDto myDto2 = mapper.readValue("{\"firstName\": \"name\",\"lastName\": \"last\"}", MyDto.class); // object with firstName and lastName defined, age is null
MyDto myDto3 = mapper.readValue("{\"firstName\": \"name\",\"lastName\": \"last\",\"age\": 1}", MyDto.class); // object with firstName, lastName and age defined

您甚至可以使用空对象或具有未知属性。

MyDto myDto4 = mapper.readValue("{}", MyDto.class); // object with all properties null
MyDto myDto5 = mapper.readValue("{\"blablah\": \"name\"}", MyDto.class); // object with all properties null

关于java - Jackson 在对丢失的属性(property)进行反序列化期间抛出 NPE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49070317/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com