spring-boot - 如何自定义 Jackson ObjectMapper 以在 Spring Boot 2.0 中允许 NaN?

标签 spring-boot jackson

将其从 GitHub 移至此处因为 Spring 团队仅使用 GitHub 问题来处理错误和功能请求。

根据 Spring Boot documentation ,应该可以定制Jackson ObjectMapper使用环境属性(例如在 application.properties 中),例如 spring.jackson.parser.<feature_name>只要您没有定义自己的 ObjectMapper bean 。

我需要激活ALLOW_NON_NUMERIC_NUMBERS解析器功能,因为我使用 NaN 获取(严格来说无效)JSON我希望 Jackson 映射到的浮点字段的值 java.lang.Double.NaN在Java中。

所以在我的 application.properties 中我添加了spring.jackson.parser.ALLOW_NON_NUMERIC_NUMBERS=true我可以看到这个正在被接收:

  • Spring Boot 的 JacksonAutoConfiguration正在创建 Jackson2ObjectMapperBuilder
  • Jackson2ObjectMapperBuilderStandardJackson2ObjectMapperBuilderCustomizer正在接我的spring.jackson.parser.ALLOW_NON_NUMERIC_NUMBERS=true属性并将其添加到其 features map
  • Jackson2ObjectMapperBuilderbuild()方法最终调用configureFeature其结果是 ALLOW_NON_NUMERIC_NUMBERS 的掩码值功能 (512) 被添加到 _parserFeatures JsonFactory 中的值ObjectMapper
  • ObjectMapper使用@Autowired注入(inject)我的bean中还有ALLOW_NON_NUMERIC_NUMBERS功能已启用

不清楚的是为什么我在解析具有 NaN 的 JSON 时仍然收到以下 Jackson 错误浮点字段的值: JSON decoding error: Character N is neither a decimal digit number, decimal point, nor "e" notation exponential mark.

我现在正在调试,所以我可能最终会回答我自己的问题。以上细节可能会对来自the GitHub issue的人有所帮助。找到一个线程来拉动,以防它们的功能标志没有被应用。

最佳答案

“问题”是我试图将浮点值映射到Java中的BigDecimal,但是BigDecimal没有表示NaN (或 (-)Inf )。问题源于 com.fasterxml.jackson.databind.util.TokenBuffer.Parser ,它在 public BigDecimal getDecimalValue() 中执行以下操作:

    return BigDecimal.valueOf(n.doubleValue());

最终(在java.match.BigDecimal中)将 double 值转换为字符串"NaN",然后将其传递到BigDecimal 构造函数,它用 NumberFormatException 拒绝它以及我在问题中提到的错误消息:

throw new NumberFormatException("Character " + c
    + " is neither a decimal digit number, decimal point, nor"
    + " \"e\" notation exponential mark.");

就我而言,我很高兴将 NaN 映射到 null,但我知道这对于每个使用 Jackson 的人来说并不是正确的行为,所以我写了一个自定义解串器来做到这一点:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;

import java.io.IOException;
import java.math.BigDecimal;

public class NaNSafeBigDecimalDeserializer extends JsonDeserializer<BigDecimal> {

    private BigDecimal nanValue = null;

    @Override
    public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        if (p.isNaN()) {
            return nanValue;
        } else {
            return NumberDeserializers.BigDecimalDeserializer.instance.deserialize(p, ctxt);
        }
    }
}

现在我可以使用 @JsonDeserialize(using = NaNSafeBigDecimalDeserializer.class) 注释我的 BigDecimal 字段

关于spring-boot - 如何自定义 Jackson ObjectMapper 以在 Spring Boot 2.0 中允许 NaN?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63899402/

相关文章:

java - 使用 JSONConfiguration.FEATURE_POJO_MAPPING 的 HTTP 错误代码 422

java - 将多维数组从 Mongodb 映射到 Java 应用程序

java - 忽略基于 Spring Boot 配置文件的测试类

java - 使用 native 查询的 JPA 查询返回 null 而不是实体列表

ssl - Grails 3.3 中基于 "CLIENT-CERT"的 X509 证书认证

java - Spring Boot GET 请求 API

java - JsonMappingException : No suitable constructor found for type -- for an external object

java - 如何映射两个文件中的键和值?

tomcat - Spring Integration 与 Spring Boot 作为 war 运行

java - 防止 Tomcat 覆盖 Controller 建议返回的错误响应