【问题标题】:How to enable 'ALLOW_NUMERIC_LEADING_ZEROS' feature to allow leading zeroes in JSON Request Body?如何启用“ALLOW_NUMERIC_LEADING_ZEROS”功能以允许 JSON 请求正文中的前导零?
【发布时间】:2025-12-02 03:45:01
【问题描述】:

根据 JSON 规范,我知道 JSON 中的整数中不允许有前导零。但根据 Jackson 文档,Jackson 库中有一个属性,即ALLOW_NUMERIC_LEADING_ZEROS,启用后,在找到前导零时不会引发异常。

我通过设置以下属性启用了属性ALLOW_NUMERIC_LEADING_ZEROS,但仍然出现错误:Leading zeroes not allowed

spring.jackson.parser.ALLOW_NUMERIC_LEADING_ZEROS=true

相关日志:

Caused by: com.fasterxml.jackson.core.JsonParseException: Invalid numeric value: Leading zeroes not allowed
at [Source: (PushbackInputStream); line: 8, column: 17]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1804) ~[jackson-core-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:663) ~[jackson-core-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.core.base.ParserMinimalBase.reportInvalidNumber(ParserMinimalBase.java:539) ~[jackson-core-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._verifyNoLeadingZeroes(UTF8StreamJsonParser.java:1489) ~[jackson-core-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._parsePosNumber(UTF8StreamJsonParser.java:1341) ~[jackson-core-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextFieldName(UTF8StreamJsonParser.java:1025) ~[jackson-core-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:376) ~[jackson-databind-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) ~[jackson-databind-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127) ~[jackson-databind-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:369) ~[jackson-databind-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) ~[jackson-databind-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001) ~[jackson-databind-2.9.4.jar:2.9.4]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3072) ~[jackson-databind-2.9.4.jar:2.9.4]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:235) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    ... 63 more

我通过执行以下代码验证了属性ALLOW_NUMERIC_LEADING_ZEROS是否已启用:

@Autowired
private ObjectMapper objectMapper;

@PostMapping(path = "random_path", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> fun123( @RequestBody RandomClass obj) throws Exception {

    log.info(" isEnabled = " + objectMapper.getFactory().isEnabled(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS));
    log.info(" isEnabled = " + objectMapper.isEnabled(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS));

    /*
        When correct request is given i.e. no leading zeroes in json body , then this function is successfully executed and
        output is true for above two statements  => i.e. feature 'ALLOW_NUMERIC_LEADING_ZEROS' is enabled.

        When leading zeroes are present in json request body, this function is not executed as an exception 'HttpMessageNotReadableException'
        is generated with error message 'Invalid numeric value: Leading zeroes not allowed'
    */

  ....
}

根据UTF8StreamJsonParser.javacode ,启用此属性时不应发生异常,但我不确定为什么会发生这种情况! 知道这背后的原因是什么吗?

来自UTF8StreamJsonParser.java的相关代码:

/**
 * Method called when we have seen one zero, and want to ensure
 * it is not followed by another
 */
private final int _verifyNoLeadingZeroes() throws IOException
{
    // Ok to have plain "0"
    if (_inputPtr >= _inputEnd && !_loadMore()) {
        return INT_0;
    }
    int ch = _inputBuffer[_inputPtr] & 0xFF;
    // if not followed by a number (probably '.'); return zero as is, to be included
    if (ch < INT_0 || ch > INT_9) {
        return INT_0;
    }
    // [JACKSON-358]: we may want to allow them, after all...
    if (!isEnabled(Feature.ALLOW_NUMERIC_LEADING_ZEROS)) {
        reportInvalidNumber("Leading zeroes not allowed");
    }

    ...
}

使用的杰克逊库版本:2.9.4

【问题讨论】:

    标签: spring jackson jackson2 fasterxml


    【解决方案1】:

    只是给遇到该问题并正在寻找更新的工作解决方案的人的说明:

    1. 在 maven 中导入最新版本的 fastxml jackson(截至今天为 2.11.0):

      <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.11.0</version> </dependency>

    2. 创建映射器对象:

      ObjectMapper objectMapper = new ObjectMapper();

    3. 允许数字前导零(未弃用的版本):

      objectMapper.enable(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS.mappedFeature());

    使用过的进口

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.core.json.JsonReadFeature;
    

    请记住,这将修剪前导 0。如果你想保留它们,那么你的 json 值不应该是数字。

    【讨论】:

      【解决方案2】:

      只需将以下属性放在您的 application.properties 文件中

      spring.jackson.parser.allow-numeric-leading-zeros=true
      

      如果没有设置默认,可以通过以下属性将jackson设置为默认转换器

      spring.http.converters.preferred-json-mapper=jackson
      

      【讨论】:

        【解决方案3】:

        MappingJackson2HttpMessageConverter 默认使用Jackson2ObjectMapperBuilder 类来构建ObjectMapper 类的新实例。要覆盖和使用容器中的ObjectMapper,我们需要覆盖JSON转换器:

        import com.fasterxml.jackson.databind.ObjectMapper;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.http.converter.HttpMessageConverter;
        import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
        import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
        
        import java.util.List;
        
        @Configuration
        public class JacksonMvcConfiguration extends WebMvcConfigurationSupport {
        
            @Autowired
            private ObjectMapper objectMapper;
        
            public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
                MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
                converter.setObjectMapper(objectMapper);
        
                return converter;
            }
        
            @Override
            protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                converters.add(mappingJackson2HttpMessageConverter());
                super.configureMessageConverters(converters);
            }
        }
        

        Customizing HttpMessageConverters with Spring Boot and Spring MVC。从现在开始,您应该能够解析带有前导零的数字了。

        【讨论】:

        • 好吧,我想使用 Spring MVC 使用的转换器,而不是自定义转换器。因此,我重写了函数configureMessageConverters(就像您在上面所做的那样),通过调用其中一个内部函数添加了默认转换器,并通过访问列表converters 启用了该属性。
        • @user,我使用Spring Boot 测试了我的示例。看起来MappingJackson2HttpMessageConverter 默认不使用由具有更新配置的容器创建的ObjectMapper。我们需要为MVC 转换器显式配置它。如果您认为我的回答对您有所帮助,请点赞。
        • 我观察到通过覆盖configuration 类来显式配置转换器的问题是Spring MVC 在初始化期间不再进行自动配置。一个人可能需要照顾这一切。例如:在上面(您的)代码中,所有其他默认转换器都不会添加到列表中。
        • @user,请参阅此答案How to configure MappingJacksonHttpMessageConverter while using spring annotation-based configuration? 并注意“调用 addDefaultHttpMessageConverters()”。
        【解决方案4】:

        这很可能是由于ObjectMapper Spring 端点使用的配置不同于映射器被注入到字段中。 为什么这是我不能说的——也许 Spring 用户列表会有所帮助。

        【讨论】:

        • 感谢您查看此内容。您是正确的,上面使用的注入映射器与 Spring MVC 内部使用的映射器不同。我通过覆盖WebMvcConfigurationSupport 类的函数configureMessageConverters 并检查它默认添加的转换器来验证这一点。我也不知道为什么会这样!我必须通过访问函数 configureMessageConverters 中的转换器来启用该属性。