diff --git a/core/src/main/java/org/apache/iceberg/rest/requests/RemoteSignRequestParser.java b/core/src/main/java/org/apache/iceberg/rest/requests/RemoteSignRequestParser.java index 61b44cc177d1..a29326a76b6f 100644 --- a/core/src/main/java/org/apache/iceberg/rest/requests/RemoteSignRequestParser.java +++ b/core/src/main/java/org/apache/iceberg/rest/requests/RemoteSignRequestParser.java @@ -133,7 +133,7 @@ public static Map> headersFromJson(String property, JsonNod .forEach( entry -> { String key = entry.getKey(); - List values = Arrays.asList(JsonUtil.getStringArray(entry.getValue())); + List values = Arrays.asList(JsonUtil.getStringArray(key, headersNode)); headers.put(key, values); }); return headers; diff --git a/core/src/main/java/org/apache/iceberg/util/JsonUtil.java b/core/src/main/java/org/apache/iceberg/util/JsonUtil.java index d8bb1f919096..58d878b94901 100644 --- a/core/src/main/java/org/apache/iceberg/util/JsonUtil.java +++ b/core/src/main/java/org/apache/iceberg/util/JsonUtil.java @@ -272,11 +272,18 @@ public static String[] getStringArray(JsonNode node) { ArrayNode arrayNode = (ArrayNode) node; String[] arr = new String[arrayNode.size()]; for (int i = 0; i < arr.length; i++) { - arr[i] = arrayNode.get(i).asText(); + JsonNode element = arrayNode.get(i); + Preconditions.checkArgument( + element.isTextual(), "Cannot parse string from non-text value: %s", element); + arr[i] = element.asText(); } return arr; } + public static String[] getStringArray(String property, JsonNode node) { + return getStringList(property, node).toArray(new String[0]); + } + public static List getStringList(String property, JsonNode node) { Preconditions.checkArgument(node.has(property), "Cannot parse missing list: %s", property); return ImmutableList.builder() diff --git a/core/src/main/java/org/apache/iceberg/view/ViewVersionParser.java b/core/src/main/java/org/apache/iceberg/view/ViewVersionParser.java index 06ee3b2648d2..69208ce34062 100644 --- a/core/src/main/java/org/apache/iceberg/view/ViewVersionParser.java +++ b/core/src/main/java/org/apache/iceberg/view/ViewVersionParser.java @@ -96,8 +96,7 @@ public static ViewVersion fromJson(JsonNode node) { String defaultCatalog = JsonUtil.getStringOrNull(DEFAULT_CATALOG, node); - Namespace defaultNamespace = - Namespace.of(JsonUtil.getStringArray(JsonUtil.get(DEFAULT_NAMESPACE, node))); + Namespace defaultNamespace = Namespace.of(JsonUtil.getStringArray(DEFAULT_NAMESPACE, node)); return ImmutableViewVersion.builder() .versionId(versionId) diff --git a/core/src/test/java/org/apache/iceberg/util/TestJsonUtil.java b/core/src/test/java/org/apache/iceberg/util/TestJsonUtil.java index 91cd96e9088f..27cf6fb2994e 100644 --- a/core/src/test/java/org/apache/iceberg/util/TestJsonUtil.java +++ b/core/src/test/java/org/apache/iceberg/util/TestJsonUtil.java @@ -430,6 +430,53 @@ public void getLongSetOrNull() throws JsonProcessingException { .containsExactlyElementsOf(Arrays.asList(23L, 45L)); } + @Test + public void getStringArray() throws JsonProcessingException { + assertThatThrownBy(() -> JsonUtil.getStringArray(JsonUtil.mapper().readTree("null"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Cannot parse string array from non-array: null"); + + assertThatThrownBy(() -> JsonUtil.getStringArray(JsonUtil.mapper().readTree("23"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Cannot parse string array from non-array: 23"); + + assertThatThrownBy(() -> JsonUtil.getStringArray(JsonUtil.mapper().readTree("[\"23\", 45]"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Cannot parse string from non-text value: 45"); + + assertThat(JsonUtil.getStringArray(JsonUtil.mapper().readTree("[\"23\", \"45\"]"))) + .containsExactly("23", "45"); + + assertThat(JsonUtil.getStringArray(JsonUtil.mapper().readTree("[]"))).isEmpty(); + } + + @Test + public void getStringArrayWithProperty() throws JsonProcessingException { + assertThatThrownBy(() -> JsonUtil.getStringArray("items", JsonUtil.mapper().readTree("{}"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Cannot parse missing list: items"); + + assertThatThrownBy( + () -> JsonUtil.getStringArray("items", JsonUtil.mapper().readTree("{\"items\": null}"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Cannot parse JSON array from non-array value: items: null"); + + assertThatThrownBy( + () -> + JsonUtil.getStringArray( + "items", JsonUtil.mapper().readTree("{\"items\": [\"23\", 45]}"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Cannot parse string from non-text value in items: 45"); + + assertThat( + JsonUtil.getStringArray( + "items", JsonUtil.mapper().readTree("{\"items\": [\"23\", \"45\"]}"))) + .containsExactly("23", "45"); + + assertThat(JsonUtil.getStringArray("items", JsonUtil.mapper().readTree("{\"items\": []}"))) + .isEmpty(); + } + @Test public void getStringList() throws JsonProcessingException { assertThatThrownBy(() -> JsonUtil.getStringList("items", JsonUtil.mapper().readTree("{}"))) diff --git a/core/src/test/java/org/apache/iceberg/view/TestViewVersionParser.java b/core/src/test/java/org/apache/iceberg/view/TestViewVersionParser.java index a68b99a6797b..a46e63401632 100644 --- a/core/src/test/java/org/apache/iceberg/view/TestViewVersionParser.java +++ b/core/src/test/java/org/apache/iceberg/view/TestViewVersionParser.java @@ -127,7 +127,7 @@ public void missingDefaultCatalog() { "{\"version-id\":1,\"timestamp-ms\":12345,\"schema-id\":1," + "\"summary\":{\"operation\":\"create\"},\"representations\":[]}")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Cannot parse missing field: default-namespace"); + .hasMessage("Cannot parse missing list: default-namespace"); } @Test