Jackson - 仅序列化Java Pojo的list属性中的Ids对象

问题描述 投票:0回答:4

我想优化要在线上发送的json数据。我的代码中有三个模型。这些是客户,发票和特殊。

客户类

@Data
public class Customer implements Serializable {

    private long customerId;

    private String name;

    private String taxId;

    private String phone;

    private String address;

    private String emailId;

    private Date created;

    private List<Invoice> invoices;
}

发票类

@Data
public class Invoice implements Serializable {

    private String invoiceId;

    private List<Particular> particulars;

    private Date invoiceDate;
}

特殊课程

@Data
public class Particular {
    private String item;
    private int quantity;
    private float tax;
    private int unitPrice;
}

我的测试代码:

@Test
    public void makeCustomerJsonWithInvoices() throws JsonProcessingException {
        Customer customer = new Customer();
        customer.setCustomerId(1234);
        customer.setName("Pawan");
        customer.setPhone("+918989898989");
        customer.setEmailId("[email protected]");
        customer.setAddress("Mumbai, India");
        customer.setTaxId("MQZ11DPS");
        customer.setCreated(new Date());

        Invoice invoice1 = new Invoice();
        invoice1.setInvoiceId("A-1");
        Particular particular1 = new Particular("abc", 1, 0, 12);
        Particular particular2 = new Particular("xyz", 2, 0, 20);
        invoice1.setInvoiceDate(new Date());
        invoice1.setParticulars(Arrays.asList(particular1, particular2));

        Particular particular3 = new Particular("mno", 2, 0, 15);
        Invoice invoice2 = new Invoice();
        invoice2.setInvoiceId("A-2");
        invoice2.setParticulars(Arrays.asList(particular3));
        invoice2.setInvoiceDate(new Date());
        customer.setInvoices(Arrays.asList(invoice1, invoice2));

        String value = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(customer);
        System.out.println(value);
    }

我想要的是通过序列化Invoice避免冗余,以便生成的json是紧凑的。这应该通过仅发送invoiceId属性值而不是整个Invoice对象json来实现。

测试代码打印的内容:

{
  "customerId" : 1234,
  "name" : "Pawan",
  "taxId" : "MQZ11DPS",
  "phone" : "+918989898989",
  "address" : "Mumbai, India",
  "emailId" : "[email protected]",
  "created" : 1553243962038,
  "invoices" : [ {
    "invoiceId" : "A-1",
    "particulars" : [ {
      "item" : "abc",
      "quantity" : 1,
      "tax" : 0.0,
      "unitPrice" : 12
    }, {
      "item" : "xyz",
      "quantity" : 2,
      "tax" : 0.0,
      "unitPrice" : 20
    } ],
    "invoiceDate" : 1553243962038
  }, {
    "invoiceId" : "A-2",
    "particulars" : [ {
      "item" : "mno",
      "quantity" : 2,
      "tax" : 0.0,
      "unitPrice" : 15
    } ],
    "invoiceDate" : 1553243962039
  } ]
}

我想要它打印:

{
  "customerId" : 1234,
  "name" : "Pawan",
  "taxId" : "MQZ11DPS",
  "phone" : "+918989898989",
  "address" : "Mumbai, India",
  "emailId" : "[email protected]",
  "created" : 1553243962038,
  "invoices" : [ {
    "invoiceId" : "A-1"
  }, {
    "invoiceId" : "A-2"
  } ]
}

@Data是用于生成getter和setter的lombok注释。

我试图将@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "invoiceId")注释添加到Invoice类,但这不会更改输出。

请注意,我希望这个序列化与Invoice仅在作为子项传递给容器Model时才会发生。如果我想独立发送Invoice,它应序列化Invoice模型中的所有字段。我相信这是实现RESTful WS时的常见场景。

我需要为此编写自定义序列化程序吗?

java json jackson jackson2
4个回答
0
投票

您可以使用@JsonIgnore忽略JSON响应中的属性。

或者您可以使用transient关键字来避免序列化


0
投票

考虑以下bean作为您案例的略微修改:

@Data
@JsonFilter("idOnlyFilter")
@AllArgsConstructor
class Complex {
    private String id;
    private List<String> aList;
    private Date aDate;
}

你可以使用@JsonFilter概念在你想要的每个bean上定义真正的粒度,序列化的条件是什么。请特别注意idOnlyFilter配置中的过滤器名称ObjectMapper以及@JsonFilter注释。

其工作原理如下:

@Test
public void includeOnlyOneField() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    FilterProvider filters = new SimpleFilterProvider()
            .addFilter("idOnlyFilter", SimpleBeanPropertyFilter.filterOutAllExcept("id"));

    Complex complex = new Complex("a string", List.of(), new Date());

    // when
    String complexAsString = mapper.writer(filters).writeValueAsString(complex);

    // then
    assertThat(complexAsString).isEqualTo("{\"id\":\"a string\"}");
}

0
投票

您可以在@JsonAutoDetect类上使用Invoice来仅序列化invoiceId字段,例如:

@JsonAutoDetect(
    fieldVisibility = Visibility.NONE,
    setterVisibility = Visibility.NONE,
    getterVisibility = Visibility.NONE,
    isGetterVisibility = Visibility.NONE,
    creatorVisibility = Visibility.NONE
)
@Data
public class Invoice implements Serializable {

    @JsonProperty (access = READ_ONLY)
    private String invoiceId;

    private List<Particular> particulars;

    private Date invoiceDate;
}

这将确保只有invoiceId通过电线,看看文档here

更新

如果你想只在Invoice作为嵌套对象发送时才有这种行为,那么你可以将其他字段设置为null(或者不首先设置那些字段)并使用@JsonInclude注释,例如:

@JsonInclude(Include.NON_NULL)
@Data
public class Invoice implements Serializable {
  ..
}

0
投票

我可以通过以下方式修改Customer类来实现此目的。

@Data
public class Customer implements Serializable {

    private long customerId;

    private String name;

    private String taxId;

    private String phone;

    private String address;

    private String emailId;

    private Date created;

    @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="invoiceId")
    @JsonIdentityReference(alwaysAsId=true)
    private List<Invoice> invoices;
}

答案来自https://stackoverflow.com/a/17583175/1365340

有了这个,我可以用发票ID列表生成Customer json。单独序列化时的Invoice对象将获取json中所有字段的所有值。

© www.soinside.com 2019 - 2024. All rights reserved.