Java Jackson 序列化摘要列表 Class
Java Jackson Serialize List of Abstract Class
场景
想象一下,我有一个名为 InfoItem
的抽象 class,从它继承的每个 class 都是一种不同类型的信息类型,稍后用于帮助我处理class化.
每个InfoItem
都有一个timestamp
作为一个属性(这个InfoItem
什么时候到)?
注意:我在这个例子中使用Lombok
@Data
@JsonTypeInfo(use = Id.NAME, visible = true, property = "@type")
public abstract class InfoItem {
private LocalDateTime timestamp;
}
我有 2 个 class 扩展这个 class:Alpha
和 Beta
。
每个 class 都有多个属性,它们之间没有共同的 属性:
@JsonTypeName("alpha")
@Data
public class Alpha extends InfoItem {
private int x;
private long y;
}
@JsonTypeName("beta")
@Data
public class Beta extends InfoItem {
private bool isOk;
}
现在假设我创建了一个包含 InfoItem
项的列表:
list[0] = Alpha(x = 10, y = 20)
list[1] = Beta(isOk = false)
问题
如果上面的列表被保存为一个名为 lst
的变量,那么我会 运行 这个命令:
ObjectMapper mapper = new ObjectMapper();
String s = mapper.writeValueAsString(lst);
System.out.println(s);
我会得到这个:
[
{
"x": 10,
"y": 20
},
{
"isOk": false
}
]
而不是:
[
{
"@type": "alpha",
"x": 10,
"y": 20
},
{
"@type": "beta",
"isOk": false
}
]
当我 运行 直接在 List
上 ObjectMapper
而不是我创建并放入列表的 class 时,就会发生这种情况。
案例:列表在我创建的class
如果我创建一个名为 FooBar
的 class,它有一个 属性 lst
(类型 List` - 同上):
@Data
public class FooBar {
private List<InfoItem> items;
}
然后我做:
FooBar bar = new FooBar();
bar.setItems(lst);
ObjectMapper mapper = new ObjectMapper();
String s = mapper.writeValueAsString(lst);
System.out.println(s);
我会得到:
{
"items": [
{
"@type": "alpha",
"x": 10,
"y": 20
},
{
"@type": "beta",
"isOk": false
}
]
}
如果你用这样的东西注释你的 abstract
class 就可以做到这一点(你可能需要根据你的需要调整它):
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Alpha.class, name = "_type"),
@JsonSubTypes.Type(value = Beta.class, name = "_type"),
})
当您生成 JSON 时,将插入一个 _type
键,其值为 Alpha
、Beta
等的 FQDN class。对于您的用例,它的工作方式应该类似。
查看 是否有助于了解更多背景知识。前一段时间我在做类似的事情——不过我还没有更新问题:)
几天后我找到了解决方案:
public static <T> Optional<String> toJson(final ObjectMapper mapper, final TypeReference<T> type, final T object) {
try {
return Optional.ofNullable(mapper.writer().forType(type).writeValueAsString(object));
} catch (JsonProcessingException e) {
return Optional.empty();
}
}
public static void main(String[] args) {
List<InfoItem> items = new ArrayList<>();
// Set values in items...
ObjectMapper mapper = new ObjectMapper();
Optional<String> json = toJson(mapper, new TypeReference<List<InfoItem>>() {}, items);
json.ifPresent(x -> System.out.println(x));
}
场景
想象一下,我有一个名为 InfoItem
的抽象 class,从它继承的每个 class 都是一种不同类型的信息类型,稍后用于帮助我处理class化.
每个InfoItem
都有一个timestamp
作为一个属性(这个InfoItem
什么时候到)?
注意:我在这个例子中使用Lombok
@Data
@JsonTypeInfo(use = Id.NAME, visible = true, property = "@type")
public abstract class InfoItem {
private LocalDateTime timestamp;
}
我有 2 个 class 扩展这个 class:Alpha
和 Beta
。
每个 class 都有多个属性,它们之间没有共同的 属性:
@JsonTypeName("alpha")
@Data
public class Alpha extends InfoItem {
private int x;
private long y;
}
@JsonTypeName("beta")
@Data
public class Beta extends InfoItem {
private bool isOk;
}
现在假设我创建了一个包含 InfoItem
项的列表:
list[0] = Alpha(x = 10, y = 20)
list[1] = Beta(isOk = false)
问题
如果上面的列表被保存为一个名为 lst
的变量,那么我会 运行 这个命令:
ObjectMapper mapper = new ObjectMapper();
String s = mapper.writeValueAsString(lst);
System.out.println(s);
我会得到这个:
[
{
"x": 10,
"y": 20
},
{
"isOk": false
}
]
而不是:
[
{
"@type": "alpha",
"x": 10,
"y": 20
},
{
"@type": "beta",
"isOk": false
}
]
当我 运行 直接在 List
上 ObjectMapper
而不是我创建并放入列表的 class 时,就会发生这种情况。
案例:列表在我创建的class
如果我创建一个名为 FooBar
的 class,它有一个 属性 lst
(类型 List` - 同上):
@Data
public class FooBar {
private List<InfoItem> items;
}
然后我做:
FooBar bar = new FooBar();
bar.setItems(lst);
ObjectMapper mapper = new ObjectMapper();
String s = mapper.writeValueAsString(lst);
System.out.println(s);
我会得到:
{
"items": [
{
"@type": "alpha",
"x": 10,
"y": 20
},
{
"@type": "beta",
"isOk": false
}
]
}
如果你用这样的东西注释你的 abstract
class 就可以做到这一点(你可能需要根据你的需要调整它):
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Alpha.class, name = "_type"),
@JsonSubTypes.Type(value = Beta.class, name = "_type"),
})
当您生成 JSON 时,将插入一个 _type
键,其值为 Alpha
、Beta
等的 FQDN class。对于您的用例,它的工作方式应该类似。
查看
几天后我找到了解决方案:
public static <T> Optional<String> toJson(final ObjectMapper mapper, final TypeReference<T> type, final T object) {
try {
return Optional.ofNullable(mapper.writer().forType(type).writeValueAsString(object));
} catch (JsonProcessingException e) {
return Optional.empty();
}
}
public static void main(String[] args) {
List<InfoItem> items = new ArrayList<>();
// Set values in items...
ObjectMapper mapper = new ObjectMapper();
Optional<String> json = toJson(mapper, new TypeReference<List<InfoItem>>() {}, items);
json.ifPresent(x -> System.out.println(x));
}