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
但是我建议你使用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在性能和方便性方面都很出色。