public static Predicate parse(String expression)
  {
    final Stack<Predicate> predicateStack = new Stack<>();
    final Stack<Character> operatorStack = new Stack<>();

    final String trimmedExpression = TRIMMER_PATTERN.matcher(expression).replaceAll("");
    final StringTokenizer tokenizer = new StringTokenizer(trimmedExpression, OPERATORS, true);
    boolean isTokenMode = true;

    while (true)
    {
      final Character operator;
      final String token;

      if (isTokenMode)
      {
        if (tokenizer.hasMoreTokens())
        {
          token = tokenizer.nextToken();
        }
        else
        {
          break;
        }

        if (OPERATORS.contains(token))
        {
          operator = token.charAt(0);
        }
        else
        {
          operator = null;
        }
      }
      else
      {
        operator = operatorStack.pop();
        token = null;
      }
      isTokenMode = true;

      if (operator == null)
      {
        try
        {
          predicateStack.push(Class.forName(token).asSubclass(Predicate.class).getDeclaredConstructor().newInstance());
        }
        catch (ClassCastException e)
        {
          throw new RuntimeException(token + " must implement " + Predicate.class.getName(), e);
        }
        catch (Exception e)
        {
          throw new RuntimeException(e);
        }
      }
      else
      {
        if (operatorStack.empty() || operator == '(')
        {
          operatorStack.push(operator);
        }
        else if (operator == ')')
        {
          while (operatorStack.peek() != '(')
          {
            evaluate(predicateStack, operatorStack);
          }

          operatorStack.pop();
        }
        else
        {
          if (OPERATOR_PRECEDENCE.get(operator) < OPERATOR_PRECEDENCE.get(operatorStack.peek()))
          {
            evaluate(predicateStack, operatorStack);
            isTokenMode = false;
          }

          operatorStack.push(operator);
        }
      }
    }

    while (!operatorStack.empty())
    {
      evaluate(predicateStack, operatorStack);
    }

    if (predicateStack.size() > 1)
    {
      throw new RuntimeException("Invalid logical expression");
    }

    return predicateStack.pop();
  }
@Test(expectedExceptions = RuntimeException.class)
  public void testNotPredicate()
  {
    PredicateExpressionParser.parse("com.linkedin.restli.tools.data.PredicateExpressionParser");
  }