【问题标题】:Jackson Filter and Polymorphism杰克逊过滤器和多态性
【发布时间】:2017-10-21 21:37:30
【问题描述】:

我有一个抽象类Vehicle

@JsonFilter('Vehicle_Filter')
public abstract class Vehicle {
    private String brand;
    private int nbOfWheels;
    //Other attributes, constructor & methods
}

我有一个子类 Car 扩展 Vehicle:

@JsonFilter('Car_Filter')
public class Car extends Vehicle {
    private int nbOfDoors;
    private boolean isElectric;
    //Other attributes, constructor & methods
}

我还有另一个子类 Bike 扩展了 Vehicle:

@JsonFilter('Bike_Filter')
public class Bike extends Vehicle {
    private double tirePressure;
    private boolean isAllTerrain;
    //Other attributes, constructor & methods
}

假设我有一个类 VehicleCollection 表示我想在 HTML 页面中显示的车辆列表:

@JsonFilter('VehicleCollection_Filter')
public abstract class VehicleCollection {
    private List<Vehicle> vehicles;
    //Other attributes, constructor & methods
}

为此,我将使用 Jackson(来自 fasterXML)对其进行序列化。 假设我只想显示每辆车的一些属性。我将使用 FilterProvider 接口。

问题是:当我想过滤车辆的属性时,我不想区分它是自行车还是汽车。重要的是,它是一辆交通工具。我想我可以在过滤时想出这个:

FilterProvider filterProvider = new SimpleFilterProvider()
            .addFilter("VehicleCollection_Filter", SimpleBeanPropertyFilter.filterOutAllExcept("vehicles"))
            .addFilter("Vehicle_Filter", SimpleBeanPropertyFilter.filterOutAllExcept("brand", "nbOfDoors", "isElectric"));

... 但是当调用 writer 时,会抛出这个错误:Could not find filter with id: 'Car_Filter'。杰克逊似乎不想听到多态性的事情……

有人遇到过同样的问题吗?如果是,我可以提示如何克服它吗?如果没有,是否有一些文档或一些隐含的解释说明为什么杰克逊过滤器不能处理继承?

【问题讨论】:

  • 如果一切都很重要,那是车辆,为什么你有@JsonFilter('Car_Filter')?和@JsonFilter('Bike_Filter')?
  • 因为在应用的其他部分,我需要分别显示Cars和Bikes

标签: java json jakarta-ee jackson polymorphism


【解决方案1】:

首先,您遇到的错误是因为当 Jackson 序列化 Car 实例时,它会在类上看到 @JsonFilter 注释,并希望通过过滤器提供程序找到具有给定 id 的过滤器。

解决方法:

  1. 添加.setFailOnUnknownId(false); 将消除错误但会导致所有字段都被序列化。
  2. 添加一个默认过滤器.setDefaultFilter(filterOutAllExcept("brand", "nbOfDoors", "isElectric")),当找不到"Bike_Filter""Car_Filter" 时将应用该过滤器。这将获得所需的输出,但灵活性有限。每个过滤器提供程序的所有类都有 1 个默认过滤器,所有过滤器提供程序的每个类都有 1 个过滤器。例如,您不能使用 3 个过滤器注释一个类并在提供程序中选择其中一个。
  3. 请改用@JsonView。与过滤器不同,视图本身支持(多个)继承,您可以为每个字段/getter 指定超过 1 个,这提供了极大的灵活性。例如:

    abstract class Vehicle {
        @JsonView(Detail.Basic.class)
        private String brand;
        @JsonView(Detail.Standard.class)
        private int nbOfWheels;
    }
    
    class Car extends Vehicle {
        @JsonView(Detail.FullCar.class)
        private int nbOfDoors;
        // multiple views on a field
        @JsonView({Detail.Standard.class, Detail.Type.class})
        private boolean electric;
    }
    
    class Bike extends Vehicle {
        @JsonView(Detail.FullBike.class)
        private int tirePressure;
        @JsonView({Detail.Standard.class, Detail.Type.class})
        private boolean allTerrain;
    }
    
    class Detail {
        // marker interfaces never implemented
        interface Basic {}
        interface Type {}
        interface Standard extends Basic {}
        interface FullCar extends Basic {}
        interface FullBike extends Basic {}
        // 1 view can inherit from many
        interface Full extends FullCar, FullBike {}
    }
    
    ObjectMapper mapper = new ObjectMapper();
    // only 1 view per writer
    ObjectWriter basicWriter = mapper.writerWithView(Detail.Basic.class);
    ObjectWriter standardWriter = mapper.writerWithView(Detail.Standard.class);
    ObjectWriter typeWriter = mapper.writerWithView(Detail.Type.class);
    

视图也不太容易出错,因为匹配类型而不是字符串,即如果视图名称中有拼写错误,IDE 会突出显示它。使用@JsonFilter ids 你会得到运行时错误。

我猜@JsonViewdocs 中提到了术语“子类” 但在@JsonFilter docs 中没有提到这一事实,这是一个很好的解释观察到的行为。

【讨论】:

  • 我尝试了所有解决方案,所有解决方案都有效!我更喜欢使用 Views 的那个,因为它更 OO,更 Java ;) 而且,对于讨厌编写纯字符串的人来说,这真的是一种解脱!谢谢!
猜你喜欢
  • 2013-08-30
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多