【问题标题】:How to apply a JsonView to a nested entity如何将 JsonView 应用于嵌套实体
【发布时间】:2021-06-02 08:39:13
【问题描述】:

我定义了以下 JsonViews:

public class EntityJsonView {
    public static class Detailed extends Abbreviated {
    }
    
    public static class AuditedDetailed extends Detailed {
    } 
    
    public static class Abbreviated {
        
    }
}

然后我有这些课程:

public Class Customer {

@JsonView(EntityJsonView.Abbreviated.class)
private Integer id;

@JsonView(EntityJsonView.Abbreviated.class)
private String name;

@JsonView(EntityJsonView.Detailed.class)
private String phone;

@JsonView(EntityJsonView.Detailed.class)
private List<Invoice> invoices;
}

public Class Invoice {

@JsonView(EntityJsonView.Abbreviated.class)
private Integer id;

@JsonView(EntityJsonView.Detailed.class)
private Customer customer;

@JsonView(EntityJsonView.Detailed.class)
private Employee salesman;

@JsonView(EntityJsonView.Abbreviated.class)
private Date invoiceDate;

@JsonView(EntityJsonView.Abbreviated.class)
private Double amount;
}

我这样返回我的客户列表:

@JsonView(EntityJsonView.Detailed.class)
    public ResponseEntity<List<Customer>> getCustomerList() {
        List<Customer> custs = customerService.getAll();
        return new ResponseEntity<List<Customer>>(custs , HttpStatus.OK);
}

虽然我希望使用详细视图对 Customer 实例进行序列化,但我希望使用 Abbreviated 视图对嵌套的 Invoice 实例进行序列化。同样,当我使用详细视图序列化发票列表时,我希望使用缩写视图序列化嵌套的客户实例。这不仅仅是递归问题,因为我还想删除许多其他属性。

我已经到处搜索了解决方案,但也许我没有使用正确的关键字。

我的前任使用@JsonIgnoreProperties 完成了这项工作,但事实证明这是一个维护问题。当一个新属性被添加到一个类中时,我必须搜索所有的忽略列表并决定是否需要忽略它。如果有相应的@JsonIncludeProperties 会更容易。

有没有人找到更好的方法来做到这一点?

【问题讨论】:

    标签: json-view


    【解决方案1】:

    我想出了一种方法来做到这一点,它适用于我的环境。我发帖以防其他人有类似的问题。第一步是为每个顶级实体创建一个视图。在此示例中,它们将是 Foo、Bar 和 Snafu。这些都应该继承自简略视图。

    public class EntityViews {
      
     public static interface Abbr {}
        
     public static interface Foo extends Abbr {}
        
     public static interface Bar extends Abbr {}
        
     public static interface Snafu extends Abbr {}
        
     public static interface Detailed extends Foo, Bar, Snafu {}
    }
    

    我使用接口是因为它允许多重继承。所有主要的类视图最终都出现在详细视图中。现在上课:

    @JsonView(EntityViews.Foo.class)
    public class Foo {
    
    @JsonView(EntityViews.Abbr.Class)
    private Integer id;
    
    @JsonView(EntityViews.Abbr.Class)
    private String name;
    
    private String description;
    
    private Bar bar;
    
    }
    
    @JsonView(EntityViews.Bar.class)
    public class Bar {
    
    @JsonView(EntityViews.Abbr.Class)
    private Integer id;
    
    @JsonView(EntityViews.Abbr.Class)
    private String name;
    
    private List<Snafu> snafus;
    }
    
    @JsonView(EntityViews.Snafu.class)
    public class Snafu {
    
    @JsonView(EntityViews.Abbr.Class)
    private Integer id;
    
    @JsonView(EntityViews.Abbr.Class)
    private String name;
    
    @JsonView(EntityViews.Bar.class, EntityViews.Snafu.class)
    @JsonIgnoreProperties("parent", "children")
    private Snafu parent;
    
    @JsonIgnoreProperties("parent", "children")
    private List<Snafu> children;
    
    }
    

    现在,让我们做端点:

    @RestController
    @RequestMapping("/api/foos")
    @CrossOrigin
    public class FooController {
    
    @JsonView(EntityViews.Foo.class)
    @GetMapping("/")
        public ResponseEntity<List<Foo>> get() {
            List<Foo> list = service.getAll();
            return new ResponseEntity<List<Foo>>(list, HttpStatus.OK);
        }
    }
    
    @RestController
    @RequestMapping("/api/bars")
    @CrossOrigin
    public class BarController {
    
    @JsonView(EntityViews.Bar.class)
    @GetMapping("/")
        public ResponseEntity<List<Foo>> get() {
            List<Bar> list = service.getAll();
            return new ResponseEntity<List<Bar>>(list, HttpStatus.OK);
        }
    }
    
    @RestController
    @RequestMapping("/api/snafus")
    @CrossOrigin
    public class SnafuController {
    
    @JsonView(EntityViews.Snafu.class)
    @GetMapping("/")
        public ResponseEntity<List<Snafu>> get() {
            List<Snafu> list = service.getAll();
            return new ResponseEntity<List<Snafu>>(list, HttpStatus.OK);
        }
    }
    

    正如我们所见,每个控制器都分配了与返回的实体相对应的视图。既然这些观点都 从 Abbr 继承,返回的所有其他实体都将应用 Abbr 视图。

    请注意,在 Snafu 类中,父属性已分配给 Bar 和 Snafu 视图。因此,当您返回 Bar 端点时, 您将获得该属性以及 Abbr 属性(我尚未对此进行测试,所以 YMMV。如果它不像我认为的那样工作,将进行编辑)。

    这个策略失败的一个地方是,如果你的属性与实体的类相同。在这种情况下,你仍然会 必须使用 @JsonIgnoreProperties 来控制返回的内容,但这是一个很小的代价,因为不必虚拟地拥有这些 每个实体属性。

    【讨论】:

      猜你喜欢
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-09
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      相关资源
      最近更新 更多