From 11eed4cfe9cb9118624bd0200691acf6b71d587e Mon Sep 17 00:00:00 2001 From: rbygrave Date: Wed, 28 Jul 2021 21:43:57 +1200 Subject: [PATCH] Add BeanPropertyJsonMapper for JSON dirty detection --- .../server/deploy/BeanProperty.java | 22 ------- .../server/deploy/BeanPropertyJsonMapper.java | 57 +++++++++++++++++++ .../deploy/meta/DeployBeanProperty.java | 3 + .../deploy/meta/DeployBeanPropertyLists.java | 13 ++--- 4 files changed, 64 insertions(+), 31 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyJsonMapper.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index d3c832c85..d9af317d7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -219,7 +219,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { */ @SuppressWarnings("rawtypes") final ScalarType scalarType; - final boolean jsonMapperType; private final DocPropertyOptions docOptions; @@ -333,7 +332,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { this.formula = sqlFormulaSelect != null; this.dbType = deploy.getDbType(); this.scalarType = deploy.getScalarType(); - this.jsonMapperType = (scalarType == null) ? false : scalarType.isJsonMapper(); this.lob = isLobType(dbType); this.propertyType = deploy.getPropertyType(); this.field = deploy.getField(); @@ -428,7 +426,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { this.setter = source.setter; this.dbType = source.getDbType(true); this.scalarType = source.scalarType; - this.jsonMapperType = source.jsonMapperType; this.lob = isLobType(dbType); this.propertyType = source.getPropertyType(); this.field = source.getField(); @@ -632,13 +629,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { Object value = scalarType.read(reader); if (bean != null) { setValue(bean, value); - if (jsonMapperType) { - String json = reader.popJson(); - if (json != null) { - final String hash = Md5.hash(json); - bean._ebean_getIntercept().mutableHash(propertyIndex, hash); - } - } } return value; } catch (TextException e) { @@ -1028,18 +1018,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { * This is only used for 'mutable' scalar types like hstore etc. */ boolean isDirtyValue(Object value, EntityBeanIntercept ebi) { - if (jsonMapperType) { - // dirty detection based on md5 hash of json content - final String json = scalarType.jsonMapper(value); - final String newHash = Md5.hash(json); - final String oldHash = ebi.mutableHash(propertyIndex); - if (!Objects.equals(newHash, oldHash)) { - ebi.mutableContent(propertyIndex, json); // so we only convert to json once - ebi.mutableHash(propertyIndex, newHash); // for dirty detection next time - return true; - } - return false; - } return scalarType.isDirty(value); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyJsonMapper.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyJsonMapper.java new file mode 100644 index 000000000..2d24958b6 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyJsonMapper.java @@ -0,0 +1,57 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.EntityBean; +import io.ebean.bean.EntityBeanIntercept; +import io.ebean.core.type.DataReader; +import io.ebean.text.TextException; +import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; +import io.ebeaninternal.server.util.Md5; + +import javax.persistence.PersistenceException; +import java.sql.SQLException; +import java.util.Objects; + +public class BeanPropertyJsonMapper extends BeanProperty { + + public BeanPropertyJsonMapper(BeanDescriptor desc, DeployBeanProperty deployProp) { + super(desc, deployProp); + } + + /** + * Return true if the mutable value is considered dirty. + * This is only used for 'mutable' scalar types like hstore etc. + */ + @Override + boolean isDirtyValue(Object value, EntityBeanIntercept ebi) { + // dirty detection based on md5 hash of json content + final String json = scalarType.jsonMapper(value); + final String newHash = Md5.hash(json); + final String oldHash = ebi.mutableHash(propertyIndex); + if (!Objects.equals(newHash, oldHash)) { + ebi.mutableContent(propertyIndex, json); // so we only convert to json once + ebi.mutableHash(propertyIndex, newHash); // for dirty detection next time + return true; + } + return false; + } + + @Override + public Object readSet(DataReader reader, EntityBean bean) throws SQLException { + try { + Object value = scalarType.read(reader); + if (bean != null) { + setValue(bean, value); + String json = reader.popJson(); + if (json != null) { + final String hash = Md5.hash(json); + bean._ebean_getIntercept().mutableHash(propertyIndex, hash); + } + } + return value; + } catch (TextException e) { + throw e; + } catch (Exception e) { + throw new PersistenceException("Error readSet on " + descriptor + "." + name, e); + } + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index e20c898ce..92ad7f1e9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -1201,4 +1201,7 @@ public class DeployBeanProperty { return false; } + boolean isJsonMapper() { + return scalarType != null && scalarType.isJsonMapper(); + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java index f6280b260..9843f8e5c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java @@ -1,15 +1,7 @@ package io.ebeaninternal.server.deploy.meta; import io.ebean.bean.EntityBean; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.deploy.BeanDescriptorMap; -import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; -import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; -import io.ebeaninternal.server.deploy.BeanPropertyIdClass; -import io.ebeaninternal.server.deploy.BeanPropertyOrderColumn; -import io.ebeaninternal.server.deploy.BeanPropertySimpleCollection; -import io.ebeaninternal.server.deploy.InheritInfo; +import io.ebeaninternal.server.deploy.*; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import io.ebeaninternal.server.properties.BeanPropertySetter; import io.ebeaninternal.server.type.ScalarTypeString; @@ -490,6 +482,9 @@ public class DeployBeanPropertyLists { return new BeanPropertyAssocMany(desc, (DeployBeanPropertyAssocMany) deployProp); } + if (deployProp.isJsonMapper()) { + return new BeanPropertyJsonMapper(desc, deployProp); + } return new BeanProperty(desc, deployProp); }