简体   繁体   English

jersey / jackson - 基于查询参数过滤属性

[英]jersey/jackson - filter properties based on query parameter

Filtering out properties with Jackson is pretty simple: 使用Jackson过滤属性非常简单:

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

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

I am trying to integrate this in my Jersey REST application. 我想在我的Jersey REST应用程序中集成它。 The API user has the possibility to filter the properties by providing a query string: API用户可以通过提供查询字符串来过滤属性:

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

What is the most elegant way to do this in Jersey? 泽西岛最优雅的方式是什么? I could easily execute the above in my resource methods, but this somehow kills the elegance of Jersey. 我可以轻松地在我的资源方法中执行上述操作,但这会以某种方式杀死Jersey的优雅。 Also, I believe that creating a new ObjectMapper for every request will have performance penalties. 此外,我相信为每个请求创建一个新的ObjectMapper会有性能损失。

I could write a MessageBodyWriter which fetches the fields query parameter from the UriInfo context and serializes the entity to json while applying a filter based on the fields query parameter. 我可以编写一个MessageBodyWriter ,它从UriInfo上下文中获取fields查询参数,并在应用基于fields查询参数的过滤器时将实体序列化为json。 Is this the best way to do this? 这是最好的方法吗? Like this: 像这样:

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

It seems to work, but I am unsure if it is smart to do it like this. 它似乎有用,但我不确定这样做是否聪明。 I am new to the Jersey library. 我是泽西岛图书馆的新手。

My current solution to a similar problem is to register the following servlet filter: 我目前解决类似问题的方法是注册以下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;
        }
    }
}

It's a little more gnarly than the solution you provided, but leaves the standard JacksonJsonProvider serialization in place. 它比您提供的解决方案更加粗糙,但JacksonJsonProvider了标准的JacksonJsonProvider序列化。

It can be improved by pulling the (possibly) existing FilterProvider via m.getConfig().getFilterProvider() and delegating to it before / after your filter. 可以通过m.getConfig().getFilterProvider()拉动(可能)现有的FilterProvider并在过滤器之前/之后委托给它来改进它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM