[NO ISSUE][*DB][EXT] Fail with helpful error message on non-JSON object
Change-Id: Ia096e108aa062e87a92f29ad3812f118390f411e
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/11525
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index 7e32e0b..4078ea2 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -307,7 +307,7 @@
PARSER_ADM_DATA_PARSER_CAST_ERROR(3072),
PARSER_ADM_DATA_PARSER_CONSTRUCTOR_MISSING_DESERIALIZER(3073),
PARSER_ADM_DATA_PARSER_WRONG_INSTANCE(3074),
- PARSER_TWEET_PARSER_CLOSED_FIELD_NULL(3075),
+ PARSER_EXT_DATA_PARSER_CLOSED_FIELD_NULL(3075),
UTIL_FILE_SYSTEM_WATCHER_NO_FILES_FOUND(3076),
UTIL_LOCAL_FILE_SYSTEM_UTILS_PATH_NOT_FOUND(3077),
UTIL_HDFS_UTILS_CANNOT_OBTAIN_HDFS_SCHEDULER(3078),
@@ -349,6 +349,7 @@
FAILED_TO_PARSE_MALFORMED_LOG_RECORD(3117),
ACTIVE_ENTITY_NOT_RUNNING(3118),
REQUIRED_PARAM_IF_PARAM_IS_PRESENT(3119),
+ PARSER_DATA_PARSER_UNEXPECTED_TOKEN(3120),
// Lifecycle management errors
DUPLICATE_PARTITION_ID(4000),
diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index 345b9d8..18898bb 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -354,6 +354,7 @@
3117 = Failed to parse record, malformed log record
3118 = Active Entity %1$s is not running (it is %2$s)
3119 = Parameter '%1$s' is required if '%2$s' is provided
+3120 = Unexpected token %s: was expecting %s
# Lifecycle management errors
4000 = Partition id %1$s for node %2$s already in use by node %3$s
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractJsonDataParser.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractJsonDataParser.java
index a5d5a08..2bf0df4 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractJsonDataParser.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractJsonDataParser.java
@@ -212,7 +212,7 @@
//fail fast if the current field is not nullable
if (currentToken() == ADMToken.NULL && !isNullableType(fieldType)) {
- throw new RuntimeDataException(ErrorCode.PARSER_TWEET_PARSER_CLOSED_FIELD_NULL, fieldName);
+ throw new RuntimeDataException(ErrorCode.PARSER_EXT_DATA_PARSER_CLOSED_FIELD_NULL, fieldName);
}
nullBitMap.set(fieldIndex);
@@ -415,13 +415,18 @@
}
}
- protected HyracksDataException createException(IOException e) {
+ protected HyracksDataException createException(Exception e) {
if (jsonParser != null) {
String msg;
if (e instanceof JsonParseException) {
msg = ((JsonParseException) e).getOriginalMessage();
} else {
- msg = ExceptionUtils.getRootCause(e).getMessage();
+ Throwable rootCause = ExceptionUtils.getRootCause(e);
+ if (rootCause instanceof ParseException) {
+ msg = ((ParseException) rootCause).getOriginalMessage();
+ } else {
+ msg = ExceptionUtils.getRootCause(e).getMessage();
+ }
}
if (msg == null) {
msg = ErrorCode.RECORD_READER_MALFORMED_INPUT_STREAM.errorMessage();
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractNestedDataParser.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractNestedDataParser.java
index c6f605d..eecbb19 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractNestedDataParser.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractNestedDataParser.java
@@ -116,7 +116,7 @@
protected void checkOptionalConstraints(ARecordType recordType, BitSet nullBitmap) throws RuntimeDataException {
for (int i = 0; i < recordType.getFieldTypes().length; i++) {
if (!nullBitmap.get(i) && !isMissableType(recordType.getFieldTypes()[i])) {
- throw new RuntimeDataException(ErrorCode.PARSER_TWEET_PARSER_CLOSED_FIELD_NULL,
+ throw new RuntimeDataException(ErrorCode.PARSER_EXT_DATA_PARSER_CLOSED_FIELD_NULL,
recordType.getFieldNames()[i]);
}
}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/JSONDataParser.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/JSONDataParser.java
index b4ec46e..b2cffa9 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/JSONDataParser.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/JSONDataParser.java
@@ -18,6 +18,8 @@
*/
package org.apache.asterix.external.parser;
+import static org.apache.asterix.common.exceptions.ErrorCode.PARSER_DATA_PARSER_UNEXPECTED_TOKEN;
+
import java.io.DataOutput;
import java.io.IOException;
import java.io.InputStream;
@@ -76,7 +78,9 @@
//TODO(wyk): find a way to reset byte[] instead of creating a new parser for each record.
jsonParser = jsonFactory.createParser(record.get(), 0, record.size());
geometryCoParser.reset(jsonParser);
- nextToken();
+ if (nextToken() != ADMToken.OBJECT_START) {
+ throw new ParseException(PARSER_DATA_PARSER_UNEXPECTED_TOKEN, currentToken(), ADMToken.OBJECT_START);
+ }
parseObject(rootType, out);
return true;
} catch (IOException e) {
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ParseException.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ParseException.java
index e9f93c9..f130fb3 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ParseException.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ParseException.java
@@ -84,4 +84,8 @@
}
return msg.append(": ").append(super.getMessage()).toString();
}
+
+ public String getOriginalMessage() {
+ return super.getMessage();
+ }
}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/TweetParser.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/TweetParser.java
index 4726a50..b970b04 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/TweetParser.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/TweetParser.java
@@ -199,7 +199,7 @@
DataOutput fieldOutput = fieldValueBuffer.getDataOutput();
if (obj.get(curFNames[iter1]).isNull() && !(curTypes[iter1] instanceof AUnionType)) {
if (curRecType.isClosedField(curFNames[iter1])) {
- throw new RuntimeDataException(ErrorCode.PARSER_TWEET_PARSER_CLOSED_FIELD_NULL,
+ throw new RuntimeDataException(ErrorCode.PARSER_EXT_DATA_PARSER_CLOSED_FIELD_NULL,
curFNames[iter1]);
} else {
continue;
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java
index 6479c8d..70b13fa 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java
@@ -102,12 +102,15 @@
try (Formatter fmt = new Formatter()) {
if (!NONE.equals(component)) {
fmt.format("%1$s%2$04d: ", component, errorCode);
+
+ // if the message is already formatted, just return it
+ if (message.startsWith(fmt.toString())) {
+ return message;
+ }
}
- // if the message is already formatted, just return it
- if (!fmt.toString().isEmpty() && message.startsWith(fmt.toString())) {
- return message;
+ if (message != null) {
+ fmt.format(message, (Object[]) params);
}
- fmt.format(message == null ? "null" : message, (Object[]) params);
if (sourceLoc != null) {
fmt.out().append(" (in line ").append(String.valueOf(sourceLoc.getLine())).append(", at column ")
.append(String.valueOf(sourceLoc.getColumn())).append(')');