带有 JsonDeserializer 的 Lombok
Lombok with JsonDeserializer
我有一个 JSON 字符串,我想将其反序列化为 class。 JSON 看起来像这样:
{ "data": { "name": "Box 1", "size": "10x20" } }
我可以将其反序列化为以下 class:
@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;
}
}
上面的 class 看起来很笨拙,因为它有一个无用的 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
和 returns 一个适当的 Dimension
,但我不能通过字段注释使用它(@JsonDeserialize(using = SizeDeserializer.class)
因为JsonDeserialize
class 注释的存在强制它在 Box1
的情况下被忽略,而在 Box2
的情况下,它被忽略,因为我正在手动构建框。
是否有解决所有这些混乱的优雅解决方案?我想要的是像这样将给定的 JSON 读入 class:
@Builder
@Value
public class Box3 {
@JsonProperty("name")
String name;
@JsonProperty("size")
Dimension size;
public static Box3 of(String json) {
...
}
}
谢谢!
阿西姆
您实际上不需要自定义反序列化器和 @JsonDeserialize
注释。 ObjectMapper
提供了一个配置来启用 wrapping/unwrapping 根值,可以使用包装对象 class.
上的 @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
部分,为此,您可以使用其他答案中提到的自定义反序列化器。
我将添加到@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);
}
}
}
我有一个 JSON 字符串,我想将其反序列化为 class。 JSON 看起来像这样:
{ "data": { "name": "Box 1", "size": "10x20" } }
我可以将其反序列化为以下 class:
@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;
}
}
上面的 class 看起来很笨拙,因为它有一个无用的 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
和 returns 一个适当的 Dimension
,但我不能通过字段注释使用它(@JsonDeserialize(using = SizeDeserializer.class)
因为JsonDeserialize
class 注释的存在强制它在 Box1
的情况下被忽略,而在 Box2
的情况下,它被忽略,因为我正在手动构建框。
是否有解决所有这些混乱的优雅解决方案?我想要的是像这样将给定的 JSON 读入 class:
@Builder
@Value
public class Box3 {
@JsonProperty("name")
String name;
@JsonProperty("size")
Dimension size;
public static Box3 of(String json) {
...
}
}
谢谢!
阿西姆
您实际上不需要自定义反序列化器和 @JsonDeserialize
注释。 ObjectMapper
提供了一个配置来启用 wrapping/unwrapping 根值,可以使用包装对象 class.
@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
部分,为此,您可以使用其他答案中提到的自定义反序列化器。
我将添加到@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);
}
}
}