【问题标题】:jersey/jackson - filter properties based on query parameterjersey/jackson - 根据查询参数过滤属性
【发布时间】:2014-12-15 15:07:12
【问题描述】:

使用 Jackson 过滤属性非常简单:

final FilterProvider filters = new SimpleFilterProvider().
    addFilter(... the name of the filter ...,
    SimpleBeanPropertyFilter.filterOutAllExcept(... enumeration of properties ...));

<object mapper>.writer(filters).writeValueAsString(... the bean ...);

我正在尝试将其集成到我的 Jersey REST 应用程序中。 API 用户可以通过提供查询字符串来过滤属性:

https://the-api/persons?fields=name,age,location,gender

在泽西岛最优雅的方式是什么?我可以轻松地在我的资源方法中执行上述操作,但这不知何故扼杀了 Jersey 的优雅。另外,我相信为每个请求创建一个新的 ObjectMapper 都会有性能损失。

我可以编写一个MessageBodyWriter,它从UriInfo 上下文中获取fields 查询参数,并将实体序列化为json,同时应用基于fields 查询参数的过滤器。这是最好的方法吗?像这样:

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JustTesting implements MessageBodyWriter<Object> {
    @Context
    UriInfo uriInfo;
    @Context
    JacksonJsonProvider jsonProvider;

    public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
        return MediaType.APPLICATION_JSON_TYPE.equals(mediaType);
    }

    public long getSize(Object object, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    public void writeTo(Object object, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> stringObjectMultivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
        final FilterProvider filters = new SimpleFilterProvider().addFilter("MyFilter", SimpleBeanPropertyFilter.filterOutAllExcept(uriInfo.getQueryParameters().getFirst("fields")));

        jsonProvider.locateMapper(aClass, mediaType).writer(filters).writeValue(outputStream, object);
    }
}

它似乎有效,但我不确定这样做是否明智。我是泽西图书馆的新手。

【问题讨论】:

  • 我现在正在做类似的事情。我的解决方案实际上还涉及 Orika(我想保存查找惰性集合)。结果,我实现了一个管理器,它检查字段上的自定义注释(如@Basic)以确定它们是否可映射,以及是否应该过滤它们。更具体地说,在泽西岛方面,我正在尝试使用 com.fasterxml.jackson.jaxrs.cfg.ObjectWriterInjector 将我“MixedIn”的过滤器应用于 Object.class。
  • .writer() 似乎不会在请求之间持续存在,这很好。我偶然使用了setFilterProvider(),并且一直存在。

标签: java rest filter jersey jackson


【解决方案1】:

我目前对类似问题的解决方案是注册以下 servlet 过滤器:

@Singleton
public class ViewFilter implements Filter {
    private @Inject Provider<ViewBeanPropertyFilter> filter;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void destroy() { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ObjectWriterInjector.set(new ObjectWriterModifier() {
            @Override
            public ObjectWriter modify(EndpointConfigBase<?> endpoint, MultivaluedMap<String, Object> responseHeaders, Object valueToWrite, ObjectWriter w, JsonGenerator g) throws IOException {
                return w.with(new FilterProvider() {
                    @Override
                    public BeanPropertyFilter findFilter(Object filterId) {
                        if(filterId.equals(ViewFilterJacksonModule.FILTER_NAME)) {
                            return filter.get();
                        }
                        return null;
                    }
                });
            }
        });
        chain.doFilter(request, response);
    }

    public static class ViewBeanPropertyFilter extends SimpleBeanPropertyFilter {
        private @Inject ViewManager manager;

        @Override
        protected boolean include(BeanPropertyWriter writer) {
            Class<?> cls = writer.getMember().getDeclaringClass();
            return manager.isFieldInView(cls, writer.getMember().getName());
        }

        @Override
        protected boolean include(PropertyWriter writer) {
            return true;
        }
    }
}

它比您提供的解决方案稍微粗糙一些,但保留了标准的JacksonJsonProvider 序列化。

可以通过m.getConfig().getFilterProvider() 拉动(可能)现有的FilterProvider 并在过滤器之前/之后委托给它来改进它。

【讨论】:

  • 谢谢,非常有趣。我不知道ObjectWriterInjector。它似乎是一些单例/静态实用程序类,用于预先添加过滤器。我想知道如果您在第一次通话时拨打ObjectWriterInjector.set,但在随后的通话中不要拨打相同的ObjectWriterInjector.set,会发生什么情况。它会留在原地吗?
  • JacksonJsonProvider中的调用代码我相信使用getAndClear,所以它会在使用时被“消耗”。
猜你喜欢
  • 2017-10-30
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
  • 2010-10-06
  • 2012-06-20
  • 1970-01-01
  • 2015-10-13
  • 2012-08-29
相关资源
最近更新 更多