From 6357c09dffdd1e128d2ca91fd3f125435a4cb685 Mon Sep 17 00:00:00 2001 From: Nikolai Amelichev Date: Fri, 26 Jan 2024 16:46:23 +0100 Subject: [PATCH] `yoj-json-jackson-v2`: Add JsonConverter implementation using Jackson --- bom/pom.xml | 5 + json-jackson-v2/pom.xml | 49 +++++++ .../db/json/JacksonJsonConverter.java | 137 ++++++++++++++++++ pom.xml | 1 + repository-inmemory/pom.xml | 5 + .../test/inmemory/TestInMemoryRepository.java | 5 +- .../test/sample/TestJsonConverter.java | 96 ------------ repository-ydb-v1/pom.xml | 5 + .../yoj/repository/ydb/TestYdbRepository.java | 5 +- .../ydb/yoj/repository/ydb/YqlTypeTest.java | 5 +- .../ydb/yql/YqlTypeAllTypesTest.java | 5 +- repository-ydb-v2/pom.xml | 5 + .../yoj/repository/ydb/TestYdbRepository.java | 5 +- .../ydb/yoj/repository/ydb/YqlTypeTest.java | 5 +- .../ydb/yql/YqlTypeAllTypesTest.java | 5 +- .../repository/db/common/JsonConverter.java | 45 +++++- 16 files changed, 267 insertions(+), 116 deletions(-) create mode 100644 json-jackson-v2/pom.xml create mode 100644 json-jackson-v2/src/main/java/tech/ydb/yoj/repository/db/json/JacksonJsonConverter.java delete mode 100644 repository-test/src/main/java/tech/ydb/yoj/repository/test/sample/TestJsonConverter.java diff --git a/bom/pom.xml b/bom/pom.xml index 17ca8373..6f5f441a 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -137,6 +137,11 @@ yoj-repository-ydb-v2 ${project.version} + + tech.ydb.yoj + yoj-json-jackson-v2 + ${project.version} + tech.ydb.yoj yoj-util diff --git a/json-jackson-v2/pom.xml b/json-jackson-v2/pom.xml new file mode 100644 index 00000000..8806efdb --- /dev/null +++ b/json-jackson-v2/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + yoj-json-jackson-v2 + jar + + + tech.ydb.yoj + yoj-parent + 1.1.0-SNAPSHOT + ../pom.xml + + + YOJ - JSON with Jackson 2.x + + Adds JSON support to YOJ (JsonConverter implementation) using Jackson 2.x as the underlying JSON library. + + + + + tech.ydb.yoj + yoj-repository + + + + javax.annotation + javax.annotation-api + + + com.google.guava + guava + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + diff --git a/json-jackson-v2/src/main/java/tech/ydb/yoj/repository/db/json/JacksonJsonConverter.java b/json-jackson-v2/src/main/java/tech/ydb/yoj/repository/db/json/JacksonJsonConverter.java new file mode 100644 index 00000000..59266796 --- /dev/null +++ b/json-jackson-v2/src/main/java/tech/ydb/yoj/repository/db/json/JacksonJsonConverter.java @@ -0,0 +1,137 @@ +package tech.ydb.yoj.repository.db.json; + +import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import tech.ydb.yoj.repository.db.common.JsonConverter; +import tech.ydb.yoj.repository.db.exception.ConversionException; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.function.UnaryOperator; + +/** + * {@link JsonConverter YOJ JSON Converter} implementation using Jackson as the underlying JSON library. + * Use it to support JSON-valued fields ({@link tech.ydb.yoj.databind.schema.Column @Column(flatten=false)} composite + * objects and dynamic fields with type of interface/abstract class, e.g. {@link java.util.List}): + *
+ *
+ * CommonConverters.defineJsonConverter(JacksonJsonConverter.getDefault());
+ * 
+ *
+ *

Note that the {@code CommonConverters.defineJsonConverter()} configuration API is unstable and subject to + * change (and potential deprecation for removal.) + * + *

+ * You can obtain an instance of {@link JacksonJsonConverter} in a number of ways: + *

+ */ +@RequiredArgsConstructor +public final class JacksonJsonConverter implements JsonConverter { + private static final JsonConverter instance = new JacksonJsonConverter(createDefaultObjectMapper()); + + private final ObjectMapper mapper; + + public JacksonJsonConverter(UnaryOperator mapperBuilder) { + this(mapperBuilder.apply(createDefaultObjectMapper())); + } + + /** + * @return {@code JsonConverter} with reasonable defaults, using Jackson for JSON serialization and deserialization + */ + public static JsonConverter getDefault() { + return instance; + } + + @Override + public String toJson(@NonNull Type type, @Nullable Object o) throws ConversionException { + try { + return mapper.writerFor(mapper.getTypeFactory().constructType(type)).writeValueAsString(o); + } catch (IOException e) { + throw new ConversionException("Could not serialize an object of type `" + type + "` to JSON", e); + } + } + + @Override + public T fromJson(@NonNull Type type, @NonNull String content) throws ConversionException { + try { + return mapper.readerFor(mapper.getTypeFactory().constructType(type)).readValue(content); + } catch (IOException e) { + throw new ConversionException("Could not deserialize an object of type `" + type + "` from JSON", e); + } + } + + @Override + @SuppressWarnings("unchecked") + public T fromObject(@NonNull Type type, @Nullable Object content) throws ConversionException { + try { + JavaType jacksonType = mapper.getTypeFactory().constructType(type); + return content != null + ? mapper.convertValue(content, jacksonType) + : (T) (jacksonType.isCollectionLikeType() ? List.of() : Map.of()); + } catch (Exception e) { + throw new ConversionException("Could not convert an object to type `" + type + "`", e); + } + } + + public String toString() { + return "JacksonJsonConverter"; + } + + private static ObjectMapper createDefaultObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.setTimeZone(TimeZone.getDefault()); + mapper.registerModule(new Jdk8Module()); + mapper.registerModule(new JavaTimeModule()); + mapper.registerModule(new SimpleModule() + .addAbstractTypeMapping(Set.class, LinkedHashSet.class) + .addAbstractTypeMapping(Map.class, LinkedHashMap.class) + .addAbstractTypeMapping(List.class, ArrayList.class) + ); + mapper.setSerializationInclusion(Include.NON_NULL); + mapper.configure(SerializationFeature.INDENT_OUTPUT, false); + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false); + mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, false); + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker() + .withFieldVisibility(Visibility.ANY) + .withGetterVisibility(Visibility.NONE) + .withIsGetterVisibility(Visibility.NONE) + .withSetterVisibility(Visibility.NONE) + ); + return mapper; + } +} diff --git a/pom.xml b/pom.xml index df497d7f..28b08c9b 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ bom databind + json-jackson-v2 repository repository-test repository-inmemory diff --git a/repository-inmemory/pom.xml b/repository-inmemory/pom.xml index 82b37c27..53341477 100644 --- a/repository-inmemory/pom.xml +++ b/repository-inmemory/pom.xml @@ -45,6 +45,11 @@ yoj-repository-test test
+ + tech.ydb.yoj + yoj-json-jackson-v2 + test + diff --git a/repository-inmemory/src/test/java/tech/ydb/yoj/repository/test/inmemory/TestInMemoryRepository.java b/repository-inmemory/src/test/java/tech/ydb/yoj/repository/test/inmemory/TestInMemoryRepository.java index 540bdab5..7e118c1f 100644 --- a/repository-inmemory/src/test/java/tech/ydb/yoj/repository/test/inmemory/TestInMemoryRepository.java +++ b/repository-inmemory/src/test/java/tech/ydb/yoj/repository/test/inmemory/TestInMemoryRepository.java @@ -5,11 +5,12 @@ import tech.ydb.yoj.repository.db.Table; import tech.ydb.yoj.repository.db.TableQueryBuilder; import tech.ydb.yoj.repository.db.TxOptions; +import tech.ydb.yoj.repository.db.common.CommonConverters; +import tech.ydb.yoj.repository.db.json.JacksonJsonConverter; import tech.ydb.yoj.repository.test.sample.TestEntityOperations; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.BubbleTable; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.ComplexTable; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.IndexedTable; -import tech.ydb.yoj.repository.test.sample.TestJsonConverter; import tech.ydb.yoj.repository.test.sample.model.Bubble; import tech.ydb.yoj.repository.test.sample.model.Complex; import tech.ydb.yoj.repository.test.sample.model.EntityWithValidation; @@ -27,7 +28,7 @@ public class TestInMemoryRepository extends InMemoryRepository { static { - TestJsonConverter.register(); + CommonConverters.defineJsonConverter(JacksonJsonConverter.getDefault()); } @Override diff --git a/repository-test/src/main/java/tech/ydb/yoj/repository/test/sample/TestJsonConverter.java b/repository-test/src/main/java/tech/ydb/yoj/repository/test/sample/TestJsonConverter.java deleted file mode 100644 index 2fbe7156..00000000 --- a/repository-test/src/main/java/tech/ydb/yoj/repository/test/sample/TestJsonConverter.java +++ /dev/null @@ -1,96 +0,0 @@ -package tech.ydb.yoj.repository.test.sample; - -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import lombok.SneakyThrows; -import tech.ydb.yoj.repository.db.common.CommonConverters; -import tech.ydb.yoj.repository.db.common.JsonConverter; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; - -/** - * Test {@link JsonConverter} implementation that is sufficiently advanced to serialize and deserialize test data - * used by YDB ORM tests. - */ -public final class TestJsonConverter implements JsonConverter { - private static final JsonConverter instance = new TestJsonConverter(); - - private static final ObjectMapper mapper = createObjectMapper(); - - private TestJsonConverter() { - } - - private static ObjectMapper createObjectMapper() { - ObjectMapper mapper = new ObjectMapper(); - mapper.setTimeZone(TimeZone.getDefault()); - mapper.registerModule(new Jdk8Module()); - mapper.registerModule(new JavaTimeModule()); - mapper.registerModule(new SimpleModule() - .addAbstractTypeMapping(Set.class, LinkedHashSet.class) - .addAbstractTypeMapping(Map.class, LinkedHashMap.class) - .addAbstractTypeMapping(List.class, ArrayList.class) - ); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.configure(SerializationFeature.INDENT_OUTPUT, false); - mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); - mapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false); - mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true); - mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true); - mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker() - .withFieldVisibility(JsonAutoDetect.Visibility.ANY) - .withGetterVisibility(JsonAutoDetect.Visibility.NONE) - .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE) - .withSetterVisibility(JsonAutoDetect.Visibility.NONE) - ); - return mapper; - } - - @Override - @SneakyThrows - public String toJson(Type type, Object o) { - return mapper.writerFor(mapper.getTypeFactory().constructType(type)).writeValueAsString(o); - } - - @Override - @SneakyThrows - public T fromJson(Type type, String content) { - return mapper.readerFor(mapper.getTypeFactory().constructType(type)).readValue(content); - } - - @Override - @SneakyThrows - public Object fromObject(Type type, Object content) { - JavaType jacksonType = mapper.getTypeFactory().constructType(type); - if (content != null) { - return mapper.convertValue(content, jacksonType); - } else { - return jacksonType.isCollectionLikeType() ? List.of() : Map.of(); - } - } - - @Override - public String toString() { - return "TestJsonConverter.instance"; - } - - public static void register() { - CommonConverters.defineJsonConverter(TestJsonConverter.instance); - } -} diff --git a/repository-ydb-v1/pom.xml b/repository-ydb-v1/pom.xml index 03b53b92..3c66e9aa 100644 --- a/repository-ydb-v1/pom.xml +++ b/repository-ydb-v1/pom.xml @@ -76,6 +76,11 @@ yoj-repository-test test + + tech.ydb.yoj + yoj-json-jackson-v2 + test + org.mockito mockito-core diff --git a/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java b/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java index 01ea00b1..b1ff0c44 100644 --- a/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java +++ b/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java @@ -7,13 +7,14 @@ import tech.ydb.yoj.repository.db.Table; import tech.ydb.yoj.repository.db.TableQueryBuilder; import tech.ydb.yoj.repository.db.TxOptions; +import tech.ydb.yoj.repository.db.common.CommonConverters; +import tech.ydb.yoj.repository.db.json.JacksonJsonConverter; import tech.ydb.yoj.repository.db.statement.Changeset; import tech.ydb.yoj.repository.test.sample.TestEntityOperations; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.BubbleTable; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.ComplexTable; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.IndexedTable; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.Supabubble2Table; -import tech.ydb.yoj.repository.test.sample.TestJsonConverter; import tech.ydb.yoj.repository.test.sample.model.Bubble; import tech.ydb.yoj.repository.test.sample.model.Complex; import tech.ydb.yoj.repository.test.sample.model.EntityWithValidation; @@ -34,7 +35,7 @@ public class TestYdbRepository extends YdbRepository { static { - TestJsonConverter.register(); + CommonConverters.defineJsonConverter(JacksonJsonConverter.getDefault()); } @Override diff --git a/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/YqlTypeTest.java b/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/YqlTypeTest.java index 09cea173..bae302a9 100644 --- a/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/YqlTypeTest.java +++ b/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/YqlTypeTest.java @@ -13,8 +13,9 @@ import tech.ydb.yoj.databind.schema.ObjectSchema; import tech.ydb.yoj.databind.schema.Schema; import tech.ydb.yoj.repository.db.Entity; +import tech.ydb.yoj.repository.db.common.CommonConverters; import tech.ydb.yoj.repository.db.exception.ConversionException; -import tech.ydb.yoj.repository.test.sample.TestJsonConverter; +import tech.ydb.yoj.repository.db.json.JacksonJsonConverter; import tech.ydb.yoj.repository.test.sample.model.NonDeserializableObject; import tech.ydb.yoj.repository.ydb.yql.YqlPrimitiveType; import tech.ydb.yoj.repository.ydb.yql.YqlType; @@ -30,7 +31,7 @@ public class YqlTypeTest { static { FieldValueType.registerStringValueType(UUID.class); - TestJsonConverter.register(); + CommonConverters.defineJsonConverter(JacksonJsonConverter.getDefault()); } @Test diff --git a/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/yql/YqlTypeAllTypesTest.java b/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/yql/YqlTypeAllTypesTest.java index 61058d98..a7779191 100644 --- a/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/yql/YqlTypeAllTypesTest.java +++ b/repository-ydb-v1/src/test/java/tech/ydb/yoj/repository/ydb/yql/YqlTypeAllTypesTest.java @@ -14,7 +14,8 @@ import tech.ydb.yoj.databind.schema.Column; import tech.ydb.yoj.databind.schema.Schema; import tech.ydb.yoj.repository.DbTypeQualifier; -import tech.ydb.yoj.repository.test.sample.TestJsonConverter; +import tech.ydb.yoj.repository.db.common.CommonConverters; +import tech.ydb.yoj.repository.db.json.JacksonJsonConverter; import tech.ydb.yoj.repository.ydb.DbType; import java.lang.reflect.Type; @@ -32,7 +33,7 @@ public class YqlTypeAllTypesTest { static { FieldValueType.registerStringValueType(UUID.class); - TestJsonConverter.register(); + CommonConverters.defineJsonConverter(JacksonJsonConverter.getDefault()); } private static final Map OBJECT_VALUE = Map.of("string", "Unnamed", "number", 11, "boolean", true); diff --git a/repository-ydb-v2/pom.xml b/repository-ydb-v2/pom.xml index 1a1e343c..0ed2c506 100644 --- a/repository-ydb-v2/pom.xml +++ b/repository-ydb-v2/pom.xml @@ -106,6 +106,11 @@ yoj-repository-test test + + tech.ydb.yoj + yoj-json-jackson-v2 + test + org.mockito diff --git a/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java b/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java index 05149f3e..7a386e7b 100644 --- a/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java +++ b/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java @@ -7,12 +7,13 @@ import tech.ydb.yoj.repository.db.Table; import tech.ydb.yoj.repository.db.TableQueryBuilder; import tech.ydb.yoj.repository.db.TxOptions; +import tech.ydb.yoj.repository.db.common.CommonConverters; +import tech.ydb.yoj.repository.db.json.JacksonJsonConverter; import tech.ydb.yoj.repository.db.statement.Changeset; import tech.ydb.yoj.repository.test.sample.TestEntityOperations; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.BubbleTable; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.ComplexTable; import tech.ydb.yoj.repository.test.sample.TestEntityOperations.IndexedTable; -import tech.ydb.yoj.repository.test.sample.TestJsonConverter; import tech.ydb.yoj.repository.test.sample.model.Bubble; import tech.ydb.yoj.repository.test.sample.model.Complex; import tech.ydb.yoj.repository.test.sample.model.EntityWithValidation; @@ -34,7 +35,7 @@ public class TestYdbRepository extends YdbRepository { static { - TestJsonConverter.register(); + CommonConverters.defineJsonConverter(JacksonJsonConverter.getDefault()); } @Override diff --git a/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/YqlTypeTest.java b/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/YqlTypeTest.java index 1a571061..d89ae35d 100644 --- a/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/YqlTypeTest.java +++ b/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/YqlTypeTest.java @@ -12,8 +12,9 @@ import tech.ydb.yoj.databind.schema.ObjectSchema; import tech.ydb.yoj.databind.schema.Schema; import tech.ydb.yoj.repository.db.Entity; +import tech.ydb.yoj.repository.db.common.CommonConverters; import tech.ydb.yoj.repository.db.exception.ConversionException; -import tech.ydb.yoj.repository.test.sample.TestJsonConverter; +import tech.ydb.yoj.repository.db.json.JacksonJsonConverter; import tech.ydb.yoj.repository.test.sample.model.NonDeserializableObject; import tech.ydb.yoj.repository.ydb.yql.YqlPrimitiveType; import tech.ydb.yoj.repository.ydb.yql.YqlType; @@ -29,7 +30,7 @@ public class YqlTypeTest { static { FieldValueType.registerStringValueType(UUID.class); - TestJsonConverter.register(); + CommonConverters.defineJsonConverter(JacksonJsonConverter.getDefault()); } @Test diff --git a/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/yql/YqlTypeAllTypesTest.java b/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/yql/YqlTypeAllTypesTest.java index 88203750..d7708ebe 100644 --- a/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/yql/YqlTypeAllTypesTest.java +++ b/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/yql/YqlTypeAllTypesTest.java @@ -14,7 +14,8 @@ import tech.ydb.yoj.databind.schema.Column; import tech.ydb.yoj.databind.schema.Schema; import tech.ydb.yoj.repository.DbTypeQualifier; -import tech.ydb.yoj.repository.test.sample.TestJsonConverter; +import tech.ydb.yoj.repository.db.common.CommonConverters; +import tech.ydb.yoj.repository.db.json.JacksonJsonConverter; import tech.ydb.yoj.repository.ydb.DbType; import java.lang.reflect.Type; @@ -32,7 +33,7 @@ public class YqlTypeAllTypesTest { static { FieldValueType.registerStringValueType(UUID.class); - TestJsonConverter.register(); + CommonConverters.defineJsonConverter(JacksonJsonConverter.getDefault()); } private static final Map OBJECT_VALUE = Map.of("string", "Unnamed", "number", 11, "boolean", true); diff --git a/repository/src/main/java/tech/ydb/yoj/repository/db/common/JsonConverter.java b/repository/src/main/java/tech/ydb/yoj/repository/db/common/JsonConverter.java index 48e9d664..7c51d959 100644 --- a/repository/src/main/java/tech/ydb/yoj/repository/db/common/JsonConverter.java +++ b/repository/src/main/java/tech/ydb/yoj/repository/db/common/JsonConverter.java @@ -1,27 +1,60 @@ package tech.ydb.yoj.repository.db.common; +import lombok.NonNull; +import tech.ydb.yoj.repository.db.exception.ConversionException; + +import javax.annotation.Nullable; import java.lang.reflect.Type; public interface JsonConverter { - String toJson(Type type, Object o); + /** + * Serializes an object of the specified type to its JSON representation. + * + * @param type object type + * @param o object to serialize (can be {@code null}) + * @return JSON representation of the serialized object, as a String + * @throws ConversionException could not serialize + * @throws UnsupportedOperationException serialization not supported + */ + String toJson(@NonNull Type type, @Nullable Object o) + throws ConversionException, UnsupportedOperationException; - T fromJson(Type type, String content); + /** + * Deserializes an object of the specified type from its JSON representation. + * + * @param type object type + * @param content JSON to deserialize, as a String + * @throws ConversionException could not deserialize + * @throws UnsupportedOperationException deserialization not supported + */ + T fromJson(@NonNull Type type, @NonNull String content) + throws ConversionException, UnsupportedOperationException; - T fromObject(Type type, Object content); + /** + * Converts an object to a different type using JSON mapping logic as an intermediary. + * + * @param type type to convert the object to + * @param content object to convert (can be {@code null}) + * @return converted object + * @throws ConversionException could not convert + * @throws UnsupportedOperationException conversion not supported + */ + T fromObject(@NonNull Type type, @Nullable Object content) + throws ConversionException, UnsupportedOperationException; JsonConverter NONE = new JsonConverter() { @Override - public String toJson(Type type, Object o) { + public String toJson(@NonNull Type type, @Nullable Object o) { throw new UnsupportedOperationException("Define appropriate JSON converter!"); } @Override - public T fromJson(Type type, String content) { + public T fromJson(@NonNull Type type, @NonNull String content) { throw new UnsupportedOperationException("Define appropriate JSON converter!"); } @Override - public T fromObject(Type type, Object content) { + public T fromObject(@NonNull Type type, @Nullable Object content) { throw new UnsupportedOperationException("Define appropriate JSON converter!"); }