Java 解码和反序列化字段的最简单方法,该字段的值是带Jackson的base64编码、字符串化JSON blob

Java 解码和反序列化字段的最简单方法,该字段的值是带Jackson的base64编码、字符串化JSON blob,java,spring-boot,jackson,json-deserialization,Java,Spring Boot,Jackson,Json Deserialization,在spring数据项目中,我们使用“标准”方法编写DTO,其中使用lombok的@Value和@Builder实现不变性,使用@JsonDeserialize(Builder=SomeClass.SomeClassBuilder.class)实现jackson反序列化 下面是一个简单的例子: @RestController class Controller { @PostMapping("/post") void post(@RequestBody PostBody body)

在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反序列化程序,但我很难理解各种不同类型的desrializer接口

到目前为止,我得到了类似的信息:

@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);
    }
}
@Value
@建筑商
@JsonDeserialize(builder=PostBody.PostBodyBuilder.class)
类PostBody{
字节[]id;
@JsonDeserialize(使用=clientDatabase64反序列化器.class)
ClientData ClientData;
@JsonPOJOBuilder(前缀为“”)
公共静态类PostBodyBuilder{}
}
//剪断
类ClientDatabase64反序列化程序扩展StdScalarDeserializer{
受保护的ClientDatabase64反序列化程序(){
super(ClientData.class);
}
@凌驾
公共ClientData反序列化(JsonParser、JsonParser、反序列化上下文、反序列化上下文)引发IOException、JsonProcessingException{
byte[]value=Base64.getDecoder().decode(jsonParser.getText());
System.out.println(新字符串(值));//打印字符串化的JSON
setCurrentValue(/*以某种方式将字符串化的JSON转换为树节点?*/value);
返回反序列化context.readValue(jsonParser,ClientData.class);
}
}
如果您有任何关于如何使用这个示例的想法,或者我可能缺少的解决这个问题的其他机制,我将不胜感激


干杯

在我提出问题的几分钟后,我终于解决了问题

ClientDatabase64反序列化器和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);
    }
}

@Value
@建筑商
@JsonDeserialize(builder=PostBody.PostBodyBuilder.class)
公营邮政机构{
字节[]id;
ClientData ClientData;
公共界面IPostBodyBuilder{
@JsonDeserialize(使用=clientDatabase64反序列化器.class)
PostBody.PostBodyBuilder客户端数据(clientData客户端数据);
}
@JsonPOJOBuilder(前缀为“”)
公共静态类PostBodyBuilder实现IPostBodyBuilder{}
}
类ClientDatabase64反序列化程序扩展StdScalarDeserializer{
私有最终ObjectMapper ObjectMapper;
受保护的ClientDatabase64反序列化程序(ObjectMapper ObjectMapper){
super(ClientData.class);
this.objectMapper=objectMapper;
}
@凌驾
公共客户端数据反序列化(
JsonParser JsonParser,反序列化上下文反序列化上下文
) {
byte[]value=jsonParser.readValueAs(byte[].class);
返回objectMapper.readValue(值,ClientData.class);
}
}

以一种真实的方式,我在提出问题几分钟后就设法解决了问题

ClientDatabase64反序列化器和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);
    }
}

@Value
@建筑商
@JsonDeserialize(builder=PostBody.PostBodyBuilder.class)
公营邮政机构{
字节[]id;
ClientData ClientData;
公共界面IPostBodyBuilder{
@JsonDeserialize(使用=clientDatabase64反序列化器.class)
PostBody.PostBodyBuilder客户端数据(clientData客户端数据);
}
@JsonPOJOBuilder(前缀为“”)
公共静态类PostBodyBuilder实现IPostBodyBuilder{}
}
类ClientDatabase64反序列化程序扩展StdScalarDeserializer{
私有最终ObjectMapper ObjectMapper;
受保护的ClientDatabase64反序列化程序(ObjectMapper ObjectMapper){
super(ClientData.class);
this.objectMapper=objectMapper;
}
@凌驾
公共客户端数据反序列化(
JsonParser JsonParser,反序列化上下文反序列化上下文
) {
byte[]value=jsonParser.readValueAs(byte[].class);
返回objectMapper.readValue(值,ClientData.class);
}
}