Home > database >  Extracting a key/value pair from json using streams
Extracting a key/value pair from json using streams

Time:08-25

My json file is like this

  {
    "Parent1": {
    "Child1":"TRUE",
    "RandomKey":"TEST-111"
   },
     "Parent2": {
      "Child1":"TRUE",
     "AnotherRandomKey":"TEST-432"
    }
  }

My goal is to extract first occurrence of Child1 from either Parent1 or Parent2 depending on whatever exists, if both exists it should just get the first.

I have the following code written in java but it is always returning false. Not sure what i am doing wrong

   final var content = Jackson.getObjectMapper().readTree(//json link);

   Stream.concat(
         Optional.ofNullable(content.at("/Parent1/Child1")).stream(),
         Optional.ofNullable(content.at("/Parent2/Child1")).stream())
        .map(JsonNode::asBoolean)
        .filter(Objects::nonNull)
        .findFirst()
        .orElse(false);

I am trying to combine both streams and just find the first occurence of Child1 and return the boolean.

CodePudding user response:

The problem is that for some reason, JsonNode.asBoolean() is implemented to be case-sensitive. Hence, parses "TRUE" as false.

Method that will try to convert value of this node to a Java boolean. JSON booleans map naturally; integer numbers other than 0 map to true, and 0 maps to false and Strings "true" and "false" map to corresponding values.

It's not very intuitive because standard JDK wrapper type Boolean performs parsing in the case-insensitive manner.

As a workaround, we can extract a String from a node, and then apply Boolean.parseBoolean.

Note: there's no need to create an Optional in order to generate a stream. In this case, Optional.ofNullable(content.at()) is an abuse of optional (for more details on the usage of optional see).

We can use Stream.of() for that purpose.

public static void main(String[] args) throws JsonProcessingException {
    String message = """
        {
            "Parent1": {
            "Child1":"TRUE",
                "RandomKey":"TEST-111"
        },
            "Parent2": {
            "Child1":"TRUE",
                "AnotherRandomKey":"TEST-432"
        }
        }""";
    
    ObjectMapper mapper = new ObjectMapper();
    JsonNode content = mapper.readTree(message);
    
    boolean result = Stream.of(content.at("/Parent1/Child1"), content.at("/Parent2/Child1"))
        .filter(Objects::nonNull)
        .map(JsonNode::asText)
        .map(Boolean::parseBoolean)
        .filter(value -> value) // guarding against the case when node "Parent1" doesn't exist
        .findFirst()
        .orElse(false);

    System.out.println(result);
    
}

Output:

true
  • Related