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

时间:2019-03-22 08:50:02

标签: java json jackson jackson2

我想优化要在线发送的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("something@something.com");
        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);
    }

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

测试代码显示什么:

{
  "customerId" : 1234,
  "name" : "Pawan",
  "taxId" : "MQZ11DPS",
  "phone" : "+918989898989",
  "address" : "Mumbai, India",
  "emailId" : "something@something.com",
  "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" : "something@something.com",
  "created" : 1553243962038,
  "invoices" : [ {
    "invoiceId" : "A-1"
  }, {
    "invoiceId" : "A-2"
  } ]
}

@Datalombok批注,用于生成获取器和设置器。

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

请注意,我希望仅当将发票作为子级传递到容器模型时,才使用发票进行序列化。如果我想独立发送发票,它将在发票模型中序列化所有字段。我相信这是实施RESTful WS时的常见情况。

我需要为此编写客户序列化程序吗?

4 个答案:

答案 0 :(得分: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(或不首先设置这些字段)并使用{{ 1}}注释,例如:

@JsonInclude

答案 1 :(得分:0)

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

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

答案 2 :(得分: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\"}");
}

答案 3 :(得分:0)

我可以通过以下方式修改Customer类来实现这一目标。

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
</head>

<body>
  <div style=" width:256px; height:256px; margin:20px auto; ">

    <svg id="artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256">
			<style type="text/css"> 
        @import url('https://fonts.googleapis.com/css?family=M+PLUS+1p');
        text {
          font-family: 'M PLUS 1p';
        }
			</style>

			<a xlink:href="#">
				<circle cx="57" cy="57" r="54.5" fill="#767dcc"/>
				<text transform="translate(33.916 87)" font-size="90" font-family="M PLUS 1p">1</text>
			</a>
		</svg>

  </div>

</body>

</html>

答案受https://stackoverflow.com/a/17583175/1365340

的启发

这样,我可以生成带有发票ID列表的@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; } json。 Customer对象在单独序列化时会从json中其所有字段中获取所有值。