Skip to end of metadata
Go to start of metadata

O módulo JExpression contem uma biblioteca simples e autocontida para interpretação de expressões cujos resultados são determinados por uma semântica da aplicação. Para tal, a API consiste basicamente de funções para a compilação (análise léxica e sintática) e para a avaliação. Na compilação, a biblioteca faz a análise de um texto (string) para validá-lo. E, na avaliação, JExpression interpreta as operações envolvidas com base em callbacks. As callbacks são fornecidas por um tratador de expressões (handler) que define o comportamento das operações, funções e variáveis envolvidas. O exemplo abaixo é bem elucidativo:

 

Análise Sintática
try {
   JExpressionHandler handler = new MyFavoriteHandler(); // usando handler da aplicação
   String exp = "A + B + 2.0";
   JExpression expression = JExpression.compile(exp);    // compilação
   Object result = expression.eval(handler);             // avaliação com um handler
}
catch (JExpressionSyntaxErrorException e) {
   System.out.println("Erro de sintaxe na expressão");
}
catch (Exception e) {
   e.printStackTrace();
   System.out.println("Erro na avaliação da expressão");
}

 

Cabe observar que o código de interpretação e avaliação é bem simples. A maior parte do trabalho para o uso correto da biblioteca está na definição do handler de avaliação. Este tratador deve ser um objeto que implementa a interface JExpressionHandler. No pacote util da biblioteca, existem bons exemplos de handlers. Com o nosso exemplo, podemos fazer um handler bem simples:

 

Handler
public class MyFavoriteHandler implements JExpressionHandler {

  // Exemplo aonde o valor, ao detectar um valor numérico simplesmente o repassa.
  @Override
  public Object handleDouble(Double value) throws Exception {
    return value;
  }


  // Exemplo aonde o handler não espera que existam valores textuais na expressão 
  // e sinaliza com uma exceção.
  @Override
  public Object handleString(String value) throws JExpressionException {
    throw new JExpressionException("Não tratamos strings!");
  }

  // Exemplo aonde o handler só aceita operandos do tipo double double para efetuar uma soma.
  @Override
  public Object handlePlus(Object first, Object second) throws Exception {
    if (first instanceof Double && second instanceof Double) {
      return ((Double) first) + (Double) second;
    }
    String f = "('+') Erro na conversão dos valores '%s' e '%s' para double.";
    throw new JExpressionException(String.format(f, first, second));
  }

  // Exemplo aonde o tratador busca valores associados à variáveis e dá uma exceção 
  // se a mesma não estiver definida.
  @Override
  public Object handleVar(String name) throws Exception {
    if (name.equals("A") {
       return new Double(45.0);
    }
    if (name.equals("B") {
       return new Double(12.0);
    }
    String f = "Variável '%s' não foi definida.";
    throw new JExpressionException(String.format(f, name));
  }



  // Implementação de outros métodos da interface que, se não forem do escopo de handler, 
  // devem sinalizar tipicamente exceção. Veja a lista completa de métodos no código da interface.
  // ...
}


Apesar dos tratadores serem naturalmente usados para avaliações numéricas, existe um grande potencial para que a biblioteca seja usada para fazer operações sobre os mais variados tipos de objetos. Esse comportamento fica a cargo do handler que a aplicação definir. Por exemplo, podemos dizer que "X + Y" são matrizes, navios, frutas etc.

A Interface JExpressionHandler

Segue a lista de métodos da interface com as operações tratadas.

RetornoMétodo
ObjecthandleAnd(Object first, Object second)
Callback da operação &&.
ObjecthandleDivision(Object first, Object second)
Callback de operação /.
ObjecthandleDouble(Double value)
Callback para valores Double.
ObjecthandleEqual(Object first, Object second)
Callback da operação ==.
ObjecthandleField(Object object, String field)
Callback de acesso a um campo de objeto.
ObjecthandleFunctionCall(String functionName, List<Object> params)
Callback de chamada de função.
ObjecthandleGreater(Object first, Object second)
Callback da operação >.
ObjecthandleGreaterEqual(Object first, Object second)
Callback da operação >=.
ObjecthandleIndex(Object object, Object index)
Callback de indexação.
ObjecthandleLower(Object first, Object second)
Callback da operação <.
ObjecthandleLowerEqual(Object first, Object second)
Callback da operação <=.
ObjecthandleMinus(Object first, Object second)
Callback de operação -.
ObjecthandleNot(Object object)
Callback do operador unário !.
ObjecthandleNotEqual(Object first, Object second)
Callback da operação !=.
ObjecthandleOr(Object first, Object second)
Callback de operação ||.
ObjecthandlePlus(Object first, Object second)
Callback da operação +.
ObjecthandlePow(Object first, Object second)
Callback da operação ^.
ObjecthandleQuestion(Object condition, Object then, Object otherwise)
Callback do operador ternário if-then-else (a ? b : c)
ObjecthandleString(String value)
Callback para valores String.
ObjecthandleTimes(Object first, Object second)
Callback de operação *.
ObjecthandleUnaryMinus(Object object)
Callback do operador unário -.
ObjecthandleVar(String name)
Callback de variável.



Write a comment…