使用Jackson 2的动态属性过滤器

时间:2014-01-21 22:39:14

标签: java json jackson

我正在构建一个REST服务平台,我们必须支持以下查询模式:

  1. format=summary这意味着我们只需反序列化使用自定义注释注释的POJO属性@Summary
  2. format=detail这意味着我们只需反序列化使用自定义注释注释的POJO属性@Detail
  3. fields=prop1,prop2,prop3表示我们必须反序列化查询中提供的POJO属性。
  4. 我正在使用Jackson 2(v2.3.0)我尝试了以下内容:

    • 开发了自定义注释(@Summary@Detail
    • 为我的POJO课程开发了一个JsonFilter(下面显示的代码)和带注释的@JsonFilter

    Location.java

    @JsonFilter("customFilter")
    public class Location implements Serializable {
    @Summary
    @Detail
    private String id;
    
    @Summary
    @Detail
    private String name;
    
    @Summary
    @Detail
    private Address address;
    
    // ... getters n setters
    

    Address.java

    @JsonFilter("customFilter")
    public class Address implements Serializable {
    
      @Detail
      private String addressLine1;
    
      @Detail
      private String addressLine2;
    
      @Detail
      private String addressLine3;
    
      @Detail
      @Summary
      private String city;
    
      @Summary
      @Detail
      private String postalCode;
    
      // ... getters n setters
    

    CustomFilter.java

    public class CustomFilter extends SimpleBeanPropertyFilter {
      @Override
      protected boolean include(BeanPropertyWriter propertyWriter) {
        if(logger.isDebugEnabled()) {
          logger.debug("include(BeanPropertyWriter) method called..");
        }
    
        return this.deserialize(propertyWriter);
      }
    
      @Override
      protected boolean include(PropertyWriter propertyWriter) {
        if(logger.isDebugEnabled()) {
          logger.debug("include(PropertyWriter) method called..");
        }
    
        return this.deserialize((BeanPropertyWriter) propertyWriter);
      }
    
      private boolean deserialize(final BeanPropertyWriter beanPropertyWriter) {
        final String format = (String) AppContext.get("format");
    
        if(StringUtils.isNotBlank(format)) {
          return deserializeForAnnotation(format, beanPropertyWriter);
        } else {
          @SuppressWarnings("unchecked")
          final Set<String> fieldNames = (Set<String>) AppContext.get("fieldNames");
          if(null != fieldNames && !fieldNames.isEmpty()) {
            final String serializedPropertyName = beanPropertyWriter.getSerializedName().getValue();
            return fieldNames.contains(serializedPropertyName);
          }
        }
    
        return false;
      }
    
      private boolean deserializeForAnnotation(final String format, final BeanPropertyWriter beanPropertyWriter) {
    
        if(StringUtils.equalsIgnoreCase(format, "detail")) {
          return (null != beanPropertyWriter.getAnnotation(Detail.class));
        } else if(StringUtils.equalsIgnoreCase(format, "summary")) {
          return (null != beanPropertyWriter.getAnnotation(Summary.class));
        }
    
        return false;
      }
    }
    

    我正在使用注释获得预期结果,但我支持要过滤的属性名称的第3个要求不起作用。

    有人可以提供帮助;如果可能的话用一些例子?

2 个答案:

答案 0 :(得分:3)

我写了一个名为Squiggly Filter的库,它根据Facebook Graph API语法的一个子集选择字段。例如,要选择用户对象的地址字段的zipCode,您将使用查询字符串?fields=address{zipCode}。 Squiggly Filter的一个优点是,只要您可以访问呈现json的ObjectMapper,就不必修改任何控制器方法的代码。

假设您正在使用servlet API,您可以执行以下操作:

1)注册过滤器

<filter> 
    <filter-name>squigglyFilter</filter-name>
    <filter-class>com.github.bohnman.squiggly.web.SquigglyRequestFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>squigglyFilter</filter-name>
    <url-pattern>/**</url-pattern> 
</filter-mapping>

2)初始化ObjectMapper

Squiggly.init(objectMapper, new RequestSquigglyContextProvider());

3)您现在可以过滤您的json

curl https://yourhost/path/to/endpoint?fields=field1,field2{nested1,nested2}

您也可以根据注释选择字段。

有关Squiggly过滤器的更多信息,请参见github

答案 1 :(得分:0)

如果您想要为每组字段设置自定义对象映射器,那么最好的办法是将创建的对象映射器保留在某个缓存中,以便下次用户请求相同的字段时对象mapper可以重复使用。

您的缓存可以像Set<String,ObjectMapper>一样简单,密钥是用户传入的字段。