This is an automated email from the ASF dual-hosted git repository.
fokko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/master by this push:
new db7e09e54a Core: Improve collection handling in JsonUtil (#6051)
db7e09e54a is described below
commit db7e09e54ac7f4c48a5fa906c6e54b838e555ef7
Author: Eduard Tudenhöfner <[email protected]>
AuthorDate: Thu Nov 3 09:25:40 2022 +0100
Core: Improve collection handling in JsonUtil (#6051)
This aligns all collection methods to show the same error message and
behave the same with null/empty/invalid json values.
Additionally, this also adds the property name of the collection when
showing an error message
---
.../java/org/apache/iceberg/util/JsonUtil.java | 26 ++-
.../iceberg/metrics/TestScanReportParser.java | 4 +-
.../iceberg/puffin/TestFileMetadataParser.java | 2 +-
.../java/org/apache/iceberg/util/TestJsonUtil.java | 214 +++++++++++++++++++++
4 files changed, 238 insertions(+), 8 deletions(-)
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 5d39c0cea6..6990464e62 100644
--- a/core/src/main/java/org/apache/iceberg/util/JsonUtil.java
+++ b/core/src/main/java/org/apache/iceberg/util/JsonUtil.java
@@ -212,8 +212,7 @@ public class JsonUtil {
}
public static Set<String> getStringSet(String property, JsonNode node) {
- Preconditions.checkArgument(
- node.hasNonNull(property), "Cannot parse missing set: %s", property);
+ Preconditions.checkArgument(node.has(property), "Cannot parse missing set:
%s", property);
return ImmutableSet.<String>builder()
.addAll(new JsonStringArrayIterator(property, node))
@@ -231,6 +230,7 @@ public class JsonUtil {
}
public static List<Integer> getIntegerList(String property, JsonNode node) {
+ Preconditions.checkArgument(node.has(property), "Cannot parse missing
list: %s", property);
return ImmutableList.<Integer>builder()
.addAll(new JsonIntegerArrayIterator(property, node))
.build();
@@ -245,6 +245,7 @@ public class JsonUtil {
}
public static Set<Integer> getIntegerSet(String property, JsonNode node) {
+ Preconditions.checkArgument(node.has(property), "Cannot parse missing set:
%s", property);
return ImmutableSet.<Integer>builder()
.addAll(new JsonIntegerArrayIterator(property, node))
.build();
@@ -255,6 +256,11 @@ public class JsonUtil {
return null;
}
+ return getLongSet(property, node);
+ }
+
+ public static Set<Long> getLongSet(String property, JsonNode node) {
+ Preconditions.checkArgument(node.has(property), "Cannot parse missing set:
%s", property);
return ImmutableSet.<Long>builder().addAll(new
JsonLongArrayIterator(property, node)).build();
}
@@ -304,9 +310,11 @@ public class JsonUtil {
}
static class JsonStringArrayIterator extends JsonArrayIterator<String> {
+ private final String property;
JsonStringArrayIterator(String property, JsonNode node) {
super(property, node);
+ this.property = property;
}
@Override
@@ -317,14 +325,19 @@ public class JsonUtil {
@Override
void validate(JsonNode element) {
Preconditions.checkArgument(
- element.isTextual(), "Cannot parse string from non-text value: %s",
element);
+ element.isTextual(),
+ "Cannot parse string from non-text value in %s: %s",
+ property,
+ element);
}
}
static class JsonIntegerArrayIterator extends JsonArrayIterator<Integer> {
+ private final String property;
JsonIntegerArrayIterator(String property, JsonNode node) {
super(property, node);
+ this.property = property;
}
@Override
@@ -335,14 +348,16 @@ public class JsonUtil {
@Override
void validate(JsonNode element) {
Preconditions.checkArgument(
- element.isInt(), "Cannot parse integer from non-int value: %s",
element);
+ element.isInt(), "Cannot parse integer from non-int value in %s:
%s", property, element);
}
}
static class JsonLongArrayIterator extends JsonArrayIterator<Long> {
+ private final String property;
JsonLongArrayIterator(String property, JsonNode node) {
super(property, node);
+ this.property = property;
}
@Override
@@ -354,7 +369,8 @@ public class JsonUtil {
void validate(JsonNode element) {
Preconditions.checkArgument(
element.isIntegralNumber() && element.canConvertToLong(),
- "Cannot parse long from non-long value: %s",
+ "Cannot parse long from non-long value in %s: %s",
+ property,
element);
}
}
diff --git
a/core/src/test/java/org/apache/iceberg/metrics/TestScanReportParser.java
b/core/src/test/java/org/apache/iceberg/metrics/TestScanReportParser.java
index 9bdb6c9f49..13130c9cfc 100644
--- a/core/src/test/java/org/apache/iceberg/metrics/TestScanReportParser.java
+++ b/core/src/test/java/org/apache/iceberg/metrics/TestScanReportParser.java
@@ -162,14 +162,14 @@ public class TestScanReportParser {
ScanReportParser.fromJson(
"{\"table-name\":\"roundTripTableName\",\"snapshot-id\":23,\"filter\":true,\"schema-id\":23,\"projected-field-ids\":
[\"1\"],\"metrics\":{}}"))
.isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Cannot parse integer from non-int value: \"1\"");
+ .hasMessage("Cannot parse integer from non-int value in
projected-field-ids: \"1\"");
Assertions.assertThatThrownBy(
() ->
ScanReportParser.fromJson(
"{\"table-name\":\"roundTripTableName\",\"snapshot-id\":23,\"filter\":true,\"schema-id\":23,\"projected-field-ids\":
[1],\"projected-field-names\": [1],\"metrics\":{}}"))
.isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Cannot parse string from non-text value: 1");
+ .hasMessage("Cannot parse string from non-text value in
projected-field-names: 1");
}
@Test
diff --git
a/core/src/test/java/org/apache/iceberg/puffin/TestFileMetadataParser.java
b/core/src/test/java/org/apache/iceberg/puffin/TestFileMetadataParser.java
index 81192be627..c105283753 100644
--- a/core/src/test/java/org/apache/iceberg/puffin/TestFileMetadataParser.java
+++ b/core/src/test/java/org/apache/iceberg/puffin/TestFileMetadataParser.java
@@ -173,7 +173,7 @@ public class TestFileMetadataParser {
+ " } ]\n"
+ "}"))
.isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Cannot parse integer from non-int value: 2147483648");
+ .hasMessage("Cannot parse integer from non-int value in fields:
2147483648");
}
private void testJsonSerialization(FileMetadata fileMetadata, String json) {
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 6fc6c6a79b..7b3f3be8de 100644
--- a/core/src/test/java/org/apache/iceberg/util/TestJsonUtil.java
+++ b/core/src/test/java/org/apache/iceberg/util/TestJsonUtil.java
@@ -19,6 +19,8 @@
package org.apache.iceberg.util;
import com.fasterxml.jackson.core.JsonProcessingException;
+import java.util.Arrays;
+import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
import org.assertj.core.api.Assertions;
import org.junit.Test;
@@ -189,4 +191,216 @@ public class TestJsonUtil {
Assertions.assertThat(JsonUtil.getBool("x",
JsonUtil.mapper().readTree("{\"x\": false}")))
.isFalse();
}
+
+ @Test
+ public void getIntegerList() throws JsonProcessingException {
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getIntegerList("items",
JsonUtil.mapper().readTree("{}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse missing list: items");
+
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getIntegerList("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse from non-array value: items: null");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getIntegerList(
+ "items", JsonUtil.mapper().readTree("{\"items\": [13,
\"23\"]}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse integer from non-int value in items:
\"23\"");
+
+ Assertions.assertThat(
+ JsonUtil.getIntegerList("items",
JsonUtil.mapper().readTree("{\"items\": [23, 45]}")))
+ .isEqualTo(Arrays.asList(23, 45));
+ }
+
+ @Test
+ public void getIntegerSet() throws JsonProcessingException {
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getIntegerSet("items",
JsonUtil.mapper().readTree("{}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse missing set: items");
+
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getIntegerSet("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse from non-array value: items: null");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getIntegerSet(
+ "items", JsonUtil.mapper().readTree("{\"items\": [13,
\"23\"]}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse integer from non-int value in items:
\"23\"");
+
+ Assertions.assertThat(
+ JsonUtil.getIntegerSet("items",
JsonUtil.mapper().readTree("{\"items\": [23, 45]}")))
+ .containsExactlyElementsOf(Arrays.asList(23, 45));
+ }
+
+ @Test
+ public void getIntegerSetOrNull() throws JsonProcessingException {
+ Assertions.assertThat(JsonUtil.getIntegerSetOrNull("items",
JsonUtil.mapper().readTree("{}")))
+ .isNull();
+
+ Assertions.assertThat(
+ JsonUtil.getIntegerSetOrNull("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isNull();
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getIntegerSetOrNull(
+ "items", JsonUtil.mapper().readTree("{\"items\": [13,
\"23\"]}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse integer from non-int value in items:
\"23\"");
+
+ Assertions.assertThat(
+ JsonUtil.getIntegerSetOrNull(
+ "items", JsonUtil.mapper().readTree("{\"items\": [23, 45]}")))
+ .containsExactlyElementsOf(Arrays.asList(23, 45));
+ }
+
+ @Test
+ public void getLongSet() throws JsonProcessingException {
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getLongSet("items",
JsonUtil.mapper().readTree("{}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse missing set: items");
+
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getLongSet("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse from non-array value: items: null");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getLongSet(
+ "items", JsonUtil.mapper().readTree("{\"items\": [13,
\"23\"]}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse long from non-long value in items: \"23\"");
+
+ Assertions.assertThat(
+ JsonUtil.getLongSet("items",
JsonUtil.mapper().readTree("{\"items\": [23, 45]}")))
+ .containsExactlyElementsOf(Arrays.asList(23L, 45L));
+ }
+
+ @Test
+ public void getLongSetOrNull() throws JsonProcessingException {
+ Assertions.assertThat(JsonUtil.getLongSetOrNull("items",
JsonUtil.mapper().readTree("{}")))
+ .isNull();
+
+ Assertions.assertThat(
+ JsonUtil.getLongSetOrNull("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isNull();
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getLongSetOrNull(
+ "items", JsonUtil.mapper().readTree("{\"items\": [13,
\"23\"]}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse long from non-long value in items: \"23\"");
+
+ Assertions.assertThat(
+ JsonUtil.getLongSetOrNull("items",
JsonUtil.mapper().readTree("{\"items\": [23, 45]}")))
+ .containsExactlyElementsOf(Arrays.asList(23L, 45L));
+ }
+
+ @Test
+ public void getStringList() throws JsonProcessingException {
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getStringList("items",
JsonUtil.mapper().readTree("{}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse missing list: items");
+
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getStringList("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse from non-array value: items: null");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getStringList(
+ "items", JsonUtil.mapper().readTree("{\"items\": [\"23\",
45]}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse string from non-text value in items: 45");
+
+ Assertions.assertThat(
+ JsonUtil.getStringList(
+ "items", JsonUtil.mapper().readTree("{\"items\": [\"23\",
\"45\"]}")))
+ .containsExactlyElementsOf(Arrays.asList("23", "45"));
+ }
+
+ @Test
+ public void getStringListOrNull() throws JsonProcessingException {
+ Assertions.assertThat(JsonUtil.getStringListOrNull("items",
JsonUtil.mapper().readTree("{}")))
+ .isNull();
+
+ Assertions.assertThat(
+ JsonUtil.getStringListOrNull("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isNull();
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getStringListOrNull(
+ "items", JsonUtil.mapper().readTree("{\"items\": [\"23\",
45]}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse string from non-text value in items: 45");
+
+ Assertions.assertThat(
+ JsonUtil.getStringListOrNull(
+ "items", JsonUtil.mapper().readTree("{\"items\": [\"23\",
\"45\"]}")))
+ .containsExactlyElementsOf(Arrays.asList("23", "45"));
+ }
+
+ @Test
+ public void getStringSet() throws JsonProcessingException {
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getStringSet("items",
JsonUtil.mapper().readTree("{}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse missing set: items");
+
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getStringSet("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse from non-array value: items: null");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getStringSet(
+ "items", JsonUtil.mapper().readTree("{\"items\": [\"23\",
45]}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse string from non-text value in items: 45");
+
+ Assertions.assertThat(
+ JsonUtil.getStringSet(
+ "items", JsonUtil.mapper().readTree("{\"items\": [\"23\",
\"45\"]}")))
+ .containsExactlyElementsOf(Arrays.asList("23", "45"));
+ }
+
+ @Test
+ public void getStringMap() throws JsonProcessingException {
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getStringMap("items",
JsonUtil.mapper().readTree("{}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse missing map: items");
+
+ Assertions.assertThatThrownBy(
+ () -> JsonUtil.getStringMap("items",
JsonUtil.mapper().readTree("{\"items\": null}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse from non-object value: items: null");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ JsonUtil.getStringMap(
+ "items", JsonUtil.mapper().readTree("{\"items\":
{\"a\":\"23\", \"b\":45}}")))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot parse to a string value: b: 45");
+
+ Assertions.assertThat(
+ JsonUtil.getStringMap(
+ "items", JsonUtil.mapper().readTree("{\"items\":
{\"a\":\"23\", \"b\":\"45\"}}")))
+ .isEqualTo(ImmutableMap.of("a", "23", "b", "45"));
+ }
}