【发布时间】:2020-04-25 22:39:42
【问题描述】:
在我们的 spring 数据项目中,我们使用“标准”方法来编写 DTO,其中我们使用 lombok 的 @Value 和 @Builder 来实现不变性,并使用 @JsonDeserialize(builder = SomeClass.SomeClassBuilder.class) 来实现 jackson 反序列化。
这是一个最小的例子:
@RestController
class Controller {
@PostMapping("/post")
void post(@RequestBody PostBody body) {
System.out.println(body);
}
}
@Value
@Builder
@JsonDeserialize(builder = PostBody.PostBodyBuilder.class)
class PostBody {
byte[] id;
ClientData clientData;
@JsonPOJOBuilder(withPrefix = "")
public static class PostBodyBuilder {}
}
@Value
@Builder
@JsonDeserialize(builder = ClientData.ClientDataBuilder.class)
class ClientData {
String something;
Integer somethingElse;
@JsonPOJOBuilder(withPrefix = "")
public static class ClientDataBuilder {}
}
正如您所期望的那样,使用普通的 JSON 有效负载可以正常工作,例如:
{
"id": "c29tZWlk",
"clientData": {
"something": "somethingValue",
"somethingElse": 1
}
}
但是,我们有一个用例,其中 clientData 结构是已知的,但出于原因,它作为 base64 编码的字符串化 JSON blob 发送,例如:
{
"id": "c29tZWlk",
"clientData": "eyJzb21ldGhpbmciOiJzb21ldGhpbmdWYWx1ZSIsInNvbWV0aGluZ0Vsc2UiOjF9"
}
如果我们能在 PostBody 调用运行 ClientData 的反序列化器之前,透明地解码和反序列化该字段作为反序列化的一部分,那就太好了。
一种解决方案是为PostBody 创建一个自定义反序列化器,但在实际示例中,需要手动处理更多字段。
我尝试创建自定义 ClientData 反序列化器,但我很难理解可用的无数不同类型的反序列化器接口。
到目前为止,我有类似的东西:
@Value
@Builder
@JsonDeserialize(builder = PostBody.PostBodyBuilder.class)
class PostBody {
byte[] id;
@JsonDeserialize(using = ClientDataBase64Deserializer.class)
ClientData clientData;
@JsonPOJOBuilder(withPrefix = "")
public static class PostBodyBuilder {}
}
// SNIP
class ClientDataBase64Deserializer extends StdScalarDeserializer<ClientData> {
protected ClientDataBase64Deserializer() {
super(ClientData.class);
}
@Override
public ClientData deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
byte[] value = Base64.getDecoder().decode(jsonParser.getText());
System.out.println(new String(value)); // prints stringified JSON
jsonParser.setCurrentValue(/* somehow convert stringified JSON to a Tree Node? */ value);
return deserializationContext.readValue(jsonParser, ClientData.class);
}
}
如果您有任何关于如何使用此示例取得进展的想法,或者我可能缺少解决此问题的其他机制,我将不胜感激?
干杯
【问题讨论】:
标签: java spring-boot jackson json-deserialization