Executando expressões lógicas dinâmicas em java
October 29, 2013 Leave a comment
Esses dias me deparei com o seguinte problema: como gerar expressões lógicas a partir de atributos anotados de um objeto como no exemplo abaixo, que são construídas pelo usuário através de uma interface gráfica?
public class Contact { @MyAnnotion private String name; @MyAnnotation(operators={Operator.Equal, Operator.GreaterThan....}) private Date birthday; @MyAnnotion private String address; @MyAnnotation(operators={Operator.Equal, Operator.GreaterThan....}) private Integer age; }
Digamos que queremos construir regras como “nome contains ‘Joao’ AND birthday <= '10/12/2013' OR age < 18", ou seja queremos criar regras para serem aplicadas nos objetos Contacts e selecionar os objetos de acordo com aqueles que atendem a regra ou não. Construir a regra em si não é um grande problema. O desafio está em executar a regra construída obedecendo a precedência dos operadores lógicos, e havendo parênteses, aumenta a complexidade, pois temos que executar os mais internos primeiro.
Uma das soluções, apontada por um amigo meu, é gerar um programa java script e utilizar a engine de script para avaliar a expressão lógica gerada. Por exemplo a expressão “nome igual ‘Eduardo’ and idade > 10” seria traduzido para algo assim:
if('Eduardo' == 'Eduardo' && 30 > 10){ return true; } else { return false; }
Basicamente geramos uma string contendo um código semelhante ao mostrado acima substituindo o campos (nome,idade no exemplo) pelos seus respectivos valores e os operadores pelos seus correspondentes na linguagem javascript.
Abaixo segue o código completo do programa em java, mostrando a solução que adotamos e que funcionou muito bem, muito superior ao que tínhamos antes que gerava um SQL, mas tinha um problema grave, pois quando estamos criando ou editando um objeto ainda não colocamos o objeto (Contact no caso desse artigo) no banco, logo as regras que estão lá não conseguirão ser aplicadas sobre os novos dados. Mas salvar o objeto no banco para poder aplicar as regras e apagá-lo caso, o usuário desista da edição ou criação do novo contato, é um convite para erros de inconsistência no banco. O jeito foi executar as regras sem precisar do banco e essa solução de usar a script engine da JVM caiu como uma luva.
import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class ExecutaRegra { public static void main(String[] args){ try { String expressaoJavascript = "if('Teste'=='Teste1' || 1==0){r=true} else {r=false}"; ScriptEngineManager mgr = new ScriptEngineManager(); ScriptEngine jsEngine = mgr.getEngineByName("JavaScript"); boolean result = (Boolean) jsEngine.eval(expressaoJavascript); System.out.println("Resultado: " + result); } catch (ScriptException ex) { ex.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } }
Recent Comments