Java - 如何反序列化为逻辑上相同的类?



我不想详细介绍,所以我会尽量简单地归结起来。我们有一个应用程序(Java,Spring Boot(,它可以生成一些信息,然后我们序列化并存储在数据库中。为了序列化它,我们使用 ObjectMapper:

final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.enableDefaultTyping(); // default to using DefaultTyping.OBJECT_AND_NON_CONCRETE
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
manifestJson = mapper.writeValueAsString(manifest);

然后将 JSON 存储在数据库中。呸呸呸。manifest是一个复杂的对象,其中包含许多其他用于创建最终产品的对象和信息。问题是当我们尝试使用该信息来生成新对象时。原始类的 FQN 与信息一起存储(有意义(。但是信息的回读发生在不同的位置/应用程序中。因此,虽然与 json 一起存储的原始命名空间是 a.b.c.d.e.f.class1 类型,但我们现在尝试将其读回类 a.b.c.g.h.i.f.class1 ...从逻辑上讲,class1 在两个命名空间中是相同的,实际上它是直接从一个命名空间复制到另一个命名空间的。唯一的区别是中间的包名称。

当然,当我们尝试反序列化 JSON 时,它会抛出一个关于找不到类型的错误,原始类型在原始项目/应用程序中,而"新"类型在当前项目中。我们可以从辅助应用引用原始应用,但出于功能原因,我们试图保持两者之间的解耦。

所以问题是,如何从一个项目中获取序列化的对象,然后将其反序列化为另一个逻辑上相同的类?

默认情况下,当不使用类型时,您可以生成一个JSON有效负载,稍后可以将其反序列化为适合此JSON的任何模型。或者,如果您根本不想创建模型,甚至可以Map或/和List对象。

在您的情况下,当具有两个不同模型的两个不同应用使用JSON有效负载时,不应附加类信息,因为它不会为另一个模型提供任何额外信息。一个JSON可以通过多种方式反序列化并用于不同的目的,因此将其与一个模型链接会导致您在示例中注意到的问题。因此,如果可以禁用键入并显式提供以后需要的所有信息才能从JSON重新创建同一对象。

如果无法做到这一点,只需提供自定义TypeIdResolver,并将一个类从一个模型映射到另一个模型中的类似类。显示一个想法的简单示例:

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.SimpleType;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
SimpleModule model2Module = new SimpleModule("Model2");
model2Module.setMixInAnnotation(PojoA2.class, CustomJsonTypeIdResolverMixIn.class);
model2Module.setMixInAnnotation(PojoB2.class, CustomJsonTypeIdResolverMixIn.class);
model2Module.setMixInAnnotation(PojoC2.class, CustomJsonTypeIdResolverMixIn.class);
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
mapper.registerModule(model2Module);
String json = mapper.writeValueAsString(new PojoA());
System.out.println(json);
System.out.println(mapper.readValue(json, PojoA.class));
System.out.println(mapper.readValue(json, PojoA2.class));
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM)
@JsonTypeIdResolver(value = Model2ClassNameIdResolver.class)
interface CustomJsonTypeIdResolverMixIn { }
class Model2ClassNameIdResolver extends ClassNameIdResolver {
private final Map<String, JavaType> types = new HashMap<>();
public Model2ClassNameIdResolver() {
super(null, null);
types.put("com.celoxity.PojoA", SimpleType.constructUnsafe(PojoA2.class));
types.put("com.celoxity.PojoB", SimpleType.constructUnsafe(PojoB2.class));
types.put("com.celoxity.PojoC", SimpleType.constructUnsafe(PojoC2.class));
}
@Override
public JavaType typeFromId(DatabindContext context, String id) throws IOException {
JavaType javaType = types.get(id);
if (javaType != null) {
return javaType;
}
return super.typeFromId(context, id);
}
}
class PojoA2 {
private PojoB2 b;
}
class PojoB2 {
private List<PojoC2> c;
}
class PojoC2 {
private String s;
private int i;
}
class PojoA {
private PojoB b;
}
class PojoB {
private List<PojoC> c;
}
class PojoC {
private String s;
private int i;
}

PojoAPojoBPojoCPojoA2PojoB2两种模型PojoC2具有相同的结构,只是名称不同。PojoAPojoA2等相同。

上面的代码打印:

["com.celoxity.PojoA",{"b":["com.celoxity.PojoB",{"c":["java.util.ArrayList",[["com.celoxity.PojoC",{"s":"Vika","i":22}]]]}]}]

后来:

PojoA{b=PojoB{c=[PojoC{s='Vika', i=22}]}}
PojoA2{b=PojoB2{c=[PojoC2{s='Vika', i=22}]}}

最新更新