#spring-boot #jackson
#spring-boot #джексон
Вопрос:
Перенесите это сюда с GitHub, поскольку команда Spring использует проблемы GitHub только для ошибок и запросов функций.
Согласно документации Spring Boot, должна быть возможность настроить Jackson ObjectMapper
с использованием свойств среды (например, в application.properties
), таких как spring.jackson.parser.<feature_name>
, до тех пор, пока вы не определяете свой собственный ObjectMapper
компонент.
Мне нужно активировать ALLOW_NON_NUMERIC_NUMBERS
функции синтаксического анализатора, поскольку я получаю (строго говоря, недопустимый) JSON со NaN
значениями для полей с плавающей запятой, которые я хочу, чтобы Jackson отображал java.lang.Double.NaN
в Java.
Итак, в моем, application.properties
я добавил spring.jackson.parser.ALLOW_NON_NUMERIC_NUMBERS=true
, и я вижу, что это подбирается:
- Spring Boot
JacksonAutoConfiguration
создаетJackson2ObjectMapperBuilder
Jackson2ObjectMapperBuilder
StandardJackson2ObjectMapperBuilderCustomizer
выбирает моеspring.jackson.parser.ALLOW_NON_NUMERIC_NUMBERS=true
свойство и добавляет его к своейfeatures
картеJackson2ObjectMapperBuilder
build()
Метод в конечном итоге вызываетconfigureFeature
, в результате чего значение маскиALLOW_NON_NUMERIC_NUMBERS
функции (512) добавляется к_parserFeatures
значению вJsonFactory
ObjectMapper
ObjectMapper
вводимая в мой компонент с помощью@Autowired
также имеетALLOW_NON_NUMERIC_NUMBERS
включенную функцию
Неясно, почему я все еще получаю следующую ошибку Jackson при разборе JSON, которая имеет NaN
значение для поля с плавающей запятой: JSON decoding error: Character N is neither a decimal digit number, decimal point, nor "e" notation exponential mark.
Сейчас я отлаживаю, поэтому, вероятно, в конечном итоге отвечу на свой собственный вопрос. Приведенная выше деталь, возможно, поможет людям, пришедшим из проблемы с GitHub, найти поток, к которому можно подключиться, если их флаги функций не применяются.
Комментарии:
1. Вместо использования
BigDecimal
в качестве типа вы можете использоватьNumber
. При включенииDeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS
функцииJackson
будет созданBigDecimal
экземпляр для чисел с плавающей запятой. В коде вы можете создать дополнительный геттерgetValueAsBigDecimal
и преобразоватьNumber
экземпляр вBigDecimal
или привести. В случаеNaN
это будетDecimal
экземпляр, который вы можете вернутьnull
при необходимости.
Ответ №1:
«Проблема» в том, что я пытаюсь сопоставить значения с плавающей точкой с BigDecimal
в Java, но 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);
}
}
}
Теперь я могу просто комментировать свои BigDecimal
поля с помощью @JsonDeserialize(using = NaNSafeBigDecimalDeserializer.class)
.