jackson过滤掉没有注释的字段

我试图通过SimpleBeanPropertyFilter使用以下(简化)代码过滤掉序列化中的某些字段:

 public static void main(String[] args) { ObjectMapper mapper = new ObjectMapper(); SimpleFilterProvider filterProvider = new SimpleFilterProvider().addFilter("test", SimpleBeanPropertyFilter.filterOutAllExcept("data1")); try { String json = mapper.writer(filterProvider).writeValueAsString(new Data()); System.out.println(json); // output: {"data1":"value1","data2":"value2"} } catch (JsonProcessingException e) { e.printStackTrace(); } } private static class Data { public String data1 = "value1"; public String data2 = "value2"; } 

我使用SimpleBeanPropertyFilter.filterOutAllExcept("data1")); 我原以为创建的序列化Json字符串只包含{"data1":"value1"} ,但我得到{"data1":"value1","data2":"value2"}

如何创建一个尊重指定filter的临时编写器(在我的情况下无法重新配置ObjectMapper)。

注意:由于我的应用程序中的使用场景,我只能接受不使用Jackson注释的答案。

您通常会注释您的Data类以应用filter:

 @JsonFilter("test") class Data { 

您已指定不能在类上使用注释。 您可以使用混合来避免注释Data类。

 @JsonFilter("test") class DataMixIn {} 

必须在ObjectMapper上指定ObjectMapper并指定您不想重新配置它。 在这种情况下,您始终可以使用其配置复制ObjectMapper ,然后修改副本的配置。 这不会影响代码中其他地方使用的原始ObjectMapper 。 例如

 ObjectMapper myMapper = mapper.copy(); myMapper.addMixIn(Data.class, DataMixIn.class); 

然后使用新的ObjectMapper编写

 String json = myMapper.writer(filterProvider).writeValueAsString(new Data()); System.out.println(json); // output: {"data1":"value1"} 

按名称排除属性的示例:

 public Class User { private String name = "abc"; private Integer age = 1; //getters } @JsonFilter("dynamicFilter") public class DynamicMixIn { } User user = new User(); String[] propertiesToExclude = {"name"}; ObjectMapper mapper = new ObjectMapper() .addMixIn(Object.class, DynamicMixIn.class); FilterProvider filterProvider = new SimpleFilterProvider() .addFilter("dynamicFilter", SimpleBeanPropertyFilter.filterOutAllExcept(propertiesToExclude)); mapper.setFilterProvider(filterProvider); mapper.writeValueAsString(user); // {"name":"abc"} 

您可以代替DynamicMixIn创建MixInByPropName

 @JsonIgnoreProperties(value = {"age"}) public class MixInByPropName { } ObjectMapper mapper = new ObjectMapper() .addMixIn(Object.class, MixInByPropName.class); mapper.writeValueAsString(user); // {"name":"abc"} 

注意:如果只想为User exclude属性,可以将方法addMixIn参数Object.class更改为User.class

按类型排除属性,您可以创建MixInByType

 @JsonIgnoreType public class MixInByType { } ObjectMapper mapper = new ObjectMapper() .addMixIn(Integer.class, MixInByType.class); mapper.writeValueAsString(user); // {"name":"abc"} 

如果由于某种原因,MixIns不适合你。 你可以尝试这种方法:

 ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector(){ @Override public boolean hasIgnoreMarker(final AnnotatedMember m) { List exclusions = Arrays.asList("field1", "field2"); return exclusions.contains(m.getName())|| super.hasIgnoreMarker(m); } }); 

看来你必须添加一个注释来指示在对bean类进行序列化时要使用哪个filter,如果你想让filter工作:

 @JsonFilter("test") public class Data { public String data1 = "value1"; public String data2 = "value2"; } 

编辑

OP刚刚添加了一个注释,只是得到了不使用bean动画的答案,那么如果你要导出的字段数量非常少,你可以自己检索那些数据并构建一个List of List,似乎没有别的这样做的方式。

 Map map = new HashMap(); map.put("data1", obj.getData1()); ... // do the serilization on the map object just created. 

如果你想排除特定字段并保留最多字段,也许你可以用reflection来做。 以下是我编写的将bean传输到地图的方法,您可以更改代码以满足自己的需要:

 protected Map transBean2Map(Object beanObj){ if(beanObj == null){ return null; } Map map = new HashMap(); try { BeanInfo beanInfo = Introspector.getBeanInfo(beanObj.getClass()); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor property : propertyDescriptors) { String key = property.getName(); if (!key.equals("class") && !key.endsWith("Entity") && !key.endsWith("Entities") && !key.endsWith("LazyInitializer") && !key.equals("handler")) { Method getter = property.getReadMethod(); if(key.endsWith("List")){ Annotation[] annotations = getter.getAnnotations(); for(Annotation annotation : annotations){ if(annotation instanceof javax.persistence.OneToMany){ if(((javax.persistence.OneToMany)annotation).fetch().equals(FetchType.EAGER)){ List entityList = (List) getter.invoke(beanObj); List> dataList = new ArrayList<>(); for(Object childEntity: entityList){ dataList.add(transBean2Map(childEntity)); } map.put(key,dataList); } } } continue; } Object value = getter.invoke(beanObj); map.put(key, value); } } } catch (Exception e) { Logger.getAnonymousLogger().log(Level.SEVERE,"transBean2Map Error " + e); } return map; } 

但是我建议你使用Google Gson作为JSON反序列化器/序列化器。主要原因是我讨厌处理exception的东西,它只是搞砸了编码风格。

通过在bean类上利用版本控制注释,可以很容易地满足您的需求,如下所示:

 @Since(GifMiaoMacro.GSON_SENSITIVE) //mark the field as sensitive data and will not export to JSON private boolean firstFrameStored; // won't export this field to JSON. 

您可以定义宏是否导出或隐藏字段,如下所示:

  public static final double GSON_SENSITIVE = 2.0f; public static final double GSON_INSENSITIVE = 1.0f; 

默认情况下,Gson将导出所有未注释@Since字段因此,如果您不关心该字段并且只是导出该字段,则不必执行任何操作。

如果某些字段您不想导出到json,即敏感信息只是在字段中添加注释。 并生成json字符串:

  private static Gson gsonInsensitive = new GsonBuilder() .registerTypeAdapter(ObjectId.class,new ObjectIdSerializer()) // you can omit this line and the following line if you are not using mongodb .registerTypeAdapter(ObjectId.class, new ObjectIdDeserializer()) //you can omit this .setVersion(GifMiaoMacro.GSON_INSENSITIVE) .disableHtmlEscaping() .create(); public static String toInsensitiveJson(Object o){ return gsonInsensitive.toJson(o); } 

然后使用这个:

  String jsonStr = StringUtils.toInsensitiveJson(yourObj); 

由于Gson是无状态的,使用静态方法来完成你的工作很好,我已经尝试了很多JSON序列化/反序列化框架,但是发现Gson在性能和方便性方面都很出色。