public static String evaluate(String jsonText, JsonEvaluationSpecification specification)
         throws JsonMappingException {
      // Parse json text ang get root node.
      JsonNode rootNode;
      try {
         ObjectMapper mapper = new ObjectMapper();
         rootNode = mapper.readTree(new StringReader(jsonText));
      } catch (Exception e) {
         log.error("Exception while parsing Json text", e);
         throw new JsonMappingException("Exception while parsing Json payload");
      }

      // Retrieve evaluated node within JSON tree.
      JsonNode evaluatedNode = rootNode.at(specification.getExp());
      String caseKey = evaluatedNode.asText();

      switch (specification.getOperator()) {
         case equals:
            // Consider simple equality.
            String value = specification.getCases().get(caseKey);
            return (value != null ? value : specification.getCases().getDefault());

         case range:
            // Consider range evaluation.
            double caseNumber = 0.000;
            try {
               caseNumber = Double.parseDouble(caseKey);
            } catch (NumberFormatException nfe) {
               log.error(caseKey + " into range expression cannot be parsed as number. Considering default case.");
               return specification.getCases().getDefault();
            }
            return foundRangeMatchingCase(caseNumber, specification.getCases());

         case regexp:
            // Consider regular expression evaluation for each case key.
            for (String choiceKey : specification.getCases().keySet()) {
               if (!"default".equals(choiceKey)) {
                  if (Pattern.matches(choiceKey, caseKey)) {
                     return specification.getCases().get(choiceKey);
                  }
               }
            }
            break;

         case size:
            // Consider size evaluation.
            if (evaluatedNode.isArray()) {
               int size = evaluatedNode.size();
               return foundRangeMatchingCase(size, specification.getCases());
            }
            break;

         case presence:
            // Consider presence evaluation of evaluatedNode directly.
            if (evaluatedNode != null && evaluatedNode.toString().length() > 0) {
               if (specification.getCases().containsKey("found")) {
                  return specification.getCases().get("found");
               }
            } else {
               if (specification.getCases().containsKey("missing")) {
                  return specification.getCases().get("missing");
               }
            }
            break;
      }
      return specification.getCases().getDefault();
   }
@Test
   void testRangeOperatorDispatcher() throws Exception {
      DispatchCases cases = new DispatchCases();
      Map<String, String> dispatchCases = new HashMap<>();
      dispatchCases.put("[4.2;5.0]", "Acceptable");
      dispatchCases.put("[0;4[", "Too low");
      dispatchCases.put("default", "Why not?");
      cases.putAll(dispatchCases);

      JsonEvaluationSpecification specifications = new JsonEvaluationSpecification();
      specifications.setExp("/rating");
      specifications.setOperator(EvaluationOperator.range);
      specifications.setCases(cases);

      String result = JsonExpressionEvaluator.evaluate(BELGIUM_BEER, specifications);
      assertEquals("Acceptable", result);

      result = JsonExpressionEvaluator.evaluate(GERMAN_BEER, specifications);
      assertEquals("Too low", result);

      result = JsonExpressionEvaluator.evaluate(ENGLISH_BEER, specifications);
      assertEquals("Why not?", result);
   }