6

I'm trying to deserialise a JSON string using ObjectMapper (Jackson) and exclude a field while performing the deserialisation.

My code is as follows:

String aContent = new String(Files.readAllBytes(Paths.get(aFile)));
String bContent = new String(Files.readAllBytes(Paths.get(bFile)));

ObjectMapper mapper = new ObjectMapper();

FilterProvider filterProvider = new SimpleFilterProvider()
      .addFilter("_idFilter", SimpleBeanPropertyFilter.serializeAllExcept("_id"));

mapper.setFilterProvider(filterProvider);

JsonNode tree1 = mapper.readTree(aContent);
JsonNode tree2 = mapper.readTree(bContent);

String x = mapper.writeValueAsString(tree1);

return tree1.equals(tree2);

Both x and tree1 and tree2 contains the value _id in the JSON String but it isn't removed.

Ori Marko
  • 56,308
  • 23
  • 131
  • 233
Mkl Rjv
  • 6,815
  • 5
  • 29
  • 47

3 Answers3

2

FilterProvider are meant to be used with custom Object like here

If you want to stick with JsonNode, use this method :

String aContent = new String("{\"a\":1,\"b\":2,\"_id\":\"id\"}"); 

ObjectMapper mapper = new ObjectMapper();

JsonNode tree1 = mapper.readTree(aContent);
ObjectNode object = (ObjectNode) tree1;
object.remove(Arrays.asList("_id"));

System.out.println(mapper.writeValueAsString(object));

Will print :

{"a":1,"b":2}
ToYonos
  • 16,469
  • 2
  • 54
  • 70
2

You are following Ignore Fields Using Filters except the first step

First, we need to define the filter on the java object:

@JsonFilter("myFilter")
public class MyDtoWithFilter { ... }

So currently you supposed to add

@JsonFilter("_idFilter")
public class JsonNode {

It's not possible so you need to create a class that extends JsonNode and use it instead

@JsonFilter("_idFilter")
public class MyJsonNode extends JsonNode {

If you don't want to implement all abstract method define as abstract

@JsonFilter("_idFilter")
public abstract class MyJsonNode extends JsonNode {
}

And in your code:

MyJsonNode tree1 = (MyJsonNode) mapper.readTree(aContent);
MyJsonNode tree2 = (MyJsonNode) mapper.readTree(bContent);
Community
  • 1
  • 1
Ori Marko
  • 56,308
  • 23
  • 131
  • 233
  • How'd you make it work? ObjectMapper.readTree returns JsonNode, not ```MyJsonNode extends JsonNode```. I've tried this approach, and getting ```Error: java: incompatible types: com.fasterxml.jackson.databind.JsonNode cannot be converted to MyJsonNode.``` – Alexander Melnichuk Feb 24 '20 at 04:01
  • @AlexanderMelnichuk you can add casting `(MyJsonNode)` – Ori Marko Feb 24 '20 at 06:29
0

If you use Jackson 2.6 or higher, you can use a FilteringParserDelegate with a custom TokenFilter.

public class PropertyBasedIgnoreFilter extends TokenFilter {

    protected Set<String> ignoreProperties;

    public PropertyBasedIgnoreFilter(String... properties) {
        ignoreProperties = new HashSet<>(Arrays.asList(properties));
    }

    @Override
    public TokenFilter includeProperty(String name) {
        if (ignoreProperties.contains(name)) {
            return null;
        }
        return INCLUDE_ALL;
    }
}

When creating the FilteringParserDelegate with this PropertyBasedIgnoreFilter, make sure to set the booleans includePath and allowMultipleMatches both to true.

public class Main {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String jsonInput = "{\"_p1\":1,\"_p2\":2,\"_id\":\"id\",\"_p3\":{\"_p3.1\":3.1,\"_id\":\"id\"}}";

        JsonParser filteredParser = new FilteringParserDelegate(mapper.getFactory().createParser(new ByteArrayInputStream(jsonInput.getBytes())),
                                                                new PropertyBasedIgnoreFilter("_id"),
                                                                true,
                                                                true);
        JsonNode tree = mapper.readTree(filteredParser);

        System.out.println(jsonInput);
        System.out.println(tree);
        System.out.println(jsonInput.equals(tree.toString()));
    }
}

prints

{"_p1":1,"_p2":2,"_id":"id","_p3":{"_p3.1":3.1,"_id":"id"}}
{"_p1":1,"_p2":2,"_p3":{"_p3.1":3.1,"_id":"id"}}
false

As you can see, nested occurrences of _idare not filtered out. In case that's not what you need, you can of course extend my PropertyBasedIgnoreFilter with your own TokenFilter implementation.

Maarten Dhondt
  • 577
  • 1
  • 9
  • 22