我尝试使用以下(简化)代码通过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"}
。
如何创建一个尊重指定过滤器的临时编写器(在我的情况下无法重新配置ObjectMapper)。
注意:由于我的应用程序中的使用场景,我只能接受不使用Jackson注释的答案。
答案 0 :(得分:6)
您通常会注释Data
类以应用过滤器:
@JsonFilter("test")
class Data {
您已指定不能在课程上使用注释。您可以使用混合来避免注释Data
类。
@JsonFilter("test")
class DataMixIn {}
在ObjectMapper
上指定了Mixins have to,并指定您不想重新配置它。在这种情况下,您始终可以使用其配置复制ObjectMapper
,然后修改副本的配置。这不会影响代码中其他地方使用的原始ObjectMapper
。 E.g。
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"}
答案 1 :(得分:6)
按名称排除属性的示例:
$ curl "localhost:9200/dt/art/_search?pretty" -d'{
"query": {
"bool": { "must": { "match_all": {} },
"filter": {
"range": {
"age": { "gte": 20, "lte": 50}}}}}}'
{ "took" : 8, "timed_out" : false,
"_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 },
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{ "_index" : "dt", "_type" : "art", "_id" : "4", "_score" : 1.0,
"_source" : { "age" : 33 } },
{ "_index" : "dt", "_type" : "art", "_id" : "3", "_score" : 1.0,
"_source" : { "age" : 42 } }
]
}
}
$
您可以代替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
的参数Object.class
更改为addMixIn
按类型排除属性,您可以创建User.class
MixInByType
答案 2 :(得分:3)
如果由于某种原因,MixIns不适合你。您可以尝试这种方法:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector(){
@Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
List<String> exclusions = Arrays.asList("field1", "field2");
return exclusions.contains(m.getName())|| super.hasIgnoreMarker(m);
}
});
答案 3 :(得分:0)
如果你想让过滤器工作,你似乎必须添加一个注释来指示在对bean类进行序列化时使用哪个过滤器:
@JsonFilter("test")
public class Data {
public String data1 = "value1";
public String data2 = "value2";
}
OP刚刚添加了一个注释,只是得到了不使用bean动画的答案,那么如果要导出的字段数量非常少,那么您可以自己检索该数据并构建List of List,似乎没有办法做到这一点。
Map<String, Object> map = new HashMap<String, Object>();
map.put("data1", obj.getData1());
...
// do the serilization on the map object just created.
如果您想要排除特定字段并保留最多字段,也许您可以通过反射来实现。以下是我编写的将bean传输到地图的方法,您可以更改代码以满足自己的需求:
protected Map<String, Object> transBean2Map(Object beanObj){
if(beanObj == null){
return null;
}
Map<String, Object> map = new HashMap<String, Object>();
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<Map<String, Object>> 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反序列化器/序列化器。主要原因是我讨厌处理异常内容,它只是搞乱了编码风格。
通过像bean这样利用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是无状态的,使用静态方法完成你的工作很好,我用Java尝试了很多JSON序列化/反序列化框架,但发现Gson既性能又方便