2014-10-20 47 views
4

过滤掉与杰克逊性能过滤性能是非常简单的:球衣/杰克逊 - 基于查询参数

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

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

我想这在我州的REST应用程序集成。 API用户可以通过提供查询字符串来过滤属性:

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

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

可以写一个MessageBodyWriter,其取出由UriInfo上下文fields查询参数和序列化,同时施加一个滤波器基于所述fields查询参数JSON的实体。这是做这件事的最好方法吗?像这样:

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

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

+0

我正在处理类似的事情。我的解决方案实际上也涉及Orika(我想保存查找lazey集合)。因此,我实现了一个管理器,用于检查字段上的自定义注释(如@Basic)以确定它们是否可映射,以及是否应该对其进行过滤。 更具体地说,在泽西岛一侧,我正在尝试使用com.fasterxml.jackson.jaxrs.cfg.ObjectWriterInjector来将我“MixedIn”的过滤器应用于Object.class。 – 2014-10-21 05:29:41

回答

6

我目前的解决类似的问题是注册下列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系列化到位。

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

+1

谢谢,非常有趣。我不知道'ObjectWriterInjector'。它似乎是一些单身/静态工具类,用于之前添加过滤器。我想知道如果在第一次调用时调用ObjectWriterInjector.set,但在随后的调用中不调用相同的ObjectWriterInjector.set,会发生什么情况。它保持原位吗? – 2014-10-21 07:32:55

+0

'JacksonJsonProvider'中的调用代码使用'getAndClear',我相信它会在使用时被“消耗”。 – 2014-10-21 21:04:49

+0

谢谢!我会接受你的回答。 – 2014-10-21 23:32:47