From 9124cdddc3344fb450492a62c6d87eea79b4ad42 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Sun, 21 May 2017 22:11:16 +0200 Subject: [PATCH] handle IllegalArgumentException when fact type does not match parameter type --- .../java/org/jeasy/rules/core/RuleProxy.java | 24 +++++++----- .../jeasy/rules/core/AnnotatedRulesTest.java | 37 ++++++++++++++++--- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java index d2522b9..3fd41aa 100644 --- a/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java @@ -23,11 +23,11 @@ */ package org.jeasy.rules.core; -import org.jeasy.rules.annotation.Fact; -import org.jeasy.rules.api.Facts; import org.jeasy.rules.annotation.Action; import org.jeasy.rules.annotation.Condition; +import org.jeasy.rules.annotation.Fact; import org.jeasy.rules.annotation.Priority; +import org.jeasy.rules.api.Facts; import org.jeasy.rules.api.Rule; import java.lang.annotation.Annotation; @@ -36,6 +36,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.*; +import static java.lang.String.format; + /** * Main class to create rule proxies from annotated objects. * @@ -87,7 +89,12 @@ public class RuleProxy implements InvocationHandler { Facts facts = (Facts) args[0]; Method conditionMethod = getConditionMethod(); List actualParameters = getActualParameters(conditionMethod, facts); - return conditionMethod.invoke(target, actualParameters.toArray()); // validated upfront + try { + return conditionMethod.invoke(target, actualParameters.toArray()); // validated upfront + } catch (IllegalArgumentException e) { + String error = "Types of injected facts in method '%s' in rule '%s' do not match parameters types"; + throw new RuntimeException(format(error, conditionMethod.getName(), target.getClass().getName()), e); + } } if (methodName.equals("execute")) { for (ActionMethodOrderBean actionMethodBean : getActionMethodBeans()) { @@ -121,19 +128,18 @@ public class RuleProxy implements InvocationHandler { private List getActualParameters(Method method, Facts facts) { List actualParameters = new ArrayList<>(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - for(Annotation[] ann : parameterAnnotations){ - if(ann.length == 1){ - String factName = ((Fact) (ann[0])).value(); //validated upfront. + for (Annotation[] annotations : parameterAnnotations) { + if (annotations.length == 1) { + String factName = ((Fact) (annotations[0])).value(); //validated upfront. Object fact = facts.get(factName); - if(fact == null){ - throw new RuntimeException(String.format("No fact named %s found in known facts", factName)); + if (fact == null) { + throw new RuntimeException(format("No fact named %s found in known facts", factName)); } actualParameters.add(fact); } else { actualParameters.add(facts); //validated upfront, there may be only one parameter not annotated and which is of type Facts.class } } - return actualParameters; } diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotatedRulesTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotatedRulesTest.java index a2f676c..5316131 100644 --- a/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotatedRulesTest.java +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotatedRulesTest.java @@ -32,6 +32,8 @@ import org.jeasy.rules.api.Rules; import org.jeasy.rules.api.RulesEngine; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + public class AnnotatedRulesTest { @Test @@ -40,10 +42,23 @@ public class AnnotatedRulesTest { facts.add("rain", true); facts.add("age", 18); - Rules rules = new Rules( - new WeatherRule(), - new AgeRule() - ); + WeatherRule weatherRule = new WeatherRule(); + AgeRule ageRule = new AgeRule(); + Rules rules = new Rules(weatherRule, ageRule); + + RulesEngine rulesEngine = new DefaultRulesEngine(); + rulesEngine.fire(rules, facts); + + assertThat(ageRule.isExecuted()).isTrue(); + assertThat(weatherRule.isExecuted()).isTrue(); + } + + @Test(expected = RuntimeException.class) + public void whenFactTypeDoesNotMatchParameterType_thenShouldThrowRuntimeException() throws Exception { + Facts facts = new Facts(); + facts.add("age", "foo"); + + Rules rules = new Rules(new AgeRule()); RulesEngine rulesEngine = new DefaultRulesEngine(); @@ -53,22 +68,30 @@ public class AnnotatedRulesTest { @Rule class AgeRule { + private boolean isExecuted; + @Condition public boolean isAdult(@Fact("age") int age) { return age >= 18; } @Action - public void then() { + public void printYourAreAdult() { System.out.println("You are an adult"); + isExecuted = true; } + public boolean isExecuted() { + return isExecuted; + } } @Rule class WeatherRule { + private boolean isExecuted; + @Condition public boolean itRains(@Fact("rain") boolean rain) { return rain; @@ -77,7 +100,11 @@ public class AnnotatedRulesTest { @Action public void takeAnUmbrella(Facts facts) { System.out.println("It rains, take an umbrella!"); + isExecuted = true; } + public boolean isExecuted() { + return isExecuted; + } } }