Skip to content

Commit 1eeb428

Browse files
committed
Update exception handling for schema
1 parent 99292fe commit 1eeb428

28 files changed

+379
-298
lines changed

src/main/java/com/relogiclabs/jschema/internal/message/ActualHelper.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.relogiclabs.jschema.message.ActualDetail;
44
import com.relogiclabs.jschema.node.JArray;
55
import com.relogiclabs.jschema.node.JNode;
6+
import com.relogiclabs.jschema.node.JObject;
67
import com.relogiclabs.jschema.node.JProperty;
78

89
import static com.relogiclabs.jschema.internal.message.MessageHelper.getTypeName;
@@ -14,15 +15,15 @@ private ActualHelper() {
1415
throw new UnsupportedOperationException();
1516
}
1617

17-
public static ActualDetail asArrayElementNotFound(JArray array, int index) {
18+
public static ActualDetail asArrayElementNotFound(JArray array) {
1819
return new ActualDetail(array, "not found");
1920
}
2021

21-
public static ActualDetail asValueMismatch(JNode node) {
22+
public static ActualDetail asValueMismatched(JNode node) {
2223
return new ActualDetail(node, "found " + node.getOutline());
2324
}
2425

25-
public static ActualDetail asGeneralValueMismatch(JNode node) {
26+
public static ActualDetail asGeneralValidationFailed(JNode node) {
2627
return new ActualDetail(node, "found " + node.getOutline());
2728
}
2829

@@ -35,27 +36,29 @@ public static ActualDetail asDataTypeArgumentFailed(JNode node) {
3536
return new ActualDetail(node, "found invalid value " + node.getOutline());
3637
}
3738

38-
public static ActualDetail asDataTypeMismatch(JNode node) {
39+
public static ActualDetail asDataTypeMismatched(JNode node) {
3940
return new ActualDetail(node, "found " + getTypeName(node)
4041
+ " inferred by " + node.getOutline());
4142
}
4243

43-
public static ActualDetail asPropertyNotFound(JNode node, JProperty property) {
44-
return new ActualDetail(node, "not found property key " + quote(property.getKey()));
44+
public static ActualDetail asPropertyNotFound(JNode node, JProperty property, JObject object) {
45+
return new ActualDetail(node, "not found property key " + quote(property.getKey())
46+
+ " in target object " + object.getOutline());
4547
}
4648

47-
public static ActualDetail asUndefinedProperty(JProperty property) {
49+
public static ActualDetail asUndefinedPropertyFound(JProperty property) {
4850
return new ActualDetail(property, "property found {" + property.getOutline() + "}");
4951
}
5052

51-
public static ActualDetail asPropertyOrderMismatch(JNode node) {
53+
public static ActualDetail asPropertyOrderMismatched(JNode node) {
5254
return node instanceof JProperty property
5355
? new ActualDetail(property, "key " + quote(property.getKey())
54-
+ " is found at current position")
55-
: new ActualDetail(node, "key not found at current position");
56+
+ " in target is found at current position")
57+
: new ActualDetail(node, "no key in target found at current position");
5658
}
5759

58-
public static ActualDetail asInvalidFunction(JNode node) {
59-
return new ActualDetail(node, "applied on non-composite type " + getTypeName(node));
60+
public static ActualDetail asNestedFunctionFailed(JNode node) {
61+
return new ActualDetail(node, "found non-composite target " + getTypeName(node)
62+
+ " of " + node.getOutline());
6063
}
6164
}

src/main/java/com/relogiclabs/jschema/internal/message/ExpectedHelper.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.relogiclabs.jschema.internal.message;
22

3+
import com.relogiclabs.jschema.internal.util.MatchResult;
34
import com.relogiclabs.jschema.message.ExpectedDetail;
45
import com.relogiclabs.jschema.node.JDataType;
56
import com.relogiclabs.jschema.node.JFunction;
@@ -17,19 +18,23 @@ private ExpectedHelper() {
1718
}
1819

1920
public static ExpectedDetail asArrayElementNotFound(JNode node, int index) {
20-
return new ExpectedDetail(node, "'" + node.getOutline() + "' element at " + index);
21+
return new ExpectedDetail(node, "an element for [" + node.getOutline()
22+
+ "] at " + index);
2123
}
2224

23-
public static ExpectedDetail asValueMismatch(JNode node) {
25+
public static ExpectedDetail asValueMismatched(JNode node) {
2426
return new ExpectedDetail(node, "value " + node.getOutline());
2527
}
2628

27-
public static ExpectedDetail asGeneralValueMismatch(JNode node) {
29+
public static ExpectedDetail asGeneralValidationFailed(JNode node) {
2830
return new ExpectedDetail(node, "a valid value of " + node.getOutline());
2931
}
3032

31-
public static ExpectedDetail asDataTypeMismatch(JDataType dataType) {
32-
return new ExpectedDetail(dataType, "data type " + dataType.toString(true));
33+
public static ExpectedDetail asDataTypeMismatched(JDataType dataType, MatchResult result) {
34+
var builder = new StringBuilder("data type ").append(dataType.toString(true));
35+
if(result.getPattern() == null) return new ExpectedDetail(dataType, builder.toString());
36+
builder.append(" formatted as ").append(quote(result.getPattern()));
37+
return new ExpectedDetail(dataType, builder.toString());
3338
}
3439

3540
public static ExpectedDetail asInvalidNonCompositeType(JDataType dataType) {
@@ -40,24 +45,24 @@ public static ExpectedDetail asDataTypeArgumentFailed(JDataType dataType) {
4045
return new ExpectedDetail(dataType, "a valid value for " + quote(dataType.getAlias()));
4146
}
4247

43-
public static ExpectedDetail asDataTypeMismatch(JNode node) {
48+
public static ExpectedDetail asDataTypeMismatched(JNode node) {
4449
return new ExpectedDetail(node, getTypeName(node) + " inferred by " + node.getOutline());
4550
}
4651

4752
public static ExpectedDetail asPropertyNotFound(JProperty property) {
48-
return new ExpectedDetail(property, "property {" + property.getOutline() + "}");
53+
return new ExpectedDetail(property, "a property for {" + property.getOutline() + "}");
4954
}
5055

51-
public static ExpectedDetail asUndefinedProperty(JObject object, JProperty property) {
56+
public static ExpectedDetail asUndefinedPropertyFound(JObject object, JProperty property) {
5257
return new ExpectedDetail(object, "no property with key " + quote(property.getKey()));
5358
}
5459

55-
public static ExpectedDetail asPropertyOrderMismatch(JProperty property) {
56-
return new ExpectedDetail(property, "property with key "
60+
public static ExpectedDetail asPropertyOrderMismatched(JProperty property) {
61+
return new ExpectedDetail(property, "a property with key "
5762
+ quote(property.getKey()) + " at current position");
5863
}
5964

60-
public static ExpectedDetail asInvalidFunction(JFunction function) {
61-
return new ExpectedDetail(function, "applying on composite type");
65+
public static ExpectedDetail asNestedFunctionFailed(JFunction function) {
66+
return new ExpectedDetail(function, "a composite data type for " + function);
6267
}
6368
}

src/main/java/com/relogiclabs/jschema/internal/message/MessageHelper.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,27 @@
66
import com.relogiclabs.jschema.type.EType;
77

88
public final class MessageHelper {
9-
109
public static final String ValidationFailed = "Validation failed";
11-
public static final String ValueMismatch = "Value mismatch";
12-
public static final String DataTypeMismatch = "Data type mismatch";
10+
public static final String ValueMismatched = "Value mismatched";
11+
public static final String DataTypeMismatched = "Data type mismatched";
1312
public static final String InvalidNonCompositeType = "Invalid non-composite value type";
13+
public static final String NestedFunctionFailed = "Nested function failed for invalid target";
1414
public static final String DataTypeArgumentFailed = "Data type argument failed";
15-
public static final String InvalidNestedFunction = "Invalid nested function operation";
1615
public static final String PropertyNotFound = "Mandatory property not found";
1716
public static final String ArrayElementNotFound = "Mandatory array element not found";
1817
public static final String UndefinedPropertyFound = "Undefined property found";
19-
public static final String PropertyKeyMismatch = "Property key mismatch";
20-
public static final String PropertyValueMismatch = "Property value mismatch";
21-
public static final String PropertyOrderMismatch = "Property order mismatch";
18+
public static final String PropertyKeyMismatched = "Property key mismatched";
19+
public static final String PropertyValueMismatched = "Property value mismatched";
20+
public static final String PropertyOrderMismatched = "Property order mismatched";
2221

2322
private MessageHelper() {
2423
throw new UnsupportedOperationException();
2524
}
2625

2726
public static String getTypeName(JNode node) {
2827
return node instanceof JsonTypable jsonTypable
29-
? jsonTypable.getType().getName()
30-
: node.getClass().getName();
28+
? jsonTypable.getType().getName()
29+
: node.getClass().getName();
3130
}
3231

3332
public static String getTypeName(Class<?> type) {
Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.relogiclabs.jschema.internal.util;
22

3-
import com.relogiclabs.jschema.exception.CommonException;
43
import com.relogiclabs.jschema.exception.DateTimeLexerException;
54
import com.relogiclabs.jschema.exception.JsonLexerException;
65
import com.relogiclabs.jschema.exception.SchemaLexerException;
@@ -9,50 +8,53 @@
98
import org.antlr.v4.runtime.RecognitionException;
109
import org.antlr.v4.runtime.Recognizer;
1110

12-
import static com.relogiclabs.jschema.message.ErrorCode.DLEX01;
13-
import static com.relogiclabs.jschema.message.ErrorCode.JLEX01;
14-
import static com.relogiclabs.jschema.message.ErrorCode.SLEX01;
11+
import static com.relogiclabs.jschema.message.ErrorCode.JSNLEX01;
12+
import static com.relogiclabs.jschema.message.ErrorCode.LEXRDT01;
13+
import static com.relogiclabs.jschema.message.ErrorCode.SCMLEX01;
1514
import static com.relogiclabs.jschema.message.MessageFormatter.ERROR_POINTER;
15+
import static org.apache.commons.lang3.StringUtils.isEmpty;
1616

1717
public abstract class LexerErrorListener extends BaseErrorListener {
1818
public static final LexerErrorListener SCHEMA = new SchemaErrorListener();
1919
public static final LexerErrorListener JSON = new JsonErrorListener();
2020
public static final LexerErrorListener DATE_TIME = new DateTimeErrorListener();
2121

22-
protected abstract CommonException failOnSyntaxError(String message, Throwable cause);
22+
private static final String NOT_FOUND = "<NOT_FOUND>";
23+
24+
protected abstract RuntimeException failOnSyntaxError(String message, Throwable cause);
2325
protected abstract String getMessageFormat();
2426

2527
private static final class SchemaErrorListener extends LexerErrorListener {
2628

2729
@Override
28-
protected CommonException failOnSyntaxError(String message, Throwable cause) {
29-
return new SchemaLexerException(SLEX01, message, cause);
30+
protected RuntimeException failOnSyntaxError(String message, Throwable cause) {
31+
return new SchemaLexerException(SCMLEX01, message, cause);
3032
}
3133

3234
@Override
3335
protected String getMessageFormat() {
34-
return "Schema (Line %d:%d) [" + SLEX01 + "]: %s (Line: %s)";
36+
return "Schema (Line %d:%d) [" + SCMLEX01 + "]: %s (Line: %s)";
3537
}
3638
}
3739

3840
private static final class JsonErrorListener extends LexerErrorListener {
3941

4042
@Override
41-
protected CommonException failOnSyntaxError(String message, Throwable cause) {
42-
return new JsonLexerException(JLEX01, message, cause);
43+
protected RuntimeException failOnSyntaxError(String message, Throwable cause) {
44+
return new JsonLexerException(JSNLEX01, message, cause);
4345
}
4446

4547
@Override
4648
protected String getMessageFormat() {
47-
return "Json (Line %d:%d) [" + JLEX01 + "]: %s (Line: %s)";
49+
return "Json (Line %d:%d) [" + JSNLEX01 + "]: %s (Line: %s)";
4850
}
4951
}
5052

5153
private static final class DateTimeErrorListener extends LexerErrorListener {
5254

5355
@Override
54-
protected CommonException failOnSyntaxError(String message, Throwable cause) {
55-
return new DateTimeLexerException(DLEX01, message, cause);
56+
protected RuntimeException failOnSyntaxError(String message, Throwable cause) {
57+
return new DateTimeLexerException(LEXRDT01, message, cause);
5658
}
5759

5860
@Override
@@ -64,12 +66,28 @@ protected String getMessageFormat() {
6466
@Override
6567
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line,
6668
int charPositionInLine, String msg, RecognitionException e) {
67-
if(this == DATE_TIME) throw failOnSyntaxError(getMessageFormat().formatted(msg,
68-
((Lexer) recognizer).getText()), e);
69-
var errorLine = new StringBuilder(recognizer.getInputStream().toString()
70-
.split("\\r?\\n")[line - 1]).insert(charPositionInLine, ERROR_POINTER)
71-
.toString().trim();
69+
if(this == DATE_TIME) {
70+
var note = ((Lexer) recognizer).getText();
71+
if(isEmpty(note)) note = getLine(recognizer, line);
72+
throw failOnSyntaxError(getMessageFormat().formatted(msg, note), e);
73+
}
7274
throw failOnSyntaxError(getMessageFormat().formatted(line, charPositionInLine,
73-
msg, errorLine), e);
75+
msg, getErrorLine(recognizer, line, charPositionInLine)), e);
76+
}
77+
78+
private static String getErrorLine(Recognizer<?, ?> recognizer, int line, int charPositionInLine) {
79+
var stream = recognizer.getInputStream();
80+
if(stream == null) return NOT_FOUND;
81+
var textLine = stream.toString().lines().skip(line - 1).findFirst();
82+
if(textLine.isEmpty()) return NOT_FOUND;
83+
var textBuilder = new StringBuilder(textLine.get());
84+
if(textBuilder.length() < charPositionInLine) return NOT_FOUND;
85+
return textBuilder.insert(charPositionInLine, ERROR_POINTER).toString().trim();
86+
}
87+
88+
private static String getLine(Recognizer<?, ?> recognizer, int line) {
89+
var stream = recognizer.getInputStream();
90+
if(stream == null) return NOT_FOUND;
91+
return stream.toString().lines().skip(line - 1).findFirst().orElse(NOT_FOUND).trim();
7492
}
7593
}

src/main/java/com/relogiclabs/jschema/internal/util/LogHelper.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.relogiclabs.jschema.internal.util;
22

3-
import com.relogiclabs.jschema.exception.CommonException;
4-
import com.relogiclabs.jschema.exception.ScriptRuntimeException;
3+
import com.relogiclabs.jschema.exception.BaseRuntimeException;
4+
import com.relogiclabs.jschema.exception.MultilevelRuntimeException;
55
import com.relogiclabs.jschema.internal.time.DateTimeContext;
66
import com.relogiclabs.jschema.tree.DataTree;
77
import org.antlr.v4.runtime.Parser;
@@ -11,7 +11,7 @@
1111
import java.util.Collections;
1212
import java.util.List;
1313

14-
import static com.relogiclabs.jschema.message.ErrorCode.TRYS01;
14+
import static com.relogiclabs.jschema.message.ErrorCode.TRYFSE01;
1515
import static com.relogiclabs.jschema.message.MessageFormatter.formatForSchema;
1616

1717
// Logging library may require
@@ -61,10 +61,12 @@ public static void log(Exception exception, Token token) {
6161
if(level > INFO) return;
6262
System.out.println("[INFO] [TRYOF ERROR]: " + exception.getMessage());
6363
if(level > DEBUG) return;
64-
Exception ex = exception instanceof CommonException ? exception
65-
: new ScriptRuntimeException(formatForSchema(
66-
TRYS01, exception.getMessage(), token), exception);
64+
if((exception instanceof MultilevelRuntimeException ex && ex.isLowLevel())
65+
|| !(exception instanceof BaseRuntimeException)) {
66+
exception = new BaseRuntimeException(formatForSchema(TRYFSE01,
67+
exception.getMessage(), token), exception);
68+
}
6769
System.out.print("[DEBUG] [TRYOF ERROR]: ");
68-
ex.printStackTrace(System.out);
70+
exception.printStackTrace(System.out);
6971
}
7072
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.relogiclabs.jschema.internal.util;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
6+
@Getter
7+
@RequiredArgsConstructor
8+
public final class MatchResult {
9+
public static final MatchResult SUCCESS = new MatchResult(true);
10+
public static final MatchResult FAILURE = new MatchResult(false);
11+
12+
private final boolean success;
13+
private final String note;
14+
private final String pattern;
15+
16+
public MatchResult(boolean success) {
17+
this.success = success;
18+
this.note = null;
19+
this.pattern = null;
20+
}
21+
}

0 commit comments

Comments
 (0)