在我们的 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"
}
如果我们能够在调用运行 ClientData
的反序列化器之前,作为 PostBody
反序列化的一部分,透明地解码和反字符串化该字段,那就太好了。
一种解决方案是为 PostBody
创建一个自定义反序列化器,但在实际示例中,还有更多字段需要手动处理。
我尝试创建自定义 ClientData 反序列化器,但我很难理解可用的各种不同类型的反序列化器接口(interface)。
到目前为止我已经得到了这样的东西:
@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);
}
}
如果您有任何有关如何继续此示例的想法,或者我可能缺少解决此问题的其他机制,我将不胜感激?
干杯
最佳答案
以真正的方式,我在提出问题后几分钟就设法解决了我的问题。
ClientDataBase64Deserializer 和 PostBody 的实现按预期工作:
@Value
@Builder
@JsonDeserialize(builder = PostBody.PostBodyBuilder.class)
public class PostBody {
byte[] id;
ClientData clientData;
public interface IPostBodyBuilder {
@JsonDeserialize(using = ClientDataBase64Deserializer.class)
PostBody.PostBodyBuilder clientData(ClientData clientData);
}
@JsonPOJOBuilder(withPrefix = "")
public static class PostBodyBuilder implements IPostBodyBuilder {}
}
class ClientDataBase64Deserializer extends StdScalarDeserializer<ClientData> {
private final ObjectMapper objectMapper;
protected ClientDataBase64Deserializer(ObjectMapper objectMapper) {
super(ClientData.class);
this.objectMapper = objectMapper;
}
@Override
public ClientData deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) {
byte[] value = jsonParser.readValueAs(byte[].class);
return objectMapper.readValue(value, ClientData.class);
}
}
关于java - 使用 Jackson 解码和反序列化其值为 Base64 编码、字符串化 JSON blob 的字段的最简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59645093/