提问人:Łukasz Wiecheć 提问时间:11/3/2023 最后编辑:Łukasz Wiecheć 更新时间:11/15/2023 访问量:32
如何在Java Jackson中创建从多个文件读取/写入的自定义(反)序列化程序?
How to create customized (de-)serializer in Java Jackson that read/writes from multiple files?
问:
我试图把我的想法总结在以下几点上:我想使用Jackson(反)序列化来自多个文件的POJO - 序列化程序会写一个“每个类的文件”。
我尝试序列化的对象包含对其他对象的引用:
public class DumpObject {
String field1;
SomeClass field2;
SomeOtherClass field3;
}
最后,我希望序列化写入 3 个文件: ,如下所示:dumpobject.json
{ "field1": "value1" }
然后用序列化的内容和类似的 for .someclass.json
SomeClass
SomeOtherClass
我正在努力评估最好的方法是否是“告诉”在这种“每个类的文件”场景中创建(反)序列化程序/ObjectMapper
到目前为止,我已经尝试了将所有 JSON 转储到单个文件的简单(反)序列化程序。
更新我想问题是是否可以根据当前正在序列化的类配置为将序列化更改为多个 s / 'JsonGenerator's。ObjectMapper
ObjectWriter
更新 2我已经“修复”了这个问题,方法是将 的实例传递给序列化程序,然后在其中为我想在另一个文件中序列化的列表的每个元素创建:ZipFOutputStream
ZipEntries
public class CustomDBDumpListSerializer extends StdSerializer<DBDumpList> {
/** the name of the 'main' entry in the ZIP file*/
public static final String MAIN_ENTRY = "DBDumpList.json";
private final ZipOutputStream zos;
public CustomDBDumpListSerializer(ZipOutputStream zos) {
this(null, zos);
}
public CustomDBDumpListSerializer(Class<DBDumpList> t, ZipOutputStream zos) {
super(t);
this.zos = zos;
}
@Override
public void serialize(DBDumpList toSerialize, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
List<String> repositories = new ArrayList<>(); // will hold repositories
// the entries need to be processed in 'natural order', here following the DBDumpDto's
toSerialize.sort(Comparator.comparing(DBDumpDto::getSyncOrder));
int i = 1;
for(DBDumpDto dto : toSerialize) {
// we need to maintain the uniqueness of the zip entries; repos can be
ZipEntry ze = new ZipEntry(i + "_" + dto.getRepository() + ".json");
zos.putNextEntry(ze);
JsonGenerator gen2 = jgen.getCodec().getFactory().createGenerator(zos);
gen2.writePOJO(dto);
log.debug("wrote to zip entry {}", ze);
repositories.add(ze.getName());
i++;
}
ZipEntry zz = new ZipEntry(MAIN_ENTRY);
zos.putNextEntry(zz);
jgen.writeStartObject();
provider.defaultSerializeField("dateLastCheck", toSerialize.getDateLastCheck(), jgen);
provider.defaultSerializeField("repositories", repositories, jgen);
jgen.writeEndObject();
}
}
反序列化程序的构造类似:传递一个实例,以便它可以在 zip 文件中找到序列化的 JSON,同时遍历存储库列表:ZipFile
public class CustomDBDumpListDeserializer extends StdDeserializer<DBDumpList> {
private final ZipFile zipfile;
public CustomDBDumpListDeserializer(ZipFile zipfile) {
this(null, zipfile);
}
public CustomDBDumpListDeserializer(Class<DBDumpList> t, ZipFile zipfile) {
super(t);
this.zipfile = zipfile;
}
@Override
public DBDumpList deserialize(JsonParser aParser, DeserializationContext aContext) throws IOException, JsonProcessingException {
DBDumpList ret = new DBDumpList();
ObjectCodec codec = aParser.getCodec();
JsonNode node = codec.readTree(aParser);
JsonNode dateNode = node.get("dateLastCheck");
ret.setDateLastCheck(LocalDateTime.parse(dateNode.asText()));
// alternative: deserialize from the list of filenames that
JsonNode repositoriesNode = node.get("repositories");
if(!repositoriesNode.isNull() && repositoriesNode.isArray()) {
repositoriesNode.iterator().forEachRemaining(Errors.rethrow().wrap(r -> {
String rSanitized = r.toString().replace("\"", "");
log.debug("trying to deser entry {}", rSanitized);
if(rSanitized.endsWith("Repository.json")) {
// now we should be able to find the ZipEntry with the name
ZipEntry zz = zipfile.getEntry(rSanitized);
if(zz == null) {
throw new IOException("ZipEntry " + rSanitized + " cannot be found");
}
try(InputStream is = zipfile.getInputStream(zz)) {
JsonParser p = codec.getFactory().createParser(is);
ret.add(p.readValueAs(DBDumpDto.class));
}
}}));
}
return ret;
}
}
然后我可以像这样序列化我的对象:
public File saveDBDumpPackage(DBDumpPackage dbDumpPackage, String filenamePrefix) throws IOException {
File zipFile = fileHelper.createTempFile(filenamePrefix, ".zip");
try(ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
// 1. configure jackson's ObjectMapper with custom (de)serializers
SimpleModule dbDumplListModule = new SimpleModule();
dbDumplListModule.addSerializer(DBDumpList.class, new CustomDBDumpListSerializer(zos));
ObjectMapper om = JsonMapper.builder()
.addModule(new JavaTimeModule())
.addModule(dbDumplListModule).build();
// better format for the dates
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om.writeValue(zos, dbDumpPackage);
}
return zipFile;
}
并像这样反序列化:
public DBDumpPackage getDBDumpPackageFromFile(File file) throws IOException {
if (file==null)
return null;
ZipFile zf = new ZipFile(file);
SimpleModule dbDumplListModule = new SimpleModule();
dbDumplListModule.addDeserializer(DBDumpList.class, new CustomDBDumpListDeserializer(zf));
ObjectMapper om = JsonMapper.builder()
.addModule(new JavaTimeModule())
.addModule(dbDumplListModule).build();
// better format for the dates
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// 4. check if we can deserialize: first position in the stream
ZipEntry zz = zf.getEntry(CustomDBDumpListSerializer.MAIN_ENTRY);
if(zz == null ) {
throw new IOException("cound not find the main entity");
}
//System.out.println("found 'main' DBDumpList.json zipentry, we can proceed");
try(InputStream zis = zf.getInputStream(zz)) {
return om.readValue(zis, DBDumpPackage.class);
}
}
答: 暂无答案
评论
#readValue
ObjectMapper