根据JSON规范,我知道JSON中的整数中不允许使用前导零。但根据杰克逊的文档,杰克逊图书馆中有一个属性,即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.java
的代码,启用此属性时,应该不会发生异常,但我不确定为什么会发生这种情况!知道这背后的原因是什么吗?
来自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
只需将以下属性放在您的application.properties
文件中
spring.jackson.parser.allow-numeric-leading-zeros=true
如果未设置默认值,您可以通过以下属性将杰克逊设置为默认转换器
spring.http.converters.preferred-json-mapper=jackson
这很可能是由于Spring端点使用的ObjectMapper
配置与注入字段的映射器不同。 为什么会这样我不能说 - 也许Spring用户列表可以提供帮助。
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);
}
}
请参阅使用 Spring Boot 和 Spring MVC 自定义 HttpMessageConverters。从现在开始,您应该能够解析带有前导零的数字。
对于遇到该问题并正在寻找更新的工作解决方案的人来说,这只是一个说明:
-
在 maven 中导入最新版本的 fasterxml jackson(截至今天的 2.11.0):
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.11.0</version> </dependency>
-
创建映射器对象:
ObjectMapper objectMapper = new ObjectMapper();
-
允许数字使用前导零(未弃用的版本):
objectMapper.enable(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS.mappedFeature());
二手进口:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.json.JsonReadFeature;
请记住,这将修剪前导 0。如果要保留它们,则 json 值不应为数字。