You can try to use JsonAnyGetter annotation and define for every POJO
extra mapping for backward compatibility.
Let's create a simple interface:
interface CompatibleToVer1 {
@JsonAnyGetter
Map<String, Object> getCompatibilityView();
}
and two classes which implement it:
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
class RootPojo implements CompatibleToVer1 {
private int rootId;
@JsonUnwrapped
private SomePojo pojo;
@Override
public Map<String, Object> getCompatibilityView() {
return Collections.singletonMap("rootId", rootId);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
class SomePojo implements CompatibleToVer1 {
private int someField;
private String someName;
@Override
public Map<String, Object> getCompatibilityView() {
Map<String, Object> extra = new LinkedHashMap<>();
extra.put("someField", someField);
return extra;
}
}
As you can see, I defined extra columns for each POJO
with custom names. Serialising to JSON
is straightforward:
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
SomePojo pojo = new SomePojo(123, "Tom");
mapper.writeValue(System.out, new RootPojo(1, pojo));
Above code prints:
{
"root_id" : 1,
"some_field" : 123,
"some_name" : "Tom",
"someField" : 123,
"rootId" : 1
}
But for CSV
we need to create extra configuration:
CsvMapper csvMapper = CsvMapper.builder().build();
CsvSchema pojoExtraScheme = CsvSchema.builder()
.addColumn("someField")
.build();
CsvSchema rootExtraScheme = CsvSchema.builder()
.addColumn("rootId")
.build();
CsvSchema compatibleSchema = CsvSchema.emptySchema()
.withHeader()
.withColumnsFrom(csvMapper.schemaFor(RootPojo.class))
.withColumnsFrom(rootExtraScheme)
.withColumnsFrom(csvMapper.schemaFor(SomePojo.class))
.withColumnsFrom(pojoExtraScheme);
SomePojo tom = new SomePojo(123, "Tom");
SomePojo jerry = new SomePojo(124, "Jerry");
List<RootPojo> pojos = Arrays.asList(new RootPojo(1, tom), new RootPojo(2, jerry));
ObjectWriter writer = csvMapper.writer(compatibleSchema);
System.out.println(writer.writeValueAsString(pojos));
Above code prints:
some_field,some_name,root_id,rootId,someField
123,Tom,1,1,123
124,Jerry,2,2,124
If you do not want to specify extra columns two times you can implement builder method based on our interface:
CsvSchema createSchemaFor(CompatibleToVer1 entity) {
CsvSchema.Builder builder = CsvSchema.builder();
entity.getCompatibilityView().keySet().forEach(builder::addColumn);
return builder.build();
}
and use as below:
CsvSchema compatibleSchema = CsvSchema.emptySchema()
.withHeader()
.withColumnsFrom(csvMapper.schemaFor(RootPojo.class))
.withColumnsFrom(createSchemaFor(new RootPojo()))
.withColumnsFrom(csvMapper.schemaFor(SomePojo.class))
.withColumnsFrom(createSchemaFor(new SomePojo()));
Using JsonAnyGetter
with CSV
is really tricky and could be problematic mixing it with other annotations, take a look at: Could please add JsonAnyGetter and JsonAnySetter annotations support?