diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index bc3ae587f..476007ebe 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -193,12 +193,6 @@ public class DatabaseConfig { */ private JsonConfig.Include jsonInclude = JsonConfig.Include.ALL; - /** - * When true then by default DbJson beans are assumed to be dirty. - * I believe we want to change this default to false in the future. - */ - private boolean jsonDirtyByDefault = true; - /** * The database platform name. Used to imply a DatabasePlatform to use. */ @@ -743,26 +737,6 @@ public class DatabaseConfig { this.jsonInclude = jsonInclude; } - /** - * Return true if DbJson beans are assumed dirty by default. - *

- * That is, when true beans that do not implement ModifyAwareType are by - * default assumed to be dirty and included in updates. - */ - public boolean isJsonDirtyByDefault() { - return jsonDirtyByDefault; - } - - /** - * Set to false if we want DbJson beans to not be assumed to be dirty. - *

- * That is, when true beans that do not implement ModifyAwareType are by - * default assumed to be dirty and included in updates. - */ - public void setJsonDirtyByDefault(boolean jsonDirtyByDefault) { - this.jsonDirtyByDefault = jsonDirtyByDefault; - } - /** * Return the name of the Database. */ @@ -2935,7 +2909,6 @@ public class DatabaseConfig { jsonInclude = p.getEnum(JsonConfig.Include.class, "jsonInclude", jsonInclude); jsonDateTime = p.getEnum(JsonConfig.DateTime.class, "jsonDateTime", jsonDateTime); jsonDate = p.getEnum(JsonConfig.Date.class, "jsonDate", jsonDate); - jsonDirtyByDefault = p.getBoolean("jsonDirtyByDefault", jsonDirtyByDefault); runMigration = p.getBoolean("migration.run", runMigration); ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate); 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 28999e838..8ffb15372 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 @@ -134,7 +134,7 @@ public final class DefaultTypeManager implements TypeManager { this.postgres = isPostgres(config.getDatabasePlatform()); this.objectMapperPresent = config.getClassLoadConfig().isJacksonObjectMapperPresent(); this.objectMapper = (objectMapperPresent) ? initObjectMapper(config) : null; - this.jsonManager = (objectMapperPresent) ? new TypeJsonManager(postgres, objectMapper, config.isJsonDirtyByDefault()) : null; + this.jsonManager = (objectMapperPresent) ? new TypeJsonManager(postgres, objectMapper) : null; this.extraTypeFactory = new DefaultTypeFactory(config); this.arrayTypeListFactory = arrayTypeListFactory(config.getDatabasePlatform()); this.arrayTypeSetFactory = arrayTypeSetFactory(config.getDatabasePlatform()); @@ -556,7 +556,7 @@ public final class DefaultTypeManager implements TypeManager { // no override or further mapping required return scalarType; } - ScalarTypeEnum scalarEnum = (ScalarTypeEnum)scalarType; + ScalarTypeEnum scalarEnum = (ScalarTypeEnum) scalarType; if (scalarEnum != null && !scalarEnum.isOverrideBy(type)) { if (type != null && !scalarEnum.isCompatible(type)) { throw new IllegalStateException("Error mapping Enum type:" + enumType + " It is mapped using 2 different modes when only one is supported (ORDINAL, STRING or an Ebean mapping)"); @@ -673,7 +673,7 @@ public final class DefaultTypeManager implements TypeManager { private Object initObjectMapper(DatabaseConfig config) { Object objectMapper = config.getObjectMapper(); if (objectMapper == null) { - objectMapper = new ObjectMapper(); + objectMapper = InitObjectMapper.init(); config.setObjectMapper(objectMapper); } return objectMapper; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/InitObjectMapper.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/InitObjectMapper.java new file mode 100644 index 000000000..90a86ec79 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/InitObjectMapper.java @@ -0,0 +1,22 @@ +package io.ebeaninternal.server.type; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Initialise the Jackson ObjectMapper. + */ +class InitObjectMapper { + + /** + * Create and return the default ObjectMapper. + */ + static Object init() { + SimpleModule module = new SimpleModule(); + module.addAbstractTypeMapping(Set.class, LinkedHashSet.class); + return new ObjectMapper().registerModule(module); + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java index 7fb3aa4b4..334f4b232 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java @@ -13,9 +13,6 @@ import io.ebean.core.type.DataReader; import io.ebean.core.type.DocPropertyType; import io.ebean.core.type.ScalarType; import io.ebean.text.TextException; -import io.ebeaninternal.json.ModifyAwareList; -import io.ebeaninternal.json.ModifyAwareMap; -import io.ebeaninternal.json.ModifyAwareSet; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import javax.persistence.PersistenceException; @@ -24,9 +21,6 @@ import java.io.DataOutput; import java.io.IOException; import java.sql.SQLException; import java.sql.Types; -import java.util.List; -import java.util.Map; -import java.util.Set; /** * Supports @DbJson properties using Jackson ObjectMapper. @@ -38,25 +32,14 @@ class ScalarTypeJsonObjectMapper { */ static ScalarType createTypeFor(TypeJsonManager jsonManager, DeployBeanProperty prop, int dbType, DocPropertyType docType) { AnnotatedField field = (AnnotatedField) prop.getJacksonField(); - Class type = field.getRawType(); - MutationDetection mode = prop.getMutationDetection(); if (mode == MutationDetection.NONE) { - return new NoMutationDetection(jsonManager, field, dbType, type); + return new NoMutationDetection(jsonManager, field, dbType, docType); } else if (mode != MutationDetection.DEFAULT) { - return new GenericObject(jsonManager, field, dbType, type); - } - if (Set.class.equals(type)) { - return new OmSet(jsonManager, field, dbType, docType); - } - if (List.class.equals(type)) { - return new OmList(jsonManager, field, dbType, docType); - } - if (Map.class.equals(type)) { - return new OmMap(jsonManager, field, dbType); + return new GenericObject(jsonManager, field, dbType, docType); } prop.setMutationDetection(MutationDetection.HASH); - return new GenericObject(jsonManager, field, dbType, type); + return new GenericObject(jsonManager, field, dbType, docType); } /** @@ -64,8 +47,8 @@ class ScalarTypeJsonObjectMapper { */ private static class NoMutationDetection extends Base { - NoMutationDetection(TypeJsonManager jsonManager, AnnotatedField field, int dbType, Class rawType) { - super(Object.class, jsonManager, field, dbType, DocPropertyType.OBJECT, rawType); + NoMutationDetection(TypeJsonManager jsonManager, AnnotatedField field, int dbType, DocPropertyType docType) { + super(Object.class, jsonManager, field, dbType, docType); } @Override @@ -84,8 +67,8 @@ class ScalarTypeJsonObjectMapper { */ private static class GenericObject extends Base { - GenericObject(TypeJsonManager jsonManager, AnnotatedField field, int dbType, Class rawType) { - super(Object.class, jsonManager, field, dbType, DocPropertyType.OBJECT, rawType); + GenericObject(TypeJsonManager jsonManager, AnnotatedField field, int dbType, DocPropertyType docType) { + super(Object.class, jsonManager, field, dbType, docType); } @Override @@ -128,60 +111,6 @@ class ScalarTypeJsonObjectMapper { } } - /** - * Type for Sets wrapping the ObjectMapper Set as a ModifyAwareSet. - */ - @SuppressWarnings("rawtypes") - private static class OmSet extends Base { - - OmSet(TypeJsonManager jsonManager, AnnotatedField field, int dbType, DocPropertyType docType) { - super(Set.class, jsonManager, field, dbType, docType); - } - - @Override - @SuppressWarnings("unchecked") - public Set read(DataReader reader) throws SQLException { - Set value = super.read(reader); - return value == null ? null : new ModifyAwareSet(value); - } - } - - /** - * Type for Lists wrapping the ObjectMapper List as a ModifyAwareList. - */ - @SuppressWarnings("rawtypes") - private static class OmList extends Base { - - OmList(TypeJsonManager jsonManager, AnnotatedField field, int dbType, DocPropertyType docType) { - super(List.class, jsonManager, field, dbType, docType); - } - - @Override - @SuppressWarnings("unchecked") - public List read(DataReader reader) throws SQLException { - List value = super.read(reader); - return value == null ? null : new ModifyAwareList(value); - } - } - - /** - * Type for Map wrapping the ObjectMapper Map as a ModifyAwareMap. - */ - @SuppressWarnings("rawtypes") - private static class OmMap extends Base { - - OmMap(TypeJsonManager jsonManager, AnnotatedField field, int dbType) { - super(Map.class, jsonManager, field, dbType, DocPropertyType.OBJECT); - } - - @Override - @SuppressWarnings("unchecked") - public Map read(DataReader reader) throws SQLException { - Map value = super.read(reader); - return value == null ? null : new ModifyAwareMap(value); - } - } - /** * ScalarType that uses Jackson ObjectMapper to marshall/unmarshall to/from JSON * and storing them in one of JSON, JSONB, VARCHAR, CLOB or BLOB. @@ -193,39 +122,22 @@ class ScalarTypeJsonObjectMapper { protected final JavaType deserType; protected final String pgType; private final DocPropertyType docType; - private final TypeJsonManager.DirtyHandler dirtyHandler; Base(Class cls, TypeJsonManager jsonManager, AnnotatedField field, int dbType, DocPropertyType docType) { - this(cls, jsonManager, field, dbType, docType, cls); - } - - Base(Class cls, TypeJsonManager jsonManager, AnnotatedField field, int dbType, DocPropertyType docType, Class rawType) { super(cls, false, dbType); this.objectReader = jsonManager.objectMapper(); this.pgType = jsonManager.postgresType(dbType); this.docType = docType; - this.dirtyHandler = jsonManager.dirtyHandler(cls, rawType); final JacksonTypeHelper helper = new JacksonTypeHelper(field, objectReader); this.deserType = helper.type(); this.objectWriter = helper.objectWriter(); } - /** - * Consider as a mutable type. Use the isDirty() method to check for dirty state. - */ @Override public boolean isMutable() { return true; } - /** - * Return true if the value should be considered dirty (and included in an update). - */ - @Override - public boolean isDirty(Object value) { - return dirtyHandler.isDirty(value); - } - @Override public T read(DataReader reader) throws SQLException { String json = reader.getString(); 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 baea26dec..9cc0b5f0d 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 @@ -2,25 +2,16 @@ package io.ebeaninternal.server.type; import com.fasterxml.jackson.databind.ObjectMapper; import io.ebean.ModifyAwareType; -import io.ebean.config.DatabaseConfig; import io.ebean.config.dbplatform.DbPlatformType; class TypeJsonManager { - interface DirtyHandler { - boolean isDirty(Object value); - } - private final boolean postgres; private final ObjectMapper objectMapper; - private final DirtyHandler defaultHandler; - private final DirtyHandler modifyAwareHandler; - TypeJsonManager(boolean postgres, Object objectMapper, boolean defaultDirty) { + TypeJsonManager(boolean postgres, Object objectMapper) { this.postgres = postgres; this.objectMapper = (ObjectMapper) objectMapper; - this.defaultHandler = new DefaultHandler(defaultDirty); - this.modifyAwareHandler = new ModifyAwareHandler(); } ObjectMapper objectMapper() { @@ -39,17 +30,6 @@ class TypeJsonManager { return null; } - /** - * Return the DirtyHandler to use. - */ - DirtyHandler dirtyHandler(Class cls, Class rawType) { - if (!Object.class.equals(cls) || ModifyAwareType.class.isAssignableFrom(rawType)) { - // Set, List and Map are modify aware - return modifyAwareHandler; - } - return defaultHandler; - } - /** * Return true if the value should be considered dirty (and included in an update). */ @@ -71,28 +51,4 @@ class TypeJsonManager { } } - static final class ModifyAwareHandler implements DirtyHandler { - @Override - public boolean isDirty(Object value) { - return checkModifyAware(value); - } - } - - /** - * Effectively constant based on {@link DatabaseConfig#isJsonDirtyByDefault()} - */ - static final class DefaultHandler implements DirtyHandler { - - private final boolean dirty; - - DefaultHandler(boolean dirty) { - this.dirty = dirty; - } - - @Override - public boolean isDirty(Object value) { - return dirty; - } - } - } diff --git a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java index dde2cb216..55eb1f06e 100644 --- a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java @@ -104,9 +104,6 @@ public class ServerConfigTest { assertEquals(PlatformConfig.DbUuid.BINARY, serverConfig.getPlatformConfig().getDbUuid()); assertEquals(JsonConfig.DateTime.MILLIS, serverConfig.getJsonDateTime()); assertEquals(JsonConfig.Date.MILLIS, serverConfig.getJsonDate()); - assertFalse(serverConfig.isJsonDirtyByDefault()); - serverConfig.setJsonDirtyByDefault(true); - assertTrue(serverConfig.isJsonDirtyByDefault()); assertEquals("r0,users,orgs", serverConfig.getEnabledL2Regions()); @@ -159,7 +156,6 @@ public class ServerConfigTest { assertFalse(serverConfig.isIdGeneratorAutomatic()); assertEquals(JsonConfig.DateTime.ISO8601, serverConfig.getJsonDateTime()); assertEquals(JsonConfig.Date.ISO8601, serverConfig.getJsonDate()); - assertTrue(serverConfig.isJsonDirtyByDefault()); assertTrue(serverConfig.getPlatformConfig().isCaseSensitiveCollation()); assertTrue(serverConfig.isAutoLoadModuleInfo()); diff --git a/ebean-core/src/test/java/org/tests/json/TestDbJson_List.java b/ebean-core/src/test/java/org/tests/json/TestDbJson_List.java index f43d6f23c..13e85a160 100644 --- a/ebean-core/src/test/java/org/tests/json/TestDbJson_List.java +++ b/ebean-core/src/test/java/org/tests/json/TestDbJson_List.java @@ -76,10 +76,11 @@ public class TestDbJson_List extends BaseTestCase { update_when_dirty(); update_when_dirty_flags(); update_when_dirty_SetListMap(); + + DB.delete(found); } - //@Test//(dependsOnMethods = "insert") - public void json_parse_format() { + private void json_parse_format() { String asJson = DB.json().toJson(found); assertThat(asJson).contains("\"tags\":[\"one\",\"two\"]"); @@ -104,8 +105,7 @@ public class TestDbJson_List extends BaseTestCase { assertThat(fromJson.getBeanMap()).hasSize(2); } - //@Test//(dependsOnMethods = "insert") - public void update_when_notDirty() { + private void update_when_notDirty() { found.setName("mod"); LoggedSqlCollector.start(); @@ -117,7 +117,7 @@ public class TestDbJson_List extends BaseTestCase { assertSql(sql.get(0)).contains("update ebasic_json_list set name=?, version=? where"); } - public void update_when_dirty() { + private void update_when_dirty() { //found.setName("modAgain"); found.getTags().add("three"); @@ -131,7 +131,7 @@ public class TestDbJson_List extends BaseTestCase { assertSql(sql.get(0)).contains("update ebasic_json_list set tags=?, version=? where id=? and version=?"); } - public void update_when_dirty_flags() { + private void update_when_dirty_flags() { //found.setName("modAgain"); found.getFlags().remove(42L); @@ -145,7 +145,7 @@ public class TestDbJson_List extends BaseTestCase { assertSql(sql.get(0)).contains("update ebasic_json_list set flags=?, version=? where id=? and version=?;"); } - public void update_when_dirty_SetListMap() { + private void update_when_dirty_SetListMap() { //found.setName("modAgain"); found.getBeanSet().clear(); diff --git a/ebean-core/src/test/java/org/tests/model/json/EBasicJsonList.java b/ebean-core/src/test/java/org/tests/model/json/EBasicJsonList.java index f76d282f7..885e85bf8 100644 --- a/ebean-core/src/test/java/org/tests/model/json/EBasicJsonList.java +++ b/ebean-core/src/test/java/org/tests/model/json/EBasicJsonList.java @@ -20,6 +20,7 @@ public class EBasicJsonList { String name; + // @JsonDeserialize(as=LinkedHashSet.class) @DbJson(length = 700, name = "beans") Set beanSet;