From 5c1b4780850d99af7a1b827f228c5cc99cedb476 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Sep 2022 21:39:36 +1200 Subject: [PATCH] Refactor extract ebean-json-node module - support for Jackson JsonNode (into separate module) --- composites/ebean/pom.xml | 6 ++ ebean-bom/pom.xml | 6 ++ ebean-core-type/pom.xml | 8 ++ .../io/ebean/core}/type/PostgresHelper.java | 17 +++- .../io/ebean/core/type/ScalarTypeSet.java | 28 +++++++ .../ebean/core/type/ScalarTypeSetFactory.java | 17 ++++ .../src/main/java/module-info.java | 1 + .../ebeaninternal/server/persist/Binder.java | 1 + .../server/type/DefaultTypeManager.java | 82 ++++--------------- .../server/type/ScalarTypeCidr.java | 1 + .../server/type/ScalarTypeInet.java | 1 + .../type/ScalarTypeInetAddressPostgres.java | 1 + .../server/type/ScalarTypeJsonList.java | 5 +- .../type/ScalarTypeJsonMapPostgres.java | 1 + .../server/type/ScalarTypeJsonSet.java | 5 +- .../server/type/ScalarTypeJsonString.java | 1 + .../server/type/TypeJsonManager.java | 1 + ebean-core/src/main/java/module-info.java | 1 + ebean-json-node/pom.xml | 52 ++++++++++++ .../ebean/jackson/jsonnode/JsonNodeSet.java | 51 ++++++++++++ .../jackson/jsonnode/JsonNodeTypeFactory.java | 31 +++++++ .../jackson/jsonnode}/ScalarTypeJsonNode.java | 11 +-- .../jsonnode}/ScalarTypeJsonNodePostgres.java | 3 +- .../src/main/java/module-info.java | 10 +++ .../io.ebean.core.type.ScalarTypeSetFactory | 1 + ebean-test/pom.xml | 7 ++ pom.xml | 1 + 27 files changed, 266 insertions(+), 84 deletions(-) rename {ebean-core/src/main/java/io/ebeaninternal/server => ebean-core-type/src/main/java/io/ebean/core}/type/PostgresHelper.java (51%) create mode 100644 ebean-core-type/src/main/java/io/ebean/core/type/ScalarTypeSet.java create mode 100644 ebean-core-type/src/main/java/io/ebean/core/type/ScalarTypeSetFactory.java create mode 100644 ebean-json-node/pom.xml create mode 100644 ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/JsonNodeSet.java create mode 100644 ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/JsonNodeTypeFactory.java rename {ebean-core/src/main/java/io/ebeaninternal/server/type => ebean-json-node/src/main/java/io/ebean/jackson/jsonnode}/ScalarTypeJsonNode.java (95%) rename {ebean-core/src/main/java/io/ebeaninternal/server/type => ebean-json-node/src/main/java/io/ebean/jackson/jsonnode}/ScalarTypeJsonNodePostgres.java (94%) create mode 100644 ebean-json-node/src/main/java/module-info.java create mode 100644 ebean-json-node/src/main/resources/META-INF/services/io.ebean.core.type.ScalarTypeSetFactory diff --git a/composites/ebean/pom.xml b/composites/ebean/pom.xml index 9bf3fe041..8c41257dc 100644 --- a/composites/ebean/pom.xml +++ b/composites/ebean/pom.xml @@ -31,6 +31,12 @@ 13.9.3-SNAPSHOT + + io.ebean + ebean-json-node + 13.9.3-SNAPSHOT + + io.ebean ebean-datasource diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index d8d18b0a8..6813c7840 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -116,6 +116,12 @@ 13.9.3-SNAPSHOT + + io.ebean + ebean-json-node + 13.9.3-SNAPSHOT + + io.ebean ebean-ddl-generator diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index f761398ee..5511e1088 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -26,6 +26,14 @@ true + + + org.postgresql + postgresql + 42.4.1 + true + + io.avaje junit diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/PostgresHelper.java b/ebean-core-type/src/main/java/io/ebean/core/type/PostgresHelper.java similarity index 51% rename from ebean-core/src/main/java/io/ebeaninternal/server/type/PostgresHelper.java rename to ebean-core-type/src/main/java/io/ebean/core/type/PostgresHelper.java index 768c7a751..c18359704 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/PostgresHelper.java +++ b/ebean-core-type/src/main/java/io/ebean/core/type/PostgresHelper.java @@ -1,5 +1,7 @@ -package io.ebeaninternal.server.type; +package io.ebean.core.type; +import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.DatabasePlatform; import org.postgresql.util.PGobject; import java.sql.SQLException; @@ -9,12 +11,12 @@ public final class PostgresHelper { /** * The Postgres JSON DB type. */ - static final String JSON_TYPE = "json"; + public static final String JSON_TYPE = "json"; /** * The Postgres JSONB DB type. */ - static final String JSONB_TYPE = "jsonb"; + public static final String JSONB_TYPE = "jsonb"; static final String INET_TYPE = "inet"; @@ -31,4 +33,13 @@ public final class PostgresHelper { pgo.setValue(rawJson); return pgo; } + + /** + * Return true if the platform is Postgres or compatible like Yugabyte, Cockroach. + */ + public static boolean isPostgresCompatible(DatabasePlatform databasePlatform) { + return databasePlatform.isPlatform(Platform.POSTGRES) + || databasePlatform.isPlatform(Platform.YUGABYTE) + || databasePlatform.isPlatform(Platform.COCKROACH); + } } diff --git a/ebean-core-type/src/main/java/io/ebean/core/type/ScalarTypeSet.java b/ebean-core-type/src/main/java/io/ebean/core/type/ScalarTypeSet.java new file mode 100644 index 000000000..725ebac3f --- /dev/null +++ b/ebean-core-type/src/main/java/io/ebean/core/type/ScalarTypeSet.java @@ -0,0 +1,28 @@ +package io.ebean.core.type; + +import io.avaje.lang.Nullable; + +/** + * A ScalarType that has variations based on the mapped JDBC type (like VARCHAR, CLOB, JSON etc). + */ +public interface ScalarTypeSet { + + /** + * The property type these scalar types map to. + */ + Class type(); + + /** + * Return a default ScalarType to use when no other annotations like {@code @DbJson} are present. + */ + @Nullable + ScalarType defaultType(); + + /** + * Return the scalarType to use for the given jdbc type. + *

+ * For example VARCHAR, CLOB, JSON etc. + */ + ScalarType forType(int jdbcType); + +} diff --git a/ebean-core-type/src/main/java/io/ebean/core/type/ScalarTypeSetFactory.java b/ebean-core-type/src/main/java/io/ebean/core/type/ScalarTypeSetFactory.java new file mode 100644 index 000000000..21d133a37 --- /dev/null +++ b/ebean-core-type/src/main/java/io/ebean/core/type/ScalarTypeSetFactory.java @@ -0,0 +1,17 @@ +package io.ebean.core.type; + +import io.avaje.lang.Nullable; +import io.ebean.config.DatabaseConfig; + +/** + * Factory to create ScalarTypeSet. + */ +public interface ScalarTypeSetFactory { + + /** + * Create the ScalarTypeSet given the config and optional objectMapper. + */ + @Nullable + ScalarTypeSet createTypeSet(DatabaseConfig config, @Nullable Object objectMapper); + +} diff --git a/ebean-core-type/src/main/java/module-info.java b/ebean-core-type/src/main/java/module-info.java index 557d5a302..88be6d462 100644 --- a/ebean-core-type/src/main/java/module-info.java +++ b/ebean-core-type/src/main/java/module-info.java @@ -4,6 +4,7 @@ module io.ebean.core.type { requires transitive java.sql; requires transitive io.ebean.api; + requires static org.postgresql.jdbc; requires static com.fasterxml.jackson.core; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/Binder.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/Binder.java index 5dd0af06a..e51dee906 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/Binder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/Binder.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.persist; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.core.type.DataReader; +import io.ebean.core.type.PostgresHelper; import io.ebean.core.type.ScalarType; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.CoreLog; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index bc644954e..b3a5d99bd 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.type; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.ebean.annotation.*; import io.ebean.config.DatabaseConfig; @@ -9,9 +8,7 @@ import io.ebean.config.PlatformConfig; import io.ebean.config.ScalarTypeConverter; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbPlatformType; -import io.ebean.core.type.DocPropertyType; -import io.ebean.core.type.ExtraTypeFactory; -import io.ebean.core.type.ScalarType; +import io.ebean.core.type.*; import io.ebean.types.Cidr; import io.ebean.types.Inet; import io.ebean.util.AnnotationUtil; @@ -51,6 +48,7 @@ public final class DefaultTypeManager implements TypeManager { private static final System.Logger log = CoreLog.internal; + private final Map, ScalarTypeSet> typeSets = new HashMap<>(); private final ConcurrentHashMap, ScalarType> typeMap; private final ConcurrentHashMap> nativeMap; private final ConcurrentHashMap> logicalMap; @@ -71,28 +69,7 @@ public final class DefaultTypeManager implements TypeManager { private final EnumType defaultEnumType; private final DatabasePlatform databasePlatform; - // OPTIONAL ScalarTypes registered if Jackson/JsonNode is in the classpath - /** - * Jackson's JsonNode storage to Clob. - */ - private ScalarType jsonNodeClob; - /** - * Jackson's JsonNode storage to Blob. - */ - private ScalarType jsonNodeBlob; - /** - * Jackson's JsonNode storage to Varchar. - */ - private ScalarType jsonNodeVarchar; - /** - * Jackson's JsonNode storage to Postgres JSON or Clob. - */ - private ScalarType jsonNodeJson; - /** - * Jackson's JsonNode storage to Postgres JSONB or Clob. - */ - private ScalarType jsonNodeJsonb; private final PlatformArrayTypeFactory arrayTypeListFactory; private final PlatformArrayTypeFactory arrayTypeSetFactory; @@ -120,7 +97,6 @@ public final class DefaultTypeManager implements TypeManager { initialiseStandard(config); initialiseJavaTimeTypes(config); - initialiseJacksonTypes(); loadTypesFromProviders(config, objectMapper); loadGeoTypeBinder(config); @@ -160,16 +136,21 @@ public final class DefaultTypeManager implements TypeManager { * Load custom scalar types registered via ExtraTypeFactory and ServiceLoader. */ private void loadTypesFromProviders(DatabaseConfig config, Object objectMapper) { - ServiceLoader factories = ServiceLoader.load(ExtraTypeFactory.class); - Iterator iterator = factories.iterator(); - if (iterator.hasNext()) { - // use the cacheFactory (via classpath service loader) - ExtraTypeFactory plugin = iterator.next(); - List> types = plugin.createTypes(config, objectMapper); - for (ScalarType type : types) { + for (ExtraTypeFactory plugin : ServiceLoader.load(ExtraTypeFactory.class)) { + for (ScalarType type : plugin.createTypes(config, objectMapper)) { add(type); } } + for (ScalarTypeSetFactory factory : ServiceLoader.load(ScalarTypeSetFactory.class)) { + ScalarTypeSet typeSet = factory.createTypeSet(config, objectMapper); + if (typeSet != null) { + typeSets.put(typeSet.type(), typeSet); + ScalarType defaultType = typeSet.defaultType(); + if (defaultType != null) { + typeMap.put(typeSet.type(), defaultType); + } + } + } } private boolean isPostgresCompatible(DatabasePlatform databasePlatform) { @@ -350,19 +331,9 @@ public final class DefaultTypeManager implements TypeManager { } } if (objectMapperPresent && prop.getMutationDetection() == MutationDetection.DEFAULT) { - if (type.equals(JsonNode.class)) { - switch (dbType) { - case Types.VARCHAR: - return jsonNodeVarchar; - case Types.BLOB: - return jsonNodeBlob; - case Types.CLOB: - return jsonNodeClob; - case DbPlatformType.JSONB: - return jsonNodeJsonb; - default: - return jsonNodeJson; - } + ScalarTypeSet typeSet = typeSets.get(type); + if (typeSet != null) { + return typeSet.forType(dbType); } } return createJsonObjectMapperType(prop, dbType, DocPropertyType.OBJECT); @@ -709,25 +680,6 @@ public final class DefaultTypeManager implements TypeManager { } } - /** - * Add support for Jackson's JsonNode mapping to Clob, Blob, Varchar, JSON and JSONB. - */ - private void initialiseJacksonTypes() { - if (objectMapper != null) { - ObjectMapper mapper = (ObjectMapper) objectMapper; - jsonNodeClob = new ScalarTypeJsonNode.Clob(mapper); - jsonNodeBlob = new ScalarTypeJsonNode.Blob(mapper); - jsonNodeVarchar = new ScalarTypeJsonNode.Varchar(mapper); - jsonNodeJson = jsonNodeClob; // Default for non-Postgres databases - jsonNodeJsonb = jsonNodeClob; // Default for non-Postgres databases - if (postgres) { - jsonNodeJson = new ScalarTypeJsonNodePostgres.JSON(mapper); - jsonNodeJsonb = new ScalarTypeJsonNodePostgres.JSONB(mapper); - } - // add as default mapping for JsonNode (when not annotated with @DbJson etc) - typeMap.put(JsonNode.class, jsonNodeJson); - } - } private void initialiseJavaTimeTypes(DatabaseConfig config) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeCidr.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeCidr.java index e355c2936..7cc2238e7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeCidr.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeCidr.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.type; import io.ebean.config.dbplatform.ExtraDbTypes; import io.ebean.core.type.DataBinder; +import io.ebean.core.type.PostgresHelper; import io.ebean.core.type.ScalarTypeBaseVarchar; import io.ebean.types.Cidr; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeInet.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeInet.java index 40f52aca6..828e42a64 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeInet.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeInet.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.type; import io.ebean.config.dbplatform.ExtraDbTypes; import io.ebean.core.type.DataBinder; +import io.ebean.core.type.PostgresHelper; import io.ebean.core.type.ScalarTypeBaseVarchar; import io.ebean.types.Inet; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeInetAddressPostgres.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeInetAddressPostgres.java index a09e7cfb0..fadcf3038 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeInetAddressPostgres.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeInetAddressPostgres.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.type; import io.ebean.config.dbplatform.ExtraDbTypes; import io.ebean.core.type.DataBinder; +import io.ebean.core.type.PostgresHelper; import io.ebean.core.type.ScalarTypeBaseVarchar; import io.ebean.text.TextException; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonList.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonList.java index 74b23c799..e37ff8cb6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonList.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonList.java @@ -3,10 +3,7 @@ package io.ebeaninternal.server.type; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import io.ebean.config.dbplatform.DbPlatformType; -import io.ebean.core.type.DataBinder; -import io.ebean.core.type.DataReader; -import io.ebean.core.type.DocPropertyType; -import io.ebean.core.type.ScalarType; +import io.ebean.core.type.*; import io.ebean.text.TextException; import io.ebean.text.json.EJson; import io.ebeaninternal.json.ModifyAwareList; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMapPostgres.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMapPostgres.java index ae33fa0e4..612048447 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMapPostgres.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMapPostgres.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.type; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.core.type.DataBinder; +import io.ebean.core.type.PostgresHelper; import java.sql.SQLException; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonSet.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonSet.java index 334e86417..0ae3248a4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonSet.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonSet.java @@ -3,10 +3,7 @@ package io.ebeaninternal.server.type; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import io.ebean.config.dbplatform.DbPlatformType; -import io.ebean.core.type.DataBinder; -import io.ebean.core.type.DataReader; -import io.ebean.core.type.DocPropertyType; -import io.ebean.core.type.ScalarType; +import io.ebean.core.type.*; import io.ebean.text.TextException; import io.ebean.text.json.EJson; import io.ebeaninternal.json.ModifyAwareSet; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonString.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonString.java index 51fb54d4b..aa69300ed 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonString.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonString.java @@ -3,6 +3,7 @@ package io.ebeaninternal.server.type; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.config.dbplatform.ExtraDbTypes; import io.ebean.core.type.DataBinder; +import io.ebean.core.type.PostgresHelper; import io.ebean.core.type.ScalarType; import java.sql.SQLException; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/TypeJsonManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/TypeJsonManager.java index 25034e409..84ceac12b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/TypeJsonManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/TypeJsonManager.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.ebean.ModifyAwareType; import io.ebean.annotation.MutationDetection; import io.ebean.config.dbplatform.DbPlatformType; +import io.ebean.core.type.PostgresHelper; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; final class TypeJsonManager { diff --git a/ebean-core/src/main/java/module-info.java b/ebean-core/src/main/java/module-info.java index ee9ba85ea..58a3438c9 100644 --- a/ebean-core/src/main/java/module-info.java +++ b/ebean-core/src/main/java/module-info.java @@ -8,6 +8,7 @@ module io.ebean.core { uses io.ebean.config.dbplatform.DatabasePlatformProvider; uses io.ebean.datasource.DataSourceAlertFactory; uses io.ebean.core.type.ExtraTypeFactory; + uses io.ebean.core.type.ScalarTypeSetFactory; uses io.ebeanservice.docstore.api.DocStoreFactory; uses io.ebean.migration.auto.AutoMigrationRunner; uses io.avaje.classpath.scanner.ClassPathScannerFactory; diff --git a/ebean-json-node/pom.xml b/ebean-json-node/pom.xml new file mode 100644 index 000000000..dfefb9b9f --- /dev/null +++ b/ebean-json-node/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + ebean-parent + io.ebean + 13.9.3-SNAPSHOT + + + ebean-json-node + + + 19 + 19 + UTF-8 + + + + + + + io.ebean + ebean-core-type + 13.9.3-SNAPSHOT + provided + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + provided + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + provided + + + + io.avaje + junit + 1.1 + test + + + + diff --git a/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/JsonNodeSet.java b/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/JsonNodeSet.java new file mode 100644 index 000000000..c932d5339 --- /dev/null +++ b/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/JsonNodeSet.java @@ -0,0 +1,51 @@ +package io.ebean.jackson.jsonnode; + +import com.fasterxml.jackson.databind.JsonNode; +import io.ebean.config.dbplatform.DbPlatformType; +import io.ebean.core.type.ScalarType; +import io.ebean.core.type.ScalarTypeSet; + +import java.sql.Types; + +class JsonNodeSet implements ScalarTypeSet { + + final ScalarType varchar; + final ScalarType clob; + final ScalarType blob; + final ScalarType jsonb; + final ScalarType json; + + JsonNodeSet(ScalarType varchar, ScalarType clob, ScalarType blob, ScalarType jsonb, ScalarType json) { + this.varchar = varchar; + this.clob = clob; + this.blob = blob; + this.jsonb = jsonb; + this.json = json; + } + + @Override + public Class type() { + return JsonNode.class; + } + + @Override + public ScalarType defaultType() { + return json; + } + + @Override + public ScalarType forType(int dbType) { + switch (dbType) { + case Types.VARCHAR: + return varchar; + case Types.BLOB: + return blob; + case Types.CLOB: + return clob; + case DbPlatformType.JSONB: + return jsonb; + default: + return json; + } + } +} diff --git a/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/JsonNodeTypeFactory.java b/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/JsonNodeTypeFactory.java new file mode 100644 index 000000000..af8f198fe --- /dev/null +++ b/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/JsonNodeTypeFactory.java @@ -0,0 +1,31 @@ +package io.ebean.jackson.jsonnode; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.ebean.config.DatabaseConfig; +import io.ebean.core.type.PostgresHelper; +import io.ebean.core.type.ScalarType; +import io.ebean.core.type.ScalarTypeSet; +import io.ebean.core.type.ScalarTypeSetFactory; + +public class JsonNodeTypeFactory implements ScalarTypeSetFactory { + + @Override + public ScalarTypeSet createTypeSet(DatabaseConfig config, Object objectMapper) { + if (objectMapper == null) { + return null; + } + + ObjectMapper mapper = (ObjectMapper) objectMapper; + var varchar = new ScalarTypeJsonNode.Varchar(mapper); + var clob = new ScalarTypeJsonNode.Clob(mapper); + var blob = new ScalarTypeJsonNode.Blob(mapper); + ScalarType json = clob; // Default for non-Postgres databases + ScalarType jsonb = clob; // Default for non-Postgres databases + if (PostgresHelper.isPostgresCompatible(config.getDatabasePlatform())) { + json = new ScalarTypeJsonNodePostgres.JSON(mapper); + jsonb = new ScalarTypeJsonNodePostgres.JSONB(mapper); + } + return new JsonNodeSet(varchar, clob, blob, jsonb, json); + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java b/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/ScalarTypeJsonNode.java similarity index 95% rename from ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java rename to ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/ScalarTypeJsonNode.java index 0c7959038..ca9859bde 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java +++ b/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/ScalarTypeJsonNode.java @@ -1,4 +1,4 @@ -package io.ebeaninternal.server.type; +package io.ebean.jackson.jsonnode; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -11,11 +11,7 @@ import io.ebean.core.type.ScalarTypeBase; import io.ebean.text.TextException; import io.ebean.util.IOUtils; -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; +import java.io.*; import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.sql.Types; @@ -182,7 +178,8 @@ abstract class ScalarTypeJsonNode extends ScalarTypeBase { if (value == null) { dataOutput.writeBoolean(false); } else { - ScalarHelp.writeUTF(dataOutput, format(value)); + dataOutput.writeBoolean(true); + dataOutput.writeUTF(format(value)); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNodePostgres.java b/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/ScalarTypeJsonNodePostgres.java similarity index 94% rename from ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNodePostgres.java rename to ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/ScalarTypeJsonNodePostgres.java index b23252367..c78a69b2b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNodePostgres.java +++ b/ebean-json-node/src/main/java/io/ebean/jackson/jsonnode/ScalarTypeJsonNodePostgres.java @@ -1,9 +1,10 @@ -package io.ebeaninternal.server.type; +package io.ebean.jackson.jsonnode; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.core.type.DataBinder; +import io.ebean.core.type.PostgresHelper; import java.sql.SQLException; diff --git a/ebean-json-node/src/main/java/module-info.java b/ebean-json-node/src/main/java/module-info.java new file mode 100644 index 000000000..ae48a30fb --- /dev/null +++ b/ebean-json-node/src/main/java/module-info.java @@ -0,0 +1,10 @@ +import io.ebean.jackson.jsonnode.JsonNodeTypeFactory; + +module io.ebean.json.node { + + requires io.ebean.core.type; + requires com.fasterxml.jackson.core; + requires com.fasterxml.jackson.databind; + + provides io.ebean.core.type.ScalarTypeSetFactory with JsonNodeTypeFactory; +} diff --git a/ebean-json-node/src/main/resources/META-INF/services/io.ebean.core.type.ScalarTypeSetFactory b/ebean-json-node/src/main/resources/META-INF/services/io.ebean.core.type.ScalarTypeSetFactory new file mode 100644 index 000000000..3ed48464a --- /dev/null +++ b/ebean-json-node/src/main/resources/META-INF/services/io.ebean.core.type.ScalarTypeSetFactory @@ -0,0 +1 @@ +io.ebean.jackson.jsonnode.JsonNodeTypeFactory diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 4c50ebdc2..9e334b365 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -109,6 +109,13 @@ test + + io.ebean + ebean-json-node + 13.9.3-SNAPSHOT + test + + io.ebean ebean-platform-all diff --git a/pom.xml b/pom.xml index 15d12f281..f2c505822 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,7 @@ composites ebean-joda-time ebean-csv-reader + ebean-json-node