Reputation: 1233
I want to optimize the json data to be sent on wire. I have three models in my code. These are Customer, Invoice and Particular.
The Customer class
@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;
}
The Invoice class
@Data
public class Invoice implements Serializable {
private String invoiceId;
private List<Particular> particulars;
private Date invoiceDate;
}
The Particular class
@Data
public class Particular {
private String item;
private int quantity;
private float tax;
private int unitPrice;
}
My test code:
@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);
}
What I want here is to avoid the redundancy by serializing the Invoice so that the resulting json would be compact. This should be achieved by only sending the invoiceId attribute value instead of whole Invoice object json.
What the test code prints:
{
"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
} ]
}
What I want it to print:
{
"customerId" : 1234,
"name" : "Pawan",
"taxId" : "MQZ11DPS",
"phone" : "+918989898989",
"address" : "Mumbai, India",
"emailId" : "[email protected]",
"created" : 1553243962038,
"invoices" : [ {
"invoiceId" : "A-1"
}, {
"invoiceId" : "A-2"
} ]
}
The @Data
is lombok annotation used to generate getters and setters.
I tried to add @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "invoiceId")
annotation to Invoice class but this doesn't change the output.
Note that I want this serialization with Invoice happen only when it is passed as a child to a container Model. If I want to send Invoice independently, it shall serialize all fields in Invoice model. I believe this is a common scenario while implementing RESTful WS.
Do I need to write customer serializer for this?
Upvotes: 2
Views: 2336
Reputation: 1233
I am able to achieve this by modifying the Customer class in following way.
@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;
}
The answer is inspired from https://stackoverflow.com/a/17583175/1365340
With this I can generate Customer
json with invoice Id list. The Invoice
object when serialized separately gets all values from all its fields in json.
Upvotes: 3
Reputation: 30819
You can use @JsonAutoDetect
on Invoice
class to serialize only invoiceId
field, e.g.:
@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;
}
This will make sure only invoiceId
goes through the wire, have a look at the documentation here.
Update
If you want to have this behaviour only when Invoice
is sent as nested object then you can set the other fields to null
(or not set those fields in the first place) and use @JsonInclude
annotation, e.g.:
@JsonInclude(Include.NON_NULL)
@Data
public class Invoice implements Serializable {
..
}
Upvotes: 0
Reputation: 2542
Consider the following bean as a slight modification of your case:
@Data
@JsonFilter("idOnlyFilter")
@AllArgsConstructor
class Complex {
private String id;
private List<String> aList;
private Date aDate;
}
You could use the @JsonFilter
concept to define really granular, on every bean you want, what the conditions for serializing are. Pay especially attention to the filter name idOnlyFilter
in the ObjectMapper
configuration as well as in the @JsonFilter
annotation.
This works as shown below:
@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\"}");
}
Upvotes: 0
Reputation: 695
You can use @JsonIgnore
for ingnoring properties in JSON response.
Or you can use transient
keyword for avoiding serialization
Upvotes: 0