У меня есть следующий компонент Java:
public class Something {
@NotBlank
private final String value;
@JsonCreator
public Something(@JsonProperty("value")final String value) {
this.value = value;
}
public String getValue() {
return value;
}
@Override
public boolean equals(final Object o) {
return EqualsBuilder.reflectionEquals(this, o);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
И следующий служебный класс для обработки json-сериализации и десериализации
public class JsonUtils {
private final ObjectMapper objectMapper;
@Inject
public JsonUtils(final ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
public <T> T jsonToObject(final String jsonString, final Class<T> classType) {
try {
return objectMapper.readValue(jsonString, classType);
} catch (IOException e) {
throw new JsonException(ErrorMessage.ERROR_PARSE_JSON_TO_OBJECT, e);
}
}
public <V> String objectToJson(final V objectToBeParsed) {
try {
return objectMapper.writeValueAsString(objectToBeParsed);
} catch (IOException e) {
throw new JsonException(ErrorMessage.ERROR_PARSE_OBJECT_TO_JSON, e);
}
}
}
Здесь настраивается мой сопоставитель объектов
public class ParserModule extends AbstractModule {
@Provides
public ObjectMapper getObjectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(WRITE_DATES_AS_TIMESTAMPS);
objectMapper.enable(ALLOW_NUMERIC_LEADING_ZEROS);
objectMapper.findAndRegisterModules();
objectMapper.registerModule(getSerializersModule());
objectMapper.registerModule(getDeserializerModule());
return objectMapper;
}
private SimpleModule getSerializersModule() {
final SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Something.class, new SomethingSerializer());
return simpleModule;
}
private SimpleModule getDeserializerModule() {
final SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(Something.class, new SomethingDeserializer());
return simpleModule;
}
}
Этот объект JSON в конце будет возвращенным значением в теле ответа REST API, но спецификация API ожидает необработанную строку, содержащую только значение поля «значение». Итак, если my Something имеет значение "hello world"
, он должен возвращать hello world
в теле ответа, а не {"value":"hello world"}
.
Эта спецификация не была определена мной, я должен ее соблюдать, и она не может измениться.
Итак, я создал следующий сериализатор и десериализатор, которые зарегистрированы в сопоставлении объектов, как было показано ранее.
public class SomethingSerializer extends StdSerializer<Something> {
public SomethingSerializer() {
this(null);
}
public SomethingSerializer(final Class<Something> t) {
super(t);
}
@Override
public void serialize(final Something something, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeRawValue(something.getValue());
}
}
public class SomethingDeserializer extends StdDeserializer<Something> {
public SomethingDeserializer() {
this(null);
}
public SomethingDeserializer(final Class<?> t) {
super(t);
}
@Override
public Something deserialize(final JsonParser jsonParser, final DeserializationContext context) throws IOException {
return new Something(jsonParser.getCodec().readTree(jsonParser).toString());
}
}
Теперь фактическое значение, которое у меня есть в моем объекте something, не "hello world"
, а скорее строка, которая выглядит так: 01.something.this.that.org
. Обратите внимание на начальный ноль здесь.
Итак, всякий раз, когда я пытаюсь десериализовать такой объект:
Something result = jsonUtils.jsonToObject(response.getBody(), Something.class);
У меня исключение:
JsonParseException: Invalid numeric value: Leading zeroes not allowed
at [Source: (String)"01.something.this.that.org"; line: 1, column: 2]
Изучив это исключение в источнике Джексона, я обнаружил, что есть функция, которая позволяет мне «пропустить» это исключение, и я подумал, что нашел свое решение, поэтому я добавил это в свой сопоставитель объектов:
objectMapper.enable(ALLOW_NUMERIC_LEADING_ZEROS);
И теперь я больше не получаю исключения, круто. Но десериализованная строка становится: 1.something.this.that.org
. Итак, я вернулся к исходной точке.
Есть ли способ:
1) не получить исключение по ведущим нулям
2) фактически сохраните ведущие нули
Спасибо.
Редактировать:
На самом деле, после добавления функции, разрешающей начальные нули, мой первый тест состоял в том, чтобы проанализировать только значение 01
, которое вернуло 1
, но если я попытаюсь проанализировать образец строки, которую я дал здесь, я получаю другое исключение:
JsonParseException: Unexpected character ('s') in numeric value: Decimal point not followed by a digit at [Source: (String)"01.something.this.that.org"; line: 1, column: 5]
Итак, я предполагаю, что мой вопрос действительно в том, как я могу заставить Джексона интерпретировать необработанную строку как фактическую строку, поскольку прямо сейчас он, кажется, интерпретирует ее как число.
в некоторых случаях (например, в случае ошибок) API будет возвращать фактические правильные строки json, иначе я бы действительно просто рассматривал его как простой текст
Очень странно! Почему вы заставляете Джексона сериализовать и десериализовать то, что не является JSON?