2014-10-20 52 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