Reputation: 13402
I have a object structure like the following:
public class Product {
int id;
String name;
Size[] sizes;
boolean organic;
}
public class Size {
int id;
String value;
@JsonIgnore String info;
}
While parsing the JSON for the Product class, I want to set the info for each of the sizes to the String
"Organic"
. In the setter for the organic
property I check the value and iterate over the sizes, setting the info for each.
@JsonProperty("organic")
public void setOrganic(boolean organic) {
this.organic = organic;
if (organic)
for(Size size : sizes) size.info = "Organic";
}
First, this approach seems to be brittle as it depends on the order of properties in the JSON and secondly, it doesn't always seem to work. For a production environment, where JSON has a lot more properties, I seem to be able to set the properties on the sub-object (Size
here) and read and log them during parsing but when I read it from the final deserialized object, those values are always null. Again, this behavior seems to be different for the smaller test cases I set up to test.
Does anyone know of a better way to do this ?
Upvotes: 1
Views: 2118
Reputation: 3959
The appropriate place to do this would be outside of these classes and some place where this type of business logic is more appropriate.
You could create a Builder class that allows you to set all of the properties for the resulting object and when the build() method that constructs the final object is called, set any additional values as appropriate. You would apply the Jackson annotations to the Builder class then, and apply any validation to it instead of the class that it creates. This way, you guarantee that any instance of a Product would be complete and valid.
If you take my original suggestion and move the logic into a business layer of your application then you would simply pass the Builders to the appropriate method, check the value of organic on the Product.Builder, and then iterate over the Size.Builder list and change their info values appropriately.
Using the Builders to hold the logic might look something like this (the logic you're looking for is all the way at the bottom):
public class Size {
private final int id;
private final String value;
private final String info;
public Size(int id, String value, String info) {
this.id = id;
this.value = value;
this.info = info;
}
public int getId() {
return id;
}
public String getValue() {
return value;
}
public String getInfo() {
return info;
}
public static class Builder {
private int id;
private String value;
private String info;
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setValue(String value) {
this.value = value;
return this;
}
@JsonIgnore
public Builder setInfo(String info) {
this.info = info;
return this;
}
public Size build() {
return new Size(id, value, info);
}
}
}
public class Product {
private final int id;
private final String name;
private final Size[] sizes;
private final boolean organic;
public Product(int id, String name, Size[] sizes, boolean organic) {
this.id = id;
this.name = name;
this.sizes = sizes;
this.organic = organic;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public Size[] getSizes() {
return sizes;
}
public boolean isOrganic() {
return organic;
}
public static class Builder {
private int id;
private String name;
private List<Size.Builder> sizeBuilders;
private boolean organic;
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setSizeBuilders(List<Size.Builder> sizeBuilders) {
this.sizeBuilders = sizeBuilders;
return this;
}
public Builder setOrganic(boolean organic) {
this.organic = organic;
return this;
}
public Product build() {
if (organic) {
for (Size.Builder sizeBuilder : sizeBuilders) {
sizeBuilder.setInfo("Organic");
}
}
Size[] sizes = new Size[sizeBuilders.size()];
for (int i = 0; i < sizeBuilders.size(); i++) {
sizes[i] = sizeBuilders.get(i).build();
}
return new Product(id, name, sizes, organic);
}
}
}
Upvotes: 1