如何在Dropwizard中实现请求范围的Jackson FilterProvider

时间:2015-07-10 10:40:51

标签: jersey jackson dropwizard

我需要根据请求中提供的参数过滤响应实体属性。

举个例子:

GET http://example.org/api/entity/1

会回复

{ "id": 1234, "foo": "FOO", "bar": "BAR" }

如果请求包含参数include=id,foo,我只想包含参数标识的属性:

{ "id": 1234, "foo": "FOO" }

通常,使用杰克逊过滤器可以使用documented few中的places进行此类动态过滤。我无法理解的是为FilterProvider提供对HttpServletRequest(或类似的任何作用域)的引用的方法。

ObjectMapper mapper = ...
mapper.setFilters(new FilterProvider() {
    public BeanPropertyFilter findFilter(Object filterId) {
        // FIXME: filter out all except those in HttpServletRequest#getParameter("include")
        return SimpleBeanPropertyFilter.filterOutAllExcept(Collections.<String>emptySet());
    }
});

如果我添加servlet或Jersey过滤器来配置ObjectWriterInjector,则可以使用potential solutionexample。我希望有一个更清晰,更直接的方法。

这一切都发生在Dropwizard应用程序中,如果这恰好有任何区别。

3 个答案:

答案 0 :(得分:0)

让我先从免责声明开始,从未与DropWizard合作,所以我可能会在这里瞎扯一下。但你可以这样做:

@GET
@Path("test")
public String get(@QueryParam("include") List<String> includeList) throws JsonProcessingException {
    MyClass myClass = new MyClass("aaa");

    ObjectMapper mapper = ...;

    FilterProvider filterProvider = new SimpleFilterProvider()
            .addFilter("myFilter", SimpleBeanPropertyFilter.filterOutAllExcept(new HashSet<>(includeList)));

    mapper.setFilters(filterProvider);

    return mapper.writeValueAsString(myClass);
}

请求将在:

GET http://example.org/api/entity/1

您当然可以在问题中保留请求并添加:

@GET
@Path("test")
public String get2(@QueryParam("include") String includeList) throws JsonProcessingException {
    MyClass myClass = new MyClass("testing123");

    String[] arr = includeList.split(",");
    ObjectMapper mapper = ...;

    FilterProvider filterProvider = new SimpleFilterProvider()

            .addFilter("myFilter", SimpleBeanPropertyFilter.filterOutAllExcept(new HashSet<>(Arrays.asList(arr))));
    mapper.setFilters(filterProvider);

    return mapper.writeValueAsString(myClass);
}

此解决方案的问题是返回String而不是对象本身会使测试更难。

答案 1 :(得分:0)

好的,请抓住你的帽子:这有点牵扯。 :)

Jackson 2.3为JAX-RS提供程序添加了通用扩展,允许对用于读写JSON(和其他格式)的ObjectReaderObjectWriter进行深度自定义。 增加是通过这个问题:

https://github.com/FasterXML/jackson-jaxrs-providers/issues/33

但要点是,您可以在处理请求期间注册ObjectReaderInjector和/或ObjectWriterInjector:通常这是通过doFilter() javax.servlet.Filter方法完成的,在DropWizard调用Jackson读取请求之前,写回复。 然后在读/写之前调用注入器(如果有注册的话),让代码进行任何想要的更改。 使用ObjectReaderObjectWriter的实例代替ObjectMapper,因为它们完全是线程安全的;您无法安全地重新配置ObjectMapper,但读取器/编写器实例可以使用各种“withXxx()”调用进行重新配置(只需记住它们创建新实例并且不要修改实例方法!)。

通过以上问题举例:

https://github.com/FasterXML/jackson-jaxrs-providers/commit/ddf256f6aaaf1d669c1c4323c5359cc20cf40654

显示了它们如何联系在一起。 代码并不像人们希望的那么简单,但它是通用的,非常强大的方式来定制阅读请求的所有方面,写出响应。

答案 2 :(得分:0)

您可以从 MyApplication 类的 run 方法中的环境参数中获取对象映射器:

public class MyApplication extends Application<MyApplicationConfiguration> {
    @Override
    public void run(MyApplicationConfiguration configuration, Environment environment) throws Exception {
        environment.getObjectMapper().setFilterProvider(new FilterProvider() {
            public BeanPropertyFilter findFilter(Object filterId) {
                //filter code here
            }
        });
    }
}