【问题标题】:Using conditions to dynamically exclude POJO property in Jackson json serialization在Jackson json序列化中使用条件动态排除POJO属性
【发布时间】:2014-09-01 10:17:06
【问题描述】:

我需要动态排除已定义 POJO 列表中的某些属性。 主要要序列化的POJO是:

public class Foo
{
    List<Bar> bar;

    public void setBar(List<Bar> bar)
    {
        this.bar = bar;
    }

    public List<Bar> getBar()
    {
        return this.bar;
    }

    public static class Bar
    {
        private int id;
        private boolean ignoreId;
        private String name;

        public void setId(int id)
        {
            this.id = id;
        }

        public int getId()
        {
            return this.id;
        }

        public void setIgnoreId(boolean ignoreId)
        {
            this.ignoreId = ignoreId;
        }

        public boolean isIgnoreId()
        {
            return this.ignoreId;
        }

        public void setName(String name)
        {
            this.name = name;
        }

        public String getName()
        {
            return this.name;
        }
    }
}

如果ignoreId = true,则忽略id,如下所示:

[
    { "id": "1", "name": "one" },
    { "name": "two" }
    { "name": "three" }
    { "id": "4", "name": "four" }
]

目前,我尝试使用JsonFilterJacksonJsonViews,但无法获得所需的输出。 如果可以为实现这一目标提供任何指示,我会很高兴。

【问题讨论】:

  • JsonFilter 应该在这种情况下使用。你能描述一下为什么过滤器不适合你吗?
  • @AlexeyGavrilov,我创建了一个这样的逻辑:@JsonFilter("Exclude.Id") class PropertyFilterMixIn {} 如果我有Set&lt;String&gt; ignorableFieldNames = new ArrayList&lt;String&gt;().add("id");,我可以这样做:FilterProvider filters = new SimpleFilterProvider().addFilter("Exclude.Id", SimpleBeanPropertyFilter.serializeAllExcept(ignorableFieldNames)); ObjectWriter writer = mapper.writer(filters); System.out.println(writer.writeValueAsString(new Foo())); my challenge's to dynamically add id` 到ignorableFieldNames[],如果&仅当ignoreId 是真的

标签: java json serialization jackson pojo


【解决方案1】:

您应该编写一个自定义的Jackson filter,它会根据其他属性值过滤掉 POJO 属性。您应该重写 PropertyFilter.serializeAsField() 方法以访问序列化对象的实例。这是一个例子:

public class JacksonFilter2 {
    @JsonFilter("filter")
    public static class Bar {
        public final int id;
        @JsonIgnore
        public final boolean ignoreId;
        public final String name;

        public Bar(int id, boolean ignoreId, String name) {
            this.id = id;
            this.ignoreId = ignoreId;
            this.name = name;
        }
    }

    public static class ExcludeIdFilter extends SimpleBeanPropertyFilter {

        @Override
        protected boolean include(BeanPropertyWriter writer) {
            return true;
        }

        @Override
        protected boolean include(PropertyWriter writer) {
            return true;
        }

        @Override
        public void serializeAsField(Object pojo,
                                     JsonGenerator jgen,
                                     SerializerProvider provider,
                                     PropertyWriter writer) throws Exception {
            if (pojo instanceof Bar
                    && "id".equals(writer.getName())
                    && ((Bar) pojo).ignoreId) {
               writer.serializeAsOmittedField(pojo, jgen, provider);
            } else {
                super.serializeAsField(pojo, jgen, provider, writer);
            }
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        List<Bar> bars = Arrays.asList(new Bar(1, false, "one"),  new Bar(2, true, "two"));
        ObjectMapper mapper = new ObjectMapper();
        mapper.setFilters(new SimpleFilterProvider().addFilter("filter", new ExcludeIdFilter()));
        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(bars));
    }

}

输出:

[ {
  "id" : 1,
  "name" : "one"
}, {
  "name" : "two"
} ]

【讨论】:

  • 谢谢阿列克谢。我似乎收到了No filter configured with id...
  • @Damilola 上面的例子对我有用。你在哪个杰克逊版本?你能用你的过滤器代码更新你的问题吗?
  • 看来我的问题和大图here的讨论类似
【解决方案2】:

我正在使用 Jackson 2.4.2。

模型对象是:

public class PostProject
{
    /* The field template of this project */
    private List< FieldTemplateObject > field_templates;

    /**
     * @author Damilola Okuboyejo
     */
    @JsonFilter( "FieldTemplateIdFilter" )
    public static class FieldTemplateObject
    {
      private int     id;
      private boolean is_inherited;
      private String  item_type;

      /**
       * @return the id
       */
      public int getId()
      {
         return id;
      }

      /**
       * @param id
       *           the id to set
       */
      public void setId( int id )
      {
         this.id = id;
      }

      /**
       * @return the is_inherited
       */
      public boolean isIs_inherited()
      {
         return is_inherited;
      }

      /**
       * @param is_inherited
       *           the is_inherited to set
       */
      public void setIs_inherited( boolean is_inherited )
      {
         this.is_inherited = is_inherited;
      }

      /**
       * @return the item_type
       */
      public String getItem_type()
      {
         if( item_type == null )
         {
            item_type = PostProject.item_type;
         }
         return item_type;
      }

      /**
       * @param item_type
       *           the item_type to set
       */
      public void setItem_type( String item_type )
      {
         this.item_type = item_type;
      }
   }
}

我的序列化器是这样的:

public static class ModelFieldSerializer extends SimpleBeanPropertyFilter
{
  @Override
  protected boolean include( BeanPropertyWriter writer )
  {
     return true;
  }

  @Override
  protected boolean include( PropertyWriter writer )
  {
     return true;
  }

  @Override
  public void serializeAsField( Object pPojo, JsonGenerator pJgen,
        SerializerProvider pProvider, PropertyWriter pWriter )
        throws Exception
  {
     if( pPojo instanceof FieldTemplateObject )
     {
        if( ("id".equals( pWriter.getName() ))
              && ((FieldTemplateObject) pPojo).isIs_inherited() )
        {
           pWriter.serializeAsOmittedField( pPojo, pJgen, pProvider );
        }
        else
        {
           super.serializeAsField( pPojo, pJgen, pProvider, pWriter );
        }
     }
  }
}

注意:模型类在客户端-服务器架构环境中通过网络传递

【讨论】:

  • 您能说明如何为 ObjectMapper 注册过滤器吗?将代码移到问题中也是有意义的,因为这不是实际答案。
  • vJsonMapper.setFilters( new SimpleFilterProvider().addFilter( "FieldTemplateIdFilter", new ModelFieldSerializer() ) );
  • 您是在设置过滤器之前还是之后使用ObjectMapper?你能制作一个完整的课程来重现你的问题吗?我的答案中的代码对您有用吗?
  • 这是一个相当冗长的代码。我之前在答案部分中指定的评论应该会重现该问题。我注意到当我用@JsonFilter("FieldTemplateIdFilter" ) 标记FieldTemplateObject 时,我得到了异常。根据jackson doc 2.3+,我注意到属性或getter也可以用@JsonFilter注释。如果我尝试这样做,问题就会消失,但不会发生过滤。
【解决方案3】:

我刚刚看到了罪魁祸首。 非常感谢@Alexey 在这方面和我在一起。经过多次尝试,我发现 Jackson 2.4.2 可能要求我将我的序列化器放在它可以使用的模型中。我想知道为什么,但可能是由于 Java 对象序列化要求,Jackson 未能在运行时映射过滤器。我希望 Tatu 会在 Jackson 文档中注意到这一点

public class PostProject
{
    /* The field template of this project */
    private List< FieldTemplateObject > field_templates;

    /**
     * @author Damilola Okuboyejo
     */
    @JsonFilter( "FieldTemplateIdFilter" )
    public static class FieldTemplateObject
    {
      private int     id;
      private boolean is_inherited;
      private String  item_type;

      /**
       * @return the id
       */
      public int getId()
      {
         return id;
      }

      /**
       * @param id
       *           the id to set
       */
      public void setId( int id )
      {
         this.id = id;
      }

      /**
       * @return the is_inherited
       */
      public boolean isIs_inherited()
      {
         return is_inherited;
      }

      /**
       * @param is_inherited
       *           the is_inherited to set
       */
      public void setIs_inherited( boolean is_inherited )
      {
         this.is_inherited = is_inherited;
      }

      /**
       * @return the item_type
       */
      public String getItem_type()
      {          
         return item_type;
      }

      /**
       * @param item_type
       *           the item_type to set
       */
      public void setItem_type( String item_type )
      {
         this.item_type = item_type;
      }
   }

   public static class ModelFieldSerializer extends SimpleBeanPropertyFilter
   {
      @Override
      protected boolean include( BeanPropertyWriter writer )
      {
         return true;
      }

      @Override
      protected boolean include( PropertyWriter writer )
      {
         return true;
      }

      @Override
      public void serializeAsField( Object pPojo, JsonGenerator pJgen,
            SerializerProvider pProvider, PropertyWriter pWriter )
            throws Exception
      {
         if( pPojo instanceof FieldTemplateObject )
         {
             boolean vAllowId = ((FieldTemplateObject) pPojo).isIs_inherited();
             if( !vAllowId && ("id".equals( pWriter.getName() )) )
             {
               return; // skip the id property
             }
             else
             {
               super.serializeAsField( pPojo, pJgen, pProvider, pWriter );
             }
         }
      }
    }
}

【讨论】:

  • Java 对象序列化要求不适用于 Jackson。你应该遇到过别的事情。如果您可以将最小化的可重现示例代码发布到 GitHub,我会尝试跟进,否则我没有任何线索。
  • @Alexey 我刚刚向GitHub发布了一个缩小的可复制版本@
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-07
  • 2016-08-16
  • 2017-07-10
相关资源
最近更新 更多