Search code examples
javajacksonobjectmapperjsonnode

Jackson: Check if ArrayNode contains JsonNode


I am using the Jackson JSON library and its Tree Model system (JsonNode) in my Java application. In this, I need to check if an ArrayNode contains a given JsonNode. I was looking through the JavaDocs and I did not see any sort of .contains() method for ArrayNode. I ended up writing a contains methods myself:

   public static boolean arrayNodeContains(ArrayNode arrayNode, JsonNode node) {
      Stream<JsonNode> nodeStream = StreamSupport.stream(arrayNode.spliterator(), false);
      return nodeStream.anyMatch(j -> j.equals(node));
   }

Unit Test:

   @Test
   public void testArrayNodeContains()
         throws IOException
   {
      ObjectMapper mapper = new ObjectMapper;

      String arrayJsonString = "[{\"foo\":\"bar\"},{\"foo\":\"baz\"},{\"baz\":\"bar\"}]";
      String nodeTrueJsonString = "{\"foo\":\"bar\"}";
      String nodeFalseJsonString = "{\"foo\":\"brains\"}";
      List<Object> list = mapper.readValue(arrayJsonString, List.class);
      ArrayNode arrayNode = mapper.valueToTree(list);

      Map<String, Object> nodeTrueMap = mapper.readValue(nodeTrueJsonString, Map.class);
      JsonNode nodeTrue = mapper.valueToTree(nodeTrueMap);

      assertTrue(arrayNodeContains(arrayNode, nodeTrue));

      Map<String, Object> nodeFalseMap = mapper.readValue(nodeFalseJsonString, Map.class);
      JsonNode nodeFalse = mapper.valueToTree(nodeFalseMap);
      assertFalse(arrayNodeContains(arrayNode, nodeFalse));
   }

Did I miss something in Jackson and I am duplicating some library method I missed. Otherwise, is there a better way of doing this than what I did?


Solution

  • There is an option of using equals method with JsonNode and Comparator

    Entry method for invoking customizable comparison, using passed-in Comparator object. Nodes will handle traversal of structured types (arrays, objects), but defer to comparator for scalar value comparisons

    New Enhancement 790 for adding JsonNode.equals(Comparator, JsonNode) to support configurable/external equality comparison:

     // but. Custom comparator can make all the difference
        Comparator<JsonNode> cmp = new Comparator<JsonNode>() {
            @Override
            public int compare(JsonNode o1, JsonNode o2) {
                if (o1.equals(o2)) {
                    return 0;
                }
                if ((o1 instanceof NumericNode) && (o2 instanceof NumericNode)) {
                    double d1 = ((NumericNode) o1).asDouble();
                    double d2 = ((NumericNode) o2).asDouble();
                    if (d1 == d2) { // strictly equals because it's integral value
                        return 1;
                    }
                }
                return 0;
            }
        };
        // but with custom comparator, yes
        assertTrue(root1.equals(cmp, root2));