【问题标题】:Lombok with JsonDeserializer带有 JsonDeserializer 的龙目岛
【发布时间】:2021-10-23 12:38:06
【问题描述】:

我有一个 JSON 字符串,我想反序列化为一个类。 JSON 看起来像这样:

{ "data": { "name": "Box 1", "size": "10x20" } }

我可以将其反序列化为以下类:

@Builder
@Value
@JsonDeserialize(builder = Box1.Box1Builder.class)
public class Box1 {

    @JsonProperty("data")
    Box1Data data;

    public static Box1 of(String json) throws IOException {
        return new ObjectMapper().readValue(json, Box1.class);
    }

    @Builder
    @Value
    @JsonDeserialize(builder = Box1Data.Box1DataBuilder.class)
    static class Box1Data {

        @JsonProperty("name")
        String name;

        @JsonProperty("size")
        String size;

    }

}

上面的类看起来很笨拙,因为它有一个无用的data 层次结构。我可以像这样摆脱它:

@Builder
@Value
@JsonDeserialize(using = Box2Deserializer.class)
public class Box2 {

    @JsonProperty("name")
    String name;

    @JsonProperty("size")
    String size;

    public static Box2 of(String json) throws IOException {
        return new ObjectMapper().readValue(json, Box2.class);
    }

    static class Box2Deserializer extends JsonDeserializer<Box2> {

        @Override
        public Box2 deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
            var node = jsonParser.getCodec().readTree(jsonParser);
            var dataNode = node.get("data");
            return Box2.builder()
                    .name(dataNode.get("name").toString())
                    .size(dataNode.get("size").toString())
                    .build();
        }
    }

}

但是在这里,我遇到了死胡同。我希望将 size 字段解析为 Dimension 实例。我可以为size 编写一个自定义反序列化器,它解析String 并返回一个正确的Dimension,但我不能通过字段注释使用它(@JsonDeserialize(using = SizeDeserializer.class),因为JsonDeserialize 类注释的存在迫使它被忽略对于Box1Box2,它被忽略了,因为我正在手动构建盒子。

是否有一个优雅的解决方案来解决所有这些混乱?我想要的是将给定的 JSON 读入这样的类:

@Builder
@Value
public class Box3 {

    @JsonProperty("name")
    String name;

    @JsonProperty("size")
    Dimension size;

    public static Box3 of(String json) {
        ...
    }

}

谢谢!

阿西姆

【问题讨论】:

  • 是否有某些原因导致您手动反序列化 Box2 而不是利用数据绑定?

标签: java json json-deserialization lombok


【解决方案1】:

我将添加到@Iprakashv 解决方案中,除了只需要JsonRootName 类型注释和用于根节点包装的映射器序列化/反序列化之外,您只需要一个从原始类型到自定义类型的自定义类型转换器:

@Builder
@Value
@JsonRootName("data")
public class Box {

    @JsonProperty("name")
    String name;

    @JsonDeserialize(converter = StringToDimensionConverter.class)
    @JsonProperty("size")
    Dimension size;

    public static Box of(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
        mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
        return mapper.readValue(json, Box.class);
    }

    private static class StringToDimensionConverter extends StdConverter<String, Dimension> {
        @Override
        public DataWrapper.Box1Data.Dimension convert(String s) {
            return new DataWrapper.Box1Data.Dimension(s);
        }
    }
}

【讨论】:

    【解决方案2】:

    您实际上不需要自定义反序列化器和 @JsonDeserialize 注释。 ObjectMapper 提供了一个配置来启用包装/解包根值,可以使用 Wrapper 对象类上的 @JsonRootName 注释来提供。

    @Builder
    @Value
    @JsonRootName("data")
    public class Box {
    
        @JsonProperty("name")
        String name;
    
        @JsonProperty("size")
        String size;
    
        public static Box of(String json) throws IOException {
            ObjectMapper mapper = new ObjectMapper();
            mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
            return mapper.readValue(json, Box.class);
        }
    }
    

    PS:完全错过了问题中的Dimension 部分,为此,您可以使用其他答案中提到的自定义反序列化器。

    【讨论】:

    • 谢谢你!看来,注解毕竟是相当强大的。 :)
    猜你喜欢
    • 2019-03-17
    • 1970-01-01
    • 2021-10-02
    • 2021-03-27
    • 2015-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    相关资源
    最近更新 更多