一尘不染

使用jackson和spring-boot将base64编码的JSON解码为POJO

spring-boot

我有这样的要求

{
    "varA"  : "A",
    "varB" : "TCFNhbiBKb3NlMRgwFgYDVQQK"
}

其中key varB是base64编码的JSON字符串。像这样的东西:

{
    "nestedVarB1": "some value here",
    "nestedVarB2" : "some other value here"
}

我想将其转换成这样的一些POJO:

@Data
public class MyRequest {
    private String varA;
    private B varB;
}

@Data
public class B {
    private String nestedVarB1;
    private String nestedVarB2;
}

如何将JSON直接转换为MyRequest使用Jackson和Spring Boot的转换?

注意:

  1. POJO MyRequestB非常大,B可以进一步嵌套,因此手动进行将是一项艰巨的任务。
  2. 我无法控制来自第三方的请求。因此,无法更改请求的格式。

阅读 662

收藏
2020-05-30

共1个答案

一尘不染

我已经做了一些实验,这是一个简单的Jackson Deserializer,应该可以为您工作。

Deserializer实现ContextualDeserializer接口以访问实际的bean属性(例如varB)。这是检测正确结果类型的必要条件,因为解串器本身可以附加到任何类型的字段。

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;

import java.io.IOException;
import java.util.Base64;

public class Base64Deserializer extends JsonDeserializer<Object> implements ContextualDeserializer {

    private Class<?> resultClass;

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext context, BeanProperty property) throws JsonMappingException {
        this.resultClass = property.getType().getRawClass();
        return this;
    }

    @Override
    public Object deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
        String value = parser.getValueAsString();
        Base64.Decoder decoder = Base64.getDecoder();

        try {
            ObjectMapper objectMapper = new ObjectMapper();
            byte[] decodedValue = decoder.decode(value);

            return objectMapper.readValue(decodedValue, this.resultClass);
        } catch (IllegalArgumentException | JsonParseException e) {
            String fieldName = parser.getParsingContext().getCurrentName();
            Class<?> wrapperClass = parser.getParsingContext().getCurrentValue().getClass();

            throw new InvalidFormatException(
                parser,
                String.format("Value for '%s' is not a base64 encoded JSON", fieldName),
                value,
                wrapperClass
            );
        }
    }
}

这是一个映射类的例子。

public class MyRequest {

    private String varA;

    @JsonDeserialize(using = Base64Deserializer.class)
    private B varB;

    public String getVarA() {
        return varA;
    }

    public void setVarA(String varA) {
        this.varA = varA;
    }

    public B getVarB() {
        return varB;
    }

    public void setVarB(B varB) {
        this.varB = varB;
    }
}
2020-05-30