aboutsummaryrefslogtreecommitdiffstats
path: root/vespajlib
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@vespa.ai>2024-02-27 09:49:15 +0100
committerBjørn Christian Seime <bjorncs@vespa.ai>2024-02-27 09:49:15 +0100
commit3677c04f0a48634c7183db0e1f9330cb13f3be4e (patch)
tree2c5f3459deed77025d086cb5778a2f96c929f14a /vespajlib
parentb28e47e2045549de4ce8f9b2779f56d07f5703bd (diff)
Various improvements to `Json`
Diffstat (limited to 'vespajlib')
-rw-r--r--vespajlib/src/main/java/ai/vespa/json/Json.java31
-rw-r--r--vespajlib/src/test/java/ai/vespa/json/JsonTest.java7
2 files changed, 36 insertions, 2 deletions
diff --git a/vespajlib/src/main/java/ai/vespa/json/Json.java b/vespajlib/src/main/java/ai/vespa/json/Json.java
index b88c804c728..da7aae06e8d 100644
--- a/vespajlib/src/main/java/ai/vespa/json/Json.java
+++ b/vespajlib/src/main/java/ai/vespa/json/Json.java
@@ -8,6 +8,8 @@ import com.yahoo.slime.SlimeUtils;
import com.yahoo.slime.Type;
import java.math.BigDecimal;
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
@@ -90,6 +92,20 @@ public class Json implements Iterable<Json> {
return asBool();
}
+ public Optional<Instant> asOptionalInstant() { return isMissing() ? Optional.empty() : Optional.of(asInstant()); }
+ public Instant asInstant() {
+ requireType(Type.STRING);
+ try {
+ return Instant.parse(asString());
+ } catch (DateTimeParseException e) {
+ throw new InvalidJsonException("Expected JSON member '%s' to be a valid timestamp: %s".formatted(path, e.getMessage()));
+ }
+ }
+ public Instant asInstant(Instant defaultValue) {
+ if (isMissing()) return defaultValue;
+ return asInstant();
+ }
+
public List<Json> toList() {
var list = new ArrayList<Json>(length());
forEachEntry(json -> list.add(json));
@@ -184,7 +200,14 @@ public class Json implements Iterable<Json> {
public static Builder.Array newArray() { return new Builder.Array(new Slime().setArray()); }
public static Builder.Object newObject() { return new Builder.Object(new Slime().setObject()); }
- public static Builder.Object existingObject(Cursor cursor) { return new Builder.Object(cursor); }
+ public static Builder.Object existingSlimeObjectCursor(Cursor cursor) {
+ if (cursor.type() != Type.OBJECT) throw new InvalidJsonException("Input is not an object");
+ return new Builder.Object(cursor);
+ }
+ public static Builder.Array existingSlimeArrayCursor(Cursor cursor) {
+ if (cursor.type() != Type.ARRAY) throw new InvalidJsonException("Input is not an array");
+ return new Builder.Array(cursor);
+ }
private Builder(Cursor cursor) { this.cursor = cursor; }
@@ -200,6 +223,8 @@ public class Json implements Iterable<Json> {
public Builder.Array add(Json json) {
SlimeUtils.addValue(json.inspector, cursor.addObject()); return this;
}
+ public Builder.Array add(Json.Builder builder) { return add(builder.build()); }
+
/** Note: does not return {@code this}! */
public Builder.Array addArray() { return new Array(cursor.addArray()); }
/** Note: does not return {@code this}! */
@@ -223,6 +248,9 @@ public class Json implements Iterable<Json> {
public Builder.Object set(String field, Json json) {
SlimeUtils.setObjectEntry(json.inspector, field, cursor); return this;
}
+ public Builder.Object set(String field, Json.Builder json) {
+ SlimeUtils.setObjectEntry(json.build().inspector, field, cursor); return this;
+ }
/** Note: does not return {@code this}! */
public Builder.Array setArray(String field) { return new Array(cursor.setArray(field)); }
/** Note: does not return {@code this}! */
@@ -233,6 +261,7 @@ public class Json implements Iterable<Json> {
public Builder.Object set(String field, double value) { cursor.setDouble(field, value); return this; }
public Builder.Object set(String field, boolean value) { cursor.setBool(field, value); return this; }
public Builder.Object set(String field, BigDecimal value) { cursor.setString(field, value.toPlainString()); return this; }
+ public Builder.Object set(String field, Instant timestamp) { cursor.setString(field, timestamp.toString()); return this; }
}
public Cursor slimeCursor() { return cursor; }
diff --git a/vespajlib/src/test/java/ai/vespa/json/JsonTest.java b/vespajlib/src/test/java/ai/vespa/json/JsonTest.java
index 293e99227a7..51b64637fd8 100644
--- a/vespajlib/src/test/java/ai/vespa/json/JsonTest.java
+++ b/vespajlib/src/test/java/ai/vespa/json/JsonTest.java
@@ -23,7 +23,8 @@ class JsonTest {
"array": [1, 2, 3],
"quux": {
"corge": "grault"
- }
+ },
+ "timestamp": "2021-06-01T12:00:00Z"
}
""";
var json = Json.of(text);
@@ -37,6 +38,7 @@ class JsonTest {
assertEquals(8.25D, json.f("floaty").asDouble());
assertEquals(8L, json.f("floaty").asLong());
assertTrue(json.f("bool").asBool());
+ assertEquals("2021-06-01T12:00:00Z", json.f("timestamp").asInstant().toString());
// Array member
assertEquals(3, json.f("array").length());
@@ -78,6 +80,9 @@ class JsonTest {
exception = assertThrows(InvalidJsonException.class, () -> json.f("string").asLong());
assertEquals("Expected JSON member 'string' to be a 'integer' or 'float' but got 'string'", exception.getMessage());
+
+ exception = assertThrows(InvalidJsonException.class, () -> json.f("string").asInstant());
+ assertEquals("Expected JSON member 'string' to be a valid timestamp: Text 'bar' could not be parsed at index 0", exception.getMessage());
}
@Test