You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by im...@apache.org on 2021/05/26 23:43:41 UTC

[asterixdb] 35/38: [NO ISSUE][*DB][EXT] Fail with helpful error message on non-JSON object

This is an automated email from the ASF dual-hosted git repository.

imaxon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git

commit 528ee18a5a7d9c01aa1f3f94282fbff2063f688a
Author: Michael Blow <mb...@apache.org>
AuthorDate: Wed May 19 20:10:46 2021 -0400

    [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 <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Till Westmann <ti...@apache.org>
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
---
 .../java/org/apache/asterix/common/exceptions/ErrorCode.java  |  3 ++-
 .../src/main/resources/asx_errormsg/en.properties             |  1 +
 .../asterix/external/parser/AbstractJsonDataParser.java       | 11 ++++++++---
 .../asterix/external/parser/AbstractNestedDataParser.java     |  2 +-
 .../org/apache/asterix/external/parser/JSONDataParser.java    |  6 +++++-
 .../org/apache/asterix/external/parser/ParseException.java    |  4 ++++
 .../java/org/apache/asterix/external/parser/TweetParser.java  |  2 +-
 .../java/org/apache/hyracks/api/util/ErrorMessageUtil.java    | 11 +++++++----
 8 files changed, 29 insertions(+), 11 deletions(-)

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 @@ public enum ErrorCode implements IError {
     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 @@ public enum ErrorCode implements IError {
     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 @@ public abstract class AbstractJsonDataParser extends AbstractNestedDataParser<AD
 
                 //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 @@ public abstract class AbstractJsonDataParser extends AbstractNestedDataParser<AD
         }
     }
 
-    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 @@ public abstract class AbstractNestedDataParser<T> extends AbstractDataParser {
     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 @@ public class JSONDataParser extends AbstractJsonDataParser implements IStreamDat
             //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 @@ public class ParseException extends HyracksDataException {
         }
         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 @@ public class TweetParser extends AbstractDataParser implements IRecordDataParser
                 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 @@ public class ErrorMessageUtil {
         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(')');