Reputation: 1152
Let's say I have a class like this that I want to serialize with Jackson.
public class Product {
int id;
String name;
List<Product> similarProducts;
}
How do I end up with something like this?
{
"id": 1,
"name": "Product 1",
"similarProducts": [
{
"id": 2,
"name": "Product 2"
},
{
"id": 3,
"name": "Product 3"
}
]
}
I've see how to use @JsonProperty to do this by class or @JsonView to select things too but that also seems like it's by class (am I mistaken)? I'm not sure how to get this to work when I have a class that's referencing itself and the parent has many properties, while the child only has a few.
Imagine this is an ecommerce site and you want to get the name and URL of similar products from a single JSON payload, but you don't need any other details of those similar products (children).
Upvotes: 2
Views: 1298
Reputation: 225
You can also accomplish this with a custom Serializer if you ALWAYS want this behavior (seems in this case it could be dangerous to not include the filter since errors will result in the self reference case)
Model:
public class Product {
public int id;
public String name;
@JsonSerialize(contentUsing=ProductSerializer.class)
public List<Product> similarProducts = Lists.newArrayList();
}
Serializer:
public class ProductSerializer extends JsonSerializer<Product> {
@Override
public void serialize(Product product, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", product.id);
jgen.writeStringField("name", product.name);
jgen.writeEndObject();
}
}
Example:
Product p1 = new Product();
Product p2 = new Product();
p1.similarProducts = Lists.newArrayList(p2);
p2.similarProducts = Lists.newArrayList(p1);
p1.id = 1;
p2.id = 2;
p1.name = "p1";
p2.name = "p2";
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(p1));
Output:
{"id":1,"name":"p1","similarProducts":[{"id":2,"name":"p2"}]}
The drawback with this approach is that you would need to add new properties to the serializer as they are added.
Upvotes: 0
Reputation: 831
You can serialize using @JsonFilter
annotation.
New version of your model:
public class Product {
int id;
String name;
@JsonFilter("productView")
List<Product> similarProducts;
// getters and setters
}
Serialization process:
FilterProvider filters = new SimpleFilterProvider()
.addFilter(
"productView",
SimpleBeanPropertyFilter.serializeAllExcept("similarProducts")
);
String res = new ObjectMapper()
.writer(filters)
.writeValueAsString(product);
System.out.println(res);
Example
Code:
Product child1 = new Product();
child1.id = 2;
child1.name = "sfd";
Product grandchild1 = new Product();
grandchild1.id = 4;
grandchild1.name = "werrwe";
child1.similarProducts = Collections.singletonList(grandchild1);
Product child2 = new Product();
child2.id = 2;
child2.name = "sfd";
Product product = new Product();
product.id = 1;
product.name = "product";
product.similarProducts = Arrays.asList(child1, child2);
FilterProvider filters = new SimpleFilterProvider().addFilter("productView",
SimpleBeanPropertyFilter.serializeAllExcept("similarProducts"));
String res = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT)
.writer(filters)
.writeValueAsString(product);
System.out.println(res);
Output:
{
"id" : 1,
"name" : "product",
"similarProducts" : [ {
"id" : 2,
"name" : "sfd"
}, {
"id" : 2,
"name" : "sfd"
} ]
}
See also
Blog post about filtering properties in jackson: Every day Jackson usage, part 3: Filtering properties
Upvotes: 2