diff --git a/sql/src/main/java/io/cloudevents/sql/EvaluationException.java b/sql/src/main/java/io/cloudevents/sql/EvaluationException.java index ab97537ab..e5ea1f663 100644 --- a/sql/src/main/java/io/cloudevents/sql/EvaluationException.java +++ b/sql/src/main/java/io/cloudevents/sql/EvaluationException.java @@ -43,7 +43,7 @@ public enum ErrorKind { private final Interval interval; private final String expression; - protected EvaluationException(ErrorKind errorKind, Interval interval, String expression, String message, Throwable cause) { + public EvaluationException(ErrorKind errorKind, Interval interval, String expression, String message, Throwable cause) { super(String.format("%s at %s `%s`: %s", errorKind.name(), interval.toString(), expression, message), cause); this.errorKind = errorKind; this.interval = interval; @@ -62,63 +62,4 @@ public String getExpressionText() { return expression; } - public static EvaluationExceptionFactory invalidCastTarget(Class from, Class to) { - return (interval, expression) -> new EvaluationException( - ErrorKind.INVALID_CAST, - interval, - expression, - "Cannot cast " + from + " to " + to + ": no cast defined.", - null - ); - } - - public static EvaluationExceptionFactory castError(Class from, Class to, Throwable cause) { - return (interval, expression) -> new EvaluationException( - ErrorKind.INVALID_CAST, - interval, - expression, - "Cannot cast " + from + " to " + to + ": " + cause.getMessage(), - cause - ); - } - - public static EvaluationException missingAttribute(Interval interval, String expression, String key) { - return new EvaluationException( - ErrorKind.MISSING_ATTRIBUTE, - interval, - expression, - "Missing attribute " + key + " in the input event. Perhaps you should check with 'EXISTS " + key + "' if the input contains the provided key?", - null - ); - } - - public static EvaluationException cannotDispatchFunction(Interval interval, String expression, String functionName, Throwable cause) { - return new EvaluationException( - ErrorKind.FUNCTION_DISPATCH, - interval, - expression, - "Cannot dispatch function invocation to function " + functionName + ": " + cause.getMessage(), - cause - ); - } - - public static EvaluationExceptionFactory functionExecutionError(String functionName, Throwable cause) { - return (interval, expression) -> new EvaluationException( - ErrorKind.FUNCTION_EXECUTION, - interval, - expression, - "Error while executing " + functionName + ": " + cause.getMessage(), - cause - ); - } - - public static EvaluationException divisionByZero(Interval interval, String expression, Integer dividend) { - return new EvaluationException( - ErrorKind.MATH, - interval, - expression, - "Division by zero: " + dividend + " / 0", - null - ); - } } diff --git a/sql/src/main/java/io/cloudevents/sql/ParseException.java b/sql/src/main/java/io/cloudevents/sql/ParseException.java index 77212a02b..7fd477f53 100644 --- a/sql/src/main/java/io/cloudevents/sql/ParseException.java +++ b/sql/src/main/java/io/cloudevents/sql/ParseException.java @@ -1,8 +1,6 @@ package io.cloudevents.sql; -import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.misc.Interval; -import org.antlr.v4.runtime.tree.ParseTree; /** * This exception represents an error occurred during parsing. @@ -10,8 +8,17 @@ public class ParseException extends RuntimeException { public enum ErrorKind { + /** + * Error when parsing the expression string + */ RECOGNITION, + /** + * Error when parsing a literal + */ PARSE_VALUE, + /** + * Error when executing the constant parts of the expression + */ CONSTANT_EXPRESSION_EVALUATION, } @@ -19,7 +26,7 @@ public enum ErrorKind { private final Interval interval; private final String expression; - protected ParseException(ErrorKind errorKind, Interval interval, String expression, String message, Throwable cause) { + public ParseException(ErrorKind errorKind, Interval interval, String expression, String message, Throwable cause) { super(String.format("[%s at %d:%d `%s`] %s", errorKind.name(), interval.a, interval.b, expression, message), cause); this.errorKind = errorKind; this.interval = interval; @@ -38,34 +45,4 @@ public String getExpression() { return expression; } - public static ParseException cannotParseValue(ParseTree node, Type target, Throwable cause) { - return new ParseException( - ErrorKind.PARSE_VALUE, - node.getSourceInterval(), - node.getText(), - "Cannot parse to " + target.name() + ": " + cause.getMessage(), - cause - ); - } - - public static ParseException recognitionError(RecognitionException e, String msg) { - return new ParseException( - ErrorKind.RECOGNITION, - new Interval(e.getOffendingToken().getStartIndex(), e.getOffendingToken().getStopIndex()), - e.getOffendingToken().getText(), - "Cannot parse: " + msg, - e - ); - } - - public static ParseException cannotEvaluateConstantExpression(EvaluationException exception) { - return new ParseException( - ErrorKind.CONSTANT_EXPRESSION_EVALUATION, - exception.getExpressionInterval(), - exception.getExpressionText(), - "Cannot evaluate the constant expression: " + exception.getExpressionText(), - exception - ); - } - } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/ExceptionFactory.java b/sql/src/main/java/io/cloudevents/sql/impl/ExceptionFactory.java new file mode 100644 index 000000000..ec03498e4 --- /dev/null +++ b/sql/src/main/java/io/cloudevents/sql/impl/ExceptionFactory.java @@ -0,0 +1,107 @@ +package io.cloudevents.sql.impl; + +import io.cloudevents.sql.EvaluationException; +import io.cloudevents.sql.ParseException; +import io.cloudevents.sql.Type; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.misc.Interval; +import org.antlr.v4.runtime.tree.ParseTree; + +/** + * This class includes a list of static methods to create {@link io.cloudevents.sql.ParseException} and {@link io.cloudevents.sql.EvaluationException}. + */ +public class ExceptionFactory { + + private ExceptionFactory() { + } + + public static EvaluationException.EvaluationExceptionFactory invalidCastTarget(Class from, Class to) { + return (interval, expression) -> new EvaluationException( + EvaluationException.ErrorKind.INVALID_CAST, + interval, + expression, + "Cannot cast " + from + " to " + to + ": no cast defined.", + null + ); + } + + public static EvaluationException.EvaluationExceptionFactory castError(Class from, Class to, Throwable cause) { + return (interval, expression) -> new EvaluationException( + EvaluationException.ErrorKind.INVALID_CAST, + interval, + expression, + "Cannot cast " + from + " to " + to + ": " + cause.getMessage(), + cause + ); + } + + public static EvaluationException missingAttribute(Interval interval, String expression, String key) { + return new EvaluationException( + EvaluationException.ErrorKind.MISSING_ATTRIBUTE, + interval, + expression, + "Missing attribute " + key + " in the input event. Perhaps you should check with 'EXISTS " + key + "' if the input contains the provided key?", + null + ); + } + + public static EvaluationException cannotDispatchFunction(Interval interval, String expression, String functionName, Throwable cause) { + return new EvaluationException( + EvaluationException.ErrorKind.FUNCTION_DISPATCH, + interval, + expression, + "Cannot dispatch function invocation to function " + functionName + ": " + cause.getMessage(), + cause + ); + } + + public static EvaluationException.EvaluationExceptionFactory functionExecutionError(String functionName, Throwable cause) { + return (interval, expression) -> new EvaluationException( + EvaluationException.ErrorKind.FUNCTION_EXECUTION, + interval, + expression, + "Error while executing " + functionName + ": " + cause.getMessage(), + cause + ); + } + + public static EvaluationException divisionByZero(Interval interval, String expression, Integer dividend) { + return new EvaluationException( + EvaluationException.ErrorKind.MATH, + interval, + expression, + "Division by zero: " + dividend + " / 0", + null + ); + } + + public static ParseException cannotParseValue(ParseTree node, Type target, Throwable cause) { + return new ParseException( + ParseException.ErrorKind.PARSE_VALUE, + node.getSourceInterval(), + node.getText(), + "Cannot parse to " + target.name() + ": " + cause.getMessage(), + cause + ); + } + + public static ParseException recognitionError(RecognitionException e, String msg) { + return new ParseException( + ParseException.ErrorKind.RECOGNITION, + new Interval(e.getOffendingToken().getStartIndex(), e.getOffendingToken().getStopIndex()), + e.getOffendingToken().getText(), + "Cannot parse: " + msg, + e + ); + } + + public static ParseException cannotEvaluateConstantExpression(EvaluationException exception) { + return new ParseException( + ParseException.ErrorKind.CONSTANT_EXPRESSION_EVALUATION, + exception.getExpressionInterval(), + exception.getExpressionText(), + "Cannot evaluate the constant expression: " + exception.getExpressionText(), + exception + ); + } +} diff --git a/sql/src/main/java/io/cloudevents/sql/impl/expressions/AccessAttributeExpression.java b/sql/src/main/java/io/cloudevents/sql/impl/expressions/AccessAttributeExpression.java index 1755a8fee..63243a91a 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/expressions/AccessAttributeExpression.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/expressions/AccessAttributeExpression.java @@ -2,8 +2,8 @@ import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.EvaluationRuntime; +import io.cloudevents.sql.impl.ExceptionFactory; import io.cloudevents.sql.impl.ExceptionThrower; import io.cloudevents.sql.impl.ExpressionInternalVisitor; import org.antlr.v4.runtime.misc.Interval; @@ -28,7 +28,7 @@ public Object evaluate(EvaluationRuntime runtime, CloudEvent event, ExceptionThr Object value = this.getter.apply(event); if (value == null) { thrower.throwException( - EvaluationException.missingAttribute(this.expressionInterval(), this.expressionText(), key) + ExceptionFactory.missingAttribute(this.expressionInterval(), this.expressionText(), key) ); return ""; } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/expressions/DivisionExpression.java b/sql/src/main/java/io/cloudevents/sql/impl/expressions/DivisionExpression.java index b28bb5803..8e54f0ac9 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/expressions/DivisionExpression.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/expressions/DivisionExpression.java @@ -1,7 +1,7 @@ package io.cloudevents.sql.impl.expressions; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.EvaluationRuntime; +import io.cloudevents.sql.impl.ExceptionFactory; import io.cloudevents.sql.impl.ExceptionThrower; import io.cloudevents.sql.impl.ExpressionInternal; import org.antlr.v4.runtime.misc.Interval; @@ -16,7 +16,7 @@ public DivisionExpression(Interval expressionInterval, String expressionText, Ex Object evaluate(EvaluationRuntime runtime, int left, int right, ExceptionThrower exceptions) { if (right == 0) { exceptions.throwException( - EvaluationException.divisionByZero(expressionInterval(), expressionText(), left) + ExceptionFactory.divisionByZero(expressionInterval(), expressionText(), left) ); return 0; } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/expressions/FunctionInvocationExpression.java b/sql/src/main/java/io/cloudevents/sql/impl/expressions/FunctionInvocationExpression.java index e36e76678..05183b851 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/expressions/FunctionInvocationExpression.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/expressions/FunctionInvocationExpression.java @@ -2,9 +2,9 @@ import io.cloudevents.CloudEvent; import io.cloudevents.sql.EvaluationContext; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.EvaluationRuntime; import io.cloudevents.sql.Function; +import io.cloudevents.sql.impl.ExceptionFactory; import io.cloudevents.sql.impl.ExceptionThrower; import io.cloudevents.sql.impl.ExpressionInternal; import io.cloudevents.sql.impl.ExpressionInternalVisitor; @@ -34,7 +34,7 @@ public Object evaluate(EvaluationRuntime runtime, CloudEvent event, ExceptionThr function = runtime.resolveFunction(functionName, arguments.size()); } catch (Exception e) { thrower.throwException( - EvaluationException.cannotDispatchFunction(expressionInterval(), expressionText(), functionName, e) + ExceptionFactory.cannotDispatchFunction(expressionInterval(), expressionText(), functionName, e) ); return ""; } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/expressions/ModuleExpression.java b/sql/src/main/java/io/cloudevents/sql/impl/expressions/ModuleExpression.java index f15abe7ce..aa11a38c3 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/expressions/ModuleExpression.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/expressions/ModuleExpression.java @@ -1,7 +1,7 @@ package io.cloudevents.sql.impl.expressions; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.EvaluationRuntime; +import io.cloudevents.sql.impl.ExceptionFactory; import io.cloudevents.sql.impl.ExceptionThrower; import io.cloudevents.sql.impl.ExpressionInternal; import org.antlr.v4.runtime.misc.Interval; @@ -16,7 +16,7 @@ public ModuleExpression(Interval expressionInterval, String expressionText, Expr Object evaluate(EvaluationRuntime runtime, int left, int right, ExceptionThrower exceptions) { if (right == 0) { exceptions.throwException( - EvaluationException.divisionByZero(expressionInterval(), expressionText(), left) + ExceptionFactory.divisionByZero(expressionInterval(), expressionText(), left) ); return 0; } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/functions/LeftFunction.java b/sql/src/main/java/io/cloudevents/sql/impl/functions/LeftFunction.java index cc3b7dc4b..563c6124b 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/functions/LeftFunction.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/functions/LeftFunction.java @@ -2,8 +2,8 @@ import io.cloudevents.CloudEvent; import io.cloudevents.sql.EvaluationContext; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.EvaluationRuntime; +import io.cloudevents.sql.impl.ExceptionFactory; public class LeftFunction extends BaseTwoArgumentFunction { public LeftFunction() { @@ -17,7 +17,7 @@ Object invoke(EvaluationContext ctx, EvaluationRuntime evaluationRuntime, CloudE } if (length < 0) { ctx.appendException( - EvaluationException.functionExecutionError(name(), new IllegalArgumentException("The length of the LEFT substring is lower than 0: " + length)) + ExceptionFactory.functionExecutionError(name(), new IllegalArgumentException("The length of the LEFT substring is lower than 0: " + length)) ); return s; } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/functions/RightFunction.java b/sql/src/main/java/io/cloudevents/sql/impl/functions/RightFunction.java index 3a110e627..b5817901c 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/functions/RightFunction.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/functions/RightFunction.java @@ -2,8 +2,8 @@ import io.cloudevents.CloudEvent; import io.cloudevents.sql.EvaluationContext; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.EvaluationRuntime; +import io.cloudevents.sql.impl.ExceptionFactory; public class RightFunction extends BaseTwoArgumentFunction { public RightFunction() { @@ -17,7 +17,7 @@ Object invoke(EvaluationContext ctx, EvaluationRuntime evaluationRuntime, CloudE } if (length < 0) { ctx.appendException( - EvaluationException.functionExecutionError(name(), new IllegalArgumentException("The length of the RIGHT substring is lower than 0: " + length)) + ExceptionFactory.functionExecutionError(name(), new IllegalArgumentException("The length of the RIGHT substring is lower than 0: " + length)) ); return s; } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/functions/SubstringFunction.java b/sql/src/main/java/io/cloudevents/sql/impl/functions/SubstringFunction.java index 1738a26d4..7123e1286 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/functions/SubstringFunction.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/functions/SubstringFunction.java @@ -2,8 +2,8 @@ import io.cloudevents.CloudEvent; import io.cloudevents.sql.EvaluationContext; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.EvaluationRuntime; +import io.cloudevents.sql.impl.ExceptionFactory; public class SubstringFunction extends BaseTwoArgumentFunction { public SubstringFunction() { @@ -15,7 +15,7 @@ Object invoke(EvaluationContext ctx, EvaluationRuntime evaluationRuntime, CloudE try { return SubstringWithLengthFunction.substring(x, pos, null); } catch (Exception e) { - ctx.appendException(EvaluationException.functionExecutionError( + ctx.appendException(ExceptionFactory.functionExecutionError( name(), e )); diff --git a/sql/src/main/java/io/cloudevents/sql/impl/functions/SubstringWithLengthFunction.java b/sql/src/main/java/io/cloudevents/sql/impl/functions/SubstringWithLengthFunction.java index c1edff078..50767507a 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/functions/SubstringWithLengthFunction.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/functions/SubstringWithLengthFunction.java @@ -2,8 +2,8 @@ import io.cloudevents.CloudEvent; import io.cloudevents.sql.EvaluationContext; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.EvaluationRuntime; +import io.cloudevents.sql.impl.ExceptionFactory; public class SubstringWithLengthFunction extends BaseThreeArgumentFunction { public SubstringWithLengthFunction() { @@ -15,7 +15,7 @@ Object invoke(EvaluationContext ctx, EvaluationRuntime evaluationRuntime, CloudE try { return substring(x, pos, len); } catch (Exception e) { - ctx.appendException(EvaluationException.functionExecutionError( + ctx.appendException(ExceptionFactory.functionExecutionError( name(), e )); diff --git a/sql/src/main/java/io/cloudevents/sql/impl/parser/ExpressionTranslatorVisitor.java b/sql/src/main/java/io/cloudevents/sql/impl/parser/ExpressionTranslatorVisitor.java index fd8d9b948..8ce88259f 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/parser/ExpressionTranslatorVisitor.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/parser/ExpressionTranslatorVisitor.java @@ -1,9 +1,9 @@ package io.cloudevents.sql.impl.parser; -import io.cloudevents.sql.ParseException; import io.cloudevents.sql.Type; import io.cloudevents.sql.generated.CESQLParserBaseVisitor; import io.cloudevents.sql.generated.CESQLParserParser; +import io.cloudevents.sql.impl.ExceptionFactory; import io.cloudevents.sql.impl.ExpressionInternal; import io.cloudevents.sql.impl.expressions.*; @@ -31,7 +31,7 @@ public ExpressionInternal visitIntegerLiteral(CESQLParserParser.IntegerLiteralCo try { return ValueExpression.fromIntegerLiteral(ctx.INTEGER_LITERAL()); } catch (RuntimeException e) { - throw ParseException.cannotParseValue(ctx, Type.INTEGER, e); + throw ExceptionFactory.cannotParseValue(ctx, Type.INTEGER, e); } } @@ -44,7 +44,7 @@ public ExpressionInternal visitStringLiteral(CESQLParserParser.StringLiteralCont return ValueExpression.fromSQuotedStringLiteral(ctx.SQUOTED_STRING_LITERAL()); } } catch (RuntimeException e) { - throw ParseException.cannotParseValue(ctx, Type.STRING, e); + throw ExceptionFactory.cannotParseValue(ctx, Type.STRING, e); } } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/parser/ParserImpl.java b/sql/src/main/java/io/cloudevents/sql/impl/parser/ParserImpl.java index 30f9437dc..c0f042358 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/parser/ParserImpl.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/parser/ParserImpl.java @@ -6,6 +6,7 @@ import io.cloudevents.sql.Parser; import io.cloudevents.sql.generated.CESQLParserLexer; import io.cloudevents.sql.generated.CESQLParserParser; +import io.cloudevents.sql.impl.ExceptionFactory; import io.cloudevents.sql.impl.ExpressionInternal; import io.cloudevents.sql.impl.runtime.ExpressionImpl; import org.antlr.v4.runtime.*; @@ -52,7 +53,7 @@ public Expression parse(String inputExpression) { @Override public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { parseExceptionList.add( - ParseException.recognitionError(e, msg) + ExceptionFactory.recognitionError(e, msg) ); } @@ -82,7 +83,7 @@ public void reportContextSensitivity(org.antlr.v4.runtime.Parser recognizer, DFA try { internal = internal.visit(new ConstantFoldingExpressionVisitor()); } catch (EvaluationException e) { - throw ParseException.cannotEvaluateConstantExpression(e); + throw ExceptionFactory.cannotEvaluateConstantExpression(e); } } diff --git a/sql/src/main/java/io/cloudevents/sql/impl/runtime/TypeCastingProvider.java b/sql/src/main/java/io/cloudevents/sql/impl/runtime/TypeCastingProvider.java index 51f881bcc..ddfc6c468 100644 --- a/sql/src/main/java/io/cloudevents/sql/impl/runtime/TypeCastingProvider.java +++ b/sql/src/main/java/io/cloudevents/sql/impl/runtime/TypeCastingProvider.java @@ -1,8 +1,8 @@ package io.cloudevents.sql.impl.runtime; import io.cloudevents.sql.EvaluationContext; -import io.cloudevents.sql.EvaluationException; import io.cloudevents.sql.Type; +import io.cloudevents.sql.impl.ExceptionFactory; import java.util.Objects; @@ -53,12 +53,12 @@ Object cast(EvaluationContext ctx, Object value, Type target) { return Integer.parseInt((String) value); } catch (NumberFormatException e) { ctx.appendException( - EvaluationException.castError(String.class, Integer.class, e) + ExceptionFactory.castError(String.class, Integer.class, e) ); } } else { ctx.appendException( - EvaluationException.invalidCastTarget(value.getClass(), target.valueClass()) + ExceptionFactory.invalidCastTarget(value.getClass(), target.valueClass()) ); } return 0; @@ -68,12 +68,12 @@ Object cast(EvaluationContext ctx, Object value, Type target) { return parseBool((String) value); } catch (IllegalArgumentException e) { ctx.appendException( - EvaluationException.castError(String.class, Boolean.class, e) + ExceptionFactory.castError(String.class, Boolean.class, e) ); } } else { ctx.appendException( - EvaluationException.invalidCastTarget(value.getClass(), target.valueClass()) + ExceptionFactory.invalidCastTarget(value.getClass(), target.valueClass()) ); } return false;