Джексон - Сериализация только идентификаторов объектов в атрибуте списка Java Pojo - PullRequest
0 голосов
/ 22 марта 2019

Я хочу оптимизировать данные 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"
  } ]
}

@Data - это lombok аннотация, используемая для генерации геттеров и сеттеров.

Я пытался добавить @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "invoiceId") аннотацию в класс Invoice, но это не меняет вывод.

Обратите внимание, что я хочу, чтобы эта сериализация с Invoice происходила только тогда, когда она передается в качестве дочернего элемента в контейнерную модель. Если я хочу отправить Инвойс независимо, он должен сериализовать все поля в модели Инвойса. Я считаю, что это распространенный сценарий при реализации RESTful WS.

Нужно ли для этого писать клиентский сериализатор?

Ответы [ 4 ]

0 голосов
/ 22 марта 2019

Я могу добиться этого, изменив класс 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

С этим я могу генерировать Customer jsonсо списком идентификаторов счетов.Объект Invoice при сериализации отдельно получает все значения из всех его полей в json.

0 голосов
/ 22 марта 2019

Вы можете использовать @JsonIgnore для включения свойств в ответе JSON.

Или вы можете использовать ключевое слово transient, чтобы избежать сериализации

0 голосов
/ 22 марта 2019

Рассмотрите следующий компонент как небольшую модификацию вашего случая:

@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 голосов
/ 22 марта 2019

Вы можете использовать @JsonAutoDetect в классе Invoice для сериализации только поля invoiceId, например ::10000 *

@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 проходит через провод, посмотрите документацию здесь .

Обновление

Если вы хотите иметь такое поведение только тогда, когда Invoice отправляется как вложенный объект, тогда вы можете установить другие поля на null (или не устанавливать эти поля в первую очередь) и использовать аннотацию @JsonInclude, например: :

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