Java 使用Jackson 2的动态特性过滤器

Java 使用Jackson 2的动态特性过滤器,java,json,jackson,Java,Json,Jackson,我正在构建一个REST服务平台,其中我们必须支持以下查询模式: format=summary这意味着我们必须仅反序列化使用自定义注释注释的POJO属性@summary format=detail这意味着我们必须仅反序列化使用自定义注释注释的POJO属性@detail fields=prop1、prop2、prop3,这意味着我们必须反序列化查询中提供的POJO属性 我正在使用Jackson 2(v2.3.0),我尝试了以下内容: 开发自定义注释(@Summary和@Detail) 开发了一个J

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

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

    • 开发自定义注释(
      @Summary
      @Detail
    • 开发了一个JsonFilter(代码如下所示),并为我的POJO类注释了
      @JsonFilter
    Location.java

    Address.java

    CustomFilter.java

    公共类CustomFilter扩展了SimpleBeanPropertyFilter{
    @凌驾
    受保护的布尔值包括(BeanPropertyWriter propertyWriter){
    if(logger.isDebugEnabled()){
    debug(“include(BeanPropertyWriter)方法调用..”);
    }
    返回此值。反序列化(propertyWriter);
    }
    @凌驾
    受保护的布尔值包括(PropertyWriter PropertyWriter){
    if(logger.isDebugEnabled()){
    debug(“include(PropertyWriter)方法调用..”);
    }
    返回此。反序列化((BeanPropertyWriter)propertyWriter);
    }
    私有布尔值反序列化(最终BeanPropertyWriter BeanPropertyWriter){
    最终字符串格式=(字符串)AppContext.get(“格式”);
    if(StringUtils.isNotBlank(格式)){
    返回反序列化的注释(格式,beanPropertyWriter);
    }否则{
    @抑制警告(“未选中”)
    final Set fieldNames=(Set)AppContext.get(“fieldNames”);
    if(null!=fieldNames&!fieldNames.isEmpty()){
    最终字符串serializedPropertyName=beanPropertyWriter.getSerializedName().getValue();
    返回fieldNames.contains(serializedPropertyName);
    }
    }
    返回false;
    }
    专用布尔值反序列化注释(最终字符串格式,最终BeanPropertyWriter BeanPropertyWriter){
    if(StringUtils.equalsIgnoreCase(格式,“详细信息”)){
    return(null!=beanPropertyWriter.getAnnotation(Detail.class));
    }else if(StringUtils.equalsIgnoreCase(格式,“摘要”)){
    return(null!=beanPropertyWriter.getAnnotation(Summary.class));
    }
    返回false;
    }
    }
    
    我通过注释获得了预期的结果,但是我的第三个要求是支持属性名以进行筛选,这一要求不起作用


    有人能帮忙吗;如果可能,请举例说明

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

    您的缓存可以像一个
    集那样简单,键是用户传入的字段。

    我编写了一个名为的库,它根据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>
    
    3) 现在可以过滤json了

    curl https://yourhost/path/to/endpoint?fields=field1,field2{nested1,nested2}
    
    也可以基于注释选择字段


    有关Squiggly筛选器的更多信息,请访问。

    我在StackOverflow中检查了一些帖子,但几乎所有人都建议编写自定义反序列化器/筛选器,并将其设置为
    ObjectMapper
    ,然后使用它。这意味着我必须为每个传入的请求创建一个新的
    ObjectMapper
    实例,我想这不是一个好主意。我使用的是Spring,所以我创建了一次
    ObjectMapper
    。所以,我必须找到一个解决方案,让我这样做。
    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;
      }
    }
    
    <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>
    
    Squiggly.init(objectMapper, new RequestSquigglyContextProvider());
    
    curl https://yourhost/path/to/endpoint?fields=field1,field2{nested1,nested2}