Jackson 用对象值反序列化 Json Patch

Jackson deserialise JsonPatch with object value

我正在使用 JsonPatch (JSR-374) 和 Apache org.apache.johnzon:johnzon-core:1.2.4 在我的 Spring 项目 PATCH 端点中实现:

@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请求一个简单的原子值

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

JsonPatch 实例被 Jackson 正确反序列化

但对于复杂值类型(对象):

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

抛出异常

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of javax.json.JsonPatch (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information at [Source: (PushbackInputStream); line: 1, column: 1]

我发现 JsonPatch(及其 Apache JsonPatchImpl)能够处理复杂类型,因为 JsonValue 提到了 JsonObject 和 ValueType.OBJECT,但我不知道如何指示 Jackson 正确反序列化

提前感谢您的任何建议或帮助!

我使用 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());
        ...
    }
}

编辑: 我通过将转换器注册为 bean 找到了更明智的解决方案。 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");
}
}