如何使用Jackson过滤自我引用的属性?

时间:2015-07-23 17:20:44

标签: java json jackson

假设我有一个这样的课程,我想和杰克逊一起序列化。

public class Product {
    int id;
    String name;
    List<Product> similarProducts;
}

我怎么会得到这样的东西?

{
    "id": 1,
    "name": "Product 1",
    "similarProducts": [
        {
            "id": 2,
            "name": "Product 2"
        },
        {
            "id": 3,
            "name": "Product 3"
        }
    ]
}

我已经看到如何使用@JsonProperty来通过类或@JsonView来做这个来选择的东西,但这看起来也像是按类(我错了)?我不确定当我有一个引用自身的类并且父类具有许多属性时,如何让它工作,而孩子只有少数属性。

想象一下,这是一个电子商务网站,您希望从单个JSON有效负载中获取类似产品的名称和网址,但您不需要这些类似产品(儿童)的任何其他详细信息。

2 个答案:

答案 0 :(得分:2)

您可以使用@JsonFilter注释进行序列化。

您的模型的新版本:

public class Product {
    int id;
    String name;

    @JsonFilter("productView")
    List<Product> similarProducts;

    // getters and setters
}

序列化过程:

 FilterProvider filters = new SimpleFilterProvider()
            .addFilter(
                "productView", 
                SimpleBeanPropertyFilter.serializeAllExcept("similarProducts")
            );
 String res = new ObjectMapper()
            .writer(filters)
            .writeValueAsString(product);
 System.out.println(res);

示例

代码:

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

输出:

{
  "id" : 1,
  "name" : "product",
  "similarProducts" : [ {
    "id" : 2,
    "name" : "sfd"
   }, {
    "id" : 2,
    "name" : "sfd"
   } ]
}

另见

有关杰克逊过滤属性的博文:Every day Jackson usage, part 3: Filtering properties

答案 1 :(得分:0)

如果您总是想要这种行为,也可以使用自定义序列化程序完成此操作(在这种情况下,如果不包含过滤器可能会很危险,因为错误会导致自引用案例)

型号:

HttpGet httppost = new HttpGet("http://primecalculation.appspot.com/");

串行:

public class Product {
    public int id;
    public String name;

    @JsonSerialize(contentUsing=ProductSerializer.class)
    public List<Product> similarProducts = Lists.newArrayList();
}

示例:

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();
    }
}

输出:

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

这种方法的缺点是,您需要在添加新属性时将其添加到序列化程序中。