Java Jackson如何将一个Pojo字段映射到2个(json)字段(相同的内容,不同的名称)

Java Jackson如何将一个Pojo字段映射到2个(json)字段(相同的内容,不同的名称),java,csv,jackson,mixins,jackson-dataformat-csv,Java,Csv,Jackson,Mixins,Jackson Dataformat Csv,我使用Jackson将POJOs序列化为CSV。现在我们需要将某些字段的命名更改为snake_case。这可以通过@JsonNaming(PropertyNamingStrategy.snakecasetracety.class)轻松实现 出于兼容性原因,我们需要一些重命名的字段也使用它们的旧名称 例如: 默认值将序列化为“someField”,SnakeCaseStrategy将序列化为“someField” 如何使用这两种方法获得序列化?: { "someField"

我使用
Jackson
POJO
s序列化为
CSV
。现在我们需要将某些字段的命名更改为snake_case。这可以通过
@JsonNaming(PropertyNamingStrategy.snakecasetracety.class)
轻松实现

出于兼容性原因,我们需要一些重命名的字段也使用它们的旧名称

例如:

默认值将序列化为“someField”,
SnakeCaseStrategy
将序列化为“someField”

如何使用这两种方法获得序列化?:

{
  "someField" : "one",
  "some_field" : "one" 
}
我的第一次尝试是混音:

public abstract class PojoFormat {

    @JsonProperty("someField")
    abstract String getSomeField();

}
但这实际上只会取消命名策略的更改。 因此,如何在序列化中复制字段—最好不要通过更改Pojo(当所有客户端都可以处理时,应该删除复制的字段)

小更新:


在我的真实类中,有一些使用的嵌套类,文档说明这不适用于自定义序列化程序(不知道这在这里有什么区别)。

好吧,我以前从未见过,如果这个站点中有人知道如何使用,我将非常高兴

在我看来,最简单的方法是使用自定义序列化程序

例如:

  • 使用@JsonSerialize注释
  • 注册模块
  • 带反射的动态序列化程序
  • @JsonSerialize注释
    import com.fasterxml.jackson.core.JsonGenerator;
    导入com.fasterxml.jackson.databind.SerializerProvider;
    导入com.fasterxml.jackson.databind.annotation.JsonSerialize;
    导入com.fasterxml.jackson.databind.ser.std.std序列化程序;
    @JsonSerializer(使用=PojoSerializer.class)
    Pojo类{
    私有字符串myValue;
    //接球手和接球手
    }
    类PojoSerializer扩展了StdSerializer{
    公共PojoSerializer(){
    超级(Pojo.class);
    }
    @凌驾
    public void serialize(Pojo值、JsonGenerator gen、SerializerProvider提供程序)引发IOException{
    gen.writeStartObject();
    gen.writeStringField(“myValue”,value.getMyValue());
    gen.writeStringField(“我的值”,value.getMyValue());
    writeEndObject将军();
    }
    }
    
    模块
    静态类Pojo{
    私有字符串myValue;
    公共字符串getMyValue(){
    返回myValue;
    }
    公共Pojo setMyValue(字符串myValue){
    this.myValue=myValue;
    归还这个;
    }
    }
    静态类PojoSerializer扩展了StdSerializer{
    公共PojoSerializer(){
    超级(Pojo.class);
    }
    @凌驾
    public void serialize(Pojo值、JsonGenerator gen、SerializerProvider提供程序)引发IOException{
    gen.writeStartObject();
    gen.writeStringField(“myValue”,value.getMyValue());
    gen.writeStringField(“我的值”,value.getMyValue());
    writeEndObject将军();
    }
    }
    公共静态void main(字符串[]args)引发JsonProcessingException{
    最终ObjectMapper映射器=新ObjectMapper();
    最终SimpleModule=新SimpleModule(“PojoModule”);
    addSerializer(Pojo.class,新的PojoSerializer());
    映射器注册表模块(模块);
    最终Pojo Pojo=新Pojo();
    setMyValue(“这是我的pojo的值”);
    System.out.println(mapper.writeValueAsString(pojo));
    }
    
    反射 我为你写了一些代码,你可能想看看,以获得新的想法。 这是一种通用方法(只是为了不编写多个序列化程序)

    //序列化程序将在ObjectMapper模块中注册。
    静态类Pojo{
    私有字符串myValue=“With snake and camel”;
    private String value=“不带蛇格”;
    私有字符串thirdValue=“snake&camel”;
    }
    //使用注释
    @JsonSerialize(使用=PojoSerializer.class)
    静态类Pojo2{
    私有字符串pojoName=“Pojo 2”;
    私有字符串pojo=“pojp”;
    }
    静态类PojoSerializer扩展了StdSerializer{
    公共PojoSerializer(){
    super(Object.class);
    }
    @凌驾
    public void serialize(对象值、JsonGenerator gen、SerializerProvider提供程序)引发IOException{
    gen.writeStartObject();
    最终字段[]字段=value.getClass().getDeclaredFields();
    用于(最终字段:字段){
    最终字符串名称=field.getName();
    最终字符串字段值;
    试一试{
    //不要用这个!
    fieldValue=(字符串)field.get(值);
    }捕获(非法访问例外e){
    抛出新的运行时异常(e);
    }
    字节firstUpperCase=-1;
    对于(字节索引=0;索引A'&字符
    您可以尝试使用注释并为每个
    POJO
    额外映射定义向后兼容性

    让我们创建一个简单的界面:

    interface CompatibleToVer1 {
    
        @JsonAnyGetter
        Map<String, Object> getCompatibilityView();
    }
    
    CsvSchema createSchemaFor(CompatibleToVer1 entity) {
        CsvSchema.Builder builder = CsvSchema.builder();
        entity.getCompatibilityView().keySet().forEach(builder::addColumn);
    
        return builder.build();
    }
    
    以上代码打印:

    {
      "root_id" : 1,
      "some_field" : 123,
      "some_name" : "Tom",
      "someField" : 123,
      "rootId" : 1
    }
    
    some_field,some_name,root_id,rootId,someField
    123,Tom,1,1,123
    124,Jerry,2,2,124
    
    但是对于
    CSV
    我们需要创建额外的配置:

    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));
    
    如果您不想两次指定额外的列,可以基于我们的界面实现生成器方法:

    interface CompatibleToVer1 {
    
        @JsonAnyGetter
        Map<String, Object> getCompatibilityView();
    }
    
    CsvSchema createSchemaFor(CompatibleToVer1 entity) {
        CsvSchema.Builder builder = CsvSchema.builder();
        entity.getCompatibilityView().keySet().forEach(builder::addColumn);
    
        return builder.build();
    }
    
    使用方法如下:

    CsvSchema compatibleSchema = CsvSchema.emptySchema()
            .withHeader()
            .withColumnsFrom(csvMapper.schemaFor(RootPojo.class))
            .withColumnsFrom(createSchemaFor(new RootPojo()))
            .withColumnsFrom(csvMapper.schemaFor(SomePojo.class))
            .withColumnsFrom(createSchemaFor(new SomePojo()));
    
    使用
    JsonAn
    
    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));
    
    some_field,some_name,root_id,rootId,someField
    123,Tom,1,1,123
    124,Jerry,2,2,124
    
    CsvSchema createSchemaFor(CompatibleToVer1 entity) {
        CsvSchema.Builder builder = CsvSchema.builder();
        entity.getCompatibilityView().keySet().forEach(builder::addColumn);
    
        return builder.build();
    }
    
    CsvSchema compatibleSchema = CsvSchema.emptySchema()
            .withHeader()
            .withColumnsFrom(csvMapper.schemaFor(RootPojo.class))
            .withColumnsFrom(createSchemaFor(new RootPojo()))
            .withColumnsFrom(csvMapper.schemaFor(SomePojo.class))
            .withColumnsFrom(createSchemaFor(new SomePojo()));