Filtering Fields and Subfields in Jackson

For some JSON:

{ "id":123, "name":"Test", "sub_object":{ "sub_field_1":1, "sub_field_2":2, "sub_field_array":[ { "array_field_1":true, "array_field_2":false }, { "array_field_1":false, "array_field_2":true } ], "sub_sub_object":{ "field_1":"me", "field_2":"myself", "field_3":"i", } } } 

I want to apply a tree-like list of field names. This can probably be expressed in JSONPath:

 root |-id |-sub_object |-sub_field_2 |-sub_field_array |-array_field_1 |-sub_sub_object 

Then I need to return something like:

 { "id":123, "sub_object":{ "sub_field_2":2, "sub_field_array":[ { "array_field_1":true }, { "array_field_1":false } ], "sub_sub_object":{ "field_1":"me", "field_2":"myself", "field_3":"i", } } } 

The idea is that for some hierarchy of fields I want to limit the displayed fields.

I do this through a library that annotated the fields of its objects, but I cannot change the library. Actually, that would not matter, because the hierarchy would be based on serialization. I am currently passing objects to the writeObject method of JsonGenerator, but this returns everything.

Some sub-objects can share field names, so this is not as simple as creating a SimpleBeanPropertyFilter to serialize only a set of names.

Thank you in advance,

John

+4
source share
2 answers

You can write a custom property filter that takes into account the declaration of a serialized property class.

You must extend SimpleBeanPropertyFilter and override the include(PropertyWriter writer) method include(PropertyWriter writer) . If this writer parameter is an instance of the BeanPropertyWriter class, you can extract information about the origin of the property and apply your custom filtering logic.

Here is an example filter that stores exception information in the class map and their property names:

 public class JacksonHierarchyFilter { @JsonFilter("filter") public static class A { public final String field1; public A(final String field1) {this.field1 = field1;} } @JsonFilter("filter") public static class B { public final String field1; public final List<A> list; public B(final String field1, final List<A> list) { this.field1 = field1; this.list = list; } } @JsonFilter("filter") public static class Foo { public final String field1; public final List<B> field2; public Foo(final String field1, final List<B> field2) { this.field1 = field1; this.field2 = field2; } } public static class MyFilter extends SimpleBeanPropertyFilter { private final Map<Class<?>, Set<String>> excludePropMap; public MyFilter(final Map<Class<?>, Set<String>> excludePropMap) { this.excludePropMap = excludePropMap; } @Override protected boolean include(final BeanPropertyWriter writer) { return false; } @Override protected boolean include(final PropertyWriter writer) { if (writer instanceof BeanPropertyWriter) { final Class<?> cls = ((BeanPropertyWriter) writer).getMember().getDeclaringClass(); final Set<String> excludePropSet = excludePropMap.get(cls); return excludePropSet == null || !excludePropSet.contains(writer.getName()); } return true; } } public static void main(String[] args) throws JsonProcessingException { final B b = new B("B1", Arrays.asList(new A("A1"), new A("A2"))); final Foo foo = new Foo("foo", Arrays.asList(b)); final ObjectMapper mapper = new ObjectMapper(); final SimpleFilterProvider filters = new SimpleFilterProvider(); final Map<Class<?>, Set<String>> excludePropMap = Collections.<Class<?>, Set<String>>singletonMap( B.class, Collections.singleton("field1")); filters.addFilter("filter", new MyFilter(excludePropMap)); mapper.setFilters(filters); final ObjectWriter objectWriter = mapper.writerWithDefaultPrettyPrinter(); System.out.println(objectWriter.writeValueAsString(foo)); } } 

Output:

 { "field1" : "foo", "field2" : [ { "list" : [ { "field1" : "A1" }, { "field1" : "A2" } ] } ] } 
+1
source

I needed to add a custom ignore annotation to my serialization. What I finished was

 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Documented public @interface Unsigned {} 

and

 ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true); mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() { @Override public String[] findPropertiesToIgnore(AnnotatedClass ac) { Set<String> result = new HashSet<>(); for (AnnotatedField field : ac.fields()) { if (field.getAnnotated().isAnnotationPresent(Unsigned.class)) { result.add(field.getName()); } } String[] tmp = super.findPropertiesToIgnore(ac); if (tmp != null) { result.addAll(Arrays.asList(tmp)); } return result.toArray(new String[] {}); } }); ObjectWriter writer = mapper.writer(); 
0
source

Source: https://habr.com/ru/post/1439463/


All Articles