Джексон десериализует JsonPatch со значением объекта - PullRequest
0 голосов
/ 09 апреля 2020

Я использую JsonPatch (JSR-374) с реализацией из Apache org. apache .johnzon: johnzon-core: 1.2.4 в моей конечной точке PATCH проекта Spring:

@Bean
@Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.createXmlMapper(false).build();
    objectMapper.registerModule(new Jdk8Module());
    objectMapper.registerModule(new JSR353Module());
    return objectMapper;
}

Контроллер

@PatchMapping("/settings")
public ResponseEntity<SettingsResponse> patchSettings(@RequestBody JsonPatch patchDocument, Locale locale) {...}

С json запросом простого атома c значения

[
  { "op": "replace", "path": "/currency", "value": "EUR" },
  { "op": "test", "path": "/version", "value": 10 }
]

Экземпляр JsonPatch правильно десериализован Джексоном

Но с комплексным типом значения (объект):

[
  { "op": "replace", "path": "/currency", "value": {"code": "USD", "label": "US Dollar"} },
  { "op": "test", "path": "/version", "value": 10 }
]

Возникло исключение

Причина: com.faster xml .jackson.databind.ex c .InvalidDefinitionException: Невозможно создать экземпляр javax.json.JsonPatch (создатели, такие как конструкция по умолчанию, не существуют): абстрактные типы либо должны быть сопоставлены с конкретными типами, либо иметь собственный десериализатор, либо содержать дополнительную информацию о типе в [Source: (PushbackInputStream); строка: 1, столбец: 1]

Я считаю, что JsonPatch (и его Apache JsonPatchImpl) способен работать со сложными типами, поскольку JsonValue упоминает JsonObject и ValueType.OBJECT, но я не знаю как поручить Джексону правильно десериализовать

Заранее благодарим за любые предложения или помощь!

1 Ответ

0 голосов
/ 13 апреля 2020

Я прошел через это с помощью реализации JSR-364 Json .createPatch:

@PatchMapping("/settings")
public ResponseEntity<SettingsResponse> patchDefaultSettingsJsonP3(@RequestBody String patchString, Locale locale) {
    try (JsonReader jsonReader = Json.createReader(new StringReader(patchString))) {
        JsonPatch patch = Json.createPatch(jsonReader.readArray());
        ...
    }
}

РЕДАКТИРОВАТЬ: я нашел более разумное решение, зарегистрировав конвертер в качестве компонента. Затем Spring заботится о десериализации внутри страны

@Component
public class JsonPatchHttpMessageConverter extends AbstractHttpMessageConverter<JsonPatch> {

public JsonPatchHttpMessageConverter() {
    super(MediaType.valueOf("application/json-patch+json"), MediaType.APPLICATION_JSON);
}

@Override
protected boolean supports(Class<?> clazz) {
    return JsonPatch.class.isAssignableFrom(clazz);
}

@Override
protected JsonPatch readInternal(Class<? extends JsonPatch> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
    try (JsonReader reader = Json.createReader(inputMessage.getBody())) {
        return Json.createPatch(reader.readArray());
    } catch (Exception e) {
        throw new HttpMessageNotReadableException(e.getMessage(), inputMessage);
    }
}

@Override
protected void writeInternal(JsonPatch jsonPatch, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
    throw new NotImplementedException("The write Json patch is not implemented");
}
}
...