jon_wu jon_wu - 6 months ago 38
Java Question

How to filter properties on a self reference using Jackson?

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).

Answer

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