From 7532ef0426f223631721e7044f06c8460e111652 Mon Sep 17 00:00:00 2001 From: datagear Date: Wed, 23 Jan 2019 10:09:21 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E7=BC=96=E8=BE=91=E9=9B=86?= =?UTF-8?q?=E5=90=88=E5=B1=9E=E6=80=A7=E5=80=BC=E5=85=83=E7=B4=A0=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E5=85=83=E7=B4=A0=E7=9A=84=E5=BC=95=E7=94=A8=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=80=BC=E6=97=A0=E6=B3=95=E4=BF=9D=E5=AD=98=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=8C=E5=8E=9F=E5=9B=A0=EF=BC=9A=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E5=A4=84=E7=90=86=E5=8F=82=E6=95=B0=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E6=B2=A1=E6=9C=89=E5=BB=B6=E8=BF=9F=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=BE=AA=E7=8E=AF=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/datagear/persistence/support/PMU.java | 77 +++++++++ .../support/UpdatePersistenceOperation.java | 25 ++- .../web/convert/AbstractDataConverter.java | 21 ++- .../web/convert/ClassDataConverter.java | 152 +++++++++++++++++- .../web/convert/ModelDataConverter.java | 128 ++++++++------- 5 files changed, 333 insertions(+), 70 deletions(-) diff --git a/datagear-persistence/src/main/java/org/datagear/persistence/support/PMU.java b/datagear-persistence/src/main/java/org/datagear/persistence/support/PMU.java index cd5591e4..2f2678cb 100644 --- a/datagear-persistence/src/main/java/org/datagear/persistence/support/PMU.java +++ b/datagear-persistence/src/main/java/org/datagear/persistence/support/PMU.java @@ -4,11 +4,15 @@ package org.datagear.persistence.support; +import java.util.Collection; + import org.datagear.model.Model; import org.datagear.model.Property; import org.datagear.model.support.MU; +import org.datagear.model.support.PropertyModel; import org.datagear.persistence.features.KeyRule; import org.datagear.persistence.features.KeyRule.RuleType; +import org.datagear.persistence.features.MappedBy; import org.datagear.persistence.mapper.Mapper; import org.datagear.persistence.mapper.MapperUtil; import org.datagear.persistence.mapper.ModelTableMapper; @@ -83,4 +87,77 @@ public class PMU { return !isPrivate(model, property, propertyConcreteModel); } + + /** + * 设置属性值。 + *

+ * 此方法会处理{@linkplain MappedBy}双向关联,反向赋值。 + *

+ *

+ * 注意:此方法不会处理反向集合属性,因为此时obj仅是反向集合中的单个元素 + *

+ * + * @param model + * @param property + * @param propertyModel + * @param obj + * @param propertyValue + */ + public static void setPropertyValue(Model model, Property property, PropertyModel propertyModel, Object obj, + Object propertyValue) + { + Model pmodel = propertyModel.getModel(); + + if (propertyValue == null) + { + if (pmodel.getType().isPrimitive()) + ; + else + property.set(obj, null); + } + else if (MU.isPrimitiveModel(pmodel)) + { + property.set(obj, propertyValue); + } + else + { + property.set(obj, propertyValue); + + RelationMapper relationMapper = property.getFeature(RelationMapper.class); + Mapper mapper = relationMapper.getMappers()[propertyModel.getIndex()]; + + String mappedTarget = null; + if (mapper.isMappedBySource()) + mappedTarget = mapper.getMappedByTarget(); + else if (mapper.isMappedByTarget()) + mappedTarget = mapper.getMappedBySource(); + + // 反向设置属性值 + if (mappedTarget != null) + { + Property mappedProperty = MU.getProperty(pmodel, mappedTarget); + + // 不处理反向集合属性,因为此时obj仅是反向集合中的单个元素 + if (MU.isMultipleProperty(mappedProperty)) + ; + else if (property.isCollection()) + { + @SuppressWarnings("unchecked") + Collection collection = (Collection) propertyValue; + + for (Object ele : collection) + mappedProperty.set(ele, obj); + } + else if (property.isArray()) + { + Object[] array = (Object[]) propertyValue; + + for (Object ele : array) + mappedProperty.set(ele, obj); + } + else + mappedProperty.set(propertyValue, obj); + } + } + } } diff --git a/datagear-persistence/src/main/java/org/datagear/persistence/support/UpdatePersistenceOperation.java b/datagear-persistence/src/main/java/org/datagear/persistence/support/UpdatePersistenceOperation.java index 1bc60726..8f6a6b43 100644 --- a/datagear-persistence/src/main/java/org/datagear/persistence/support/UpdatePersistenceOperation.java +++ b/datagear-persistence/src/main/java/org/datagear/persistence/support/UpdatePersistenceOperation.java @@ -307,7 +307,7 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten else { UpdateInfoForAutoKeyUpdateRule updateInfo = new UpdateInfoForAutoKeyUpdateRule(property, i, - pmm, myMapperIndex, updatePropertyValueElement); + pmm, myMapperIndex, originalPropertyValueElement, updatePropertyValueElement); updateInfoForAutoKeyUpdateRules.add(updateInfo); } } @@ -341,7 +341,8 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten else { UpdateInfoForAutoKeyUpdateRule updateInfo = new UpdateInfoForAutoKeyUpdateRule(property, i, - pmm, myOriginalMapperIndex, updatePropertyValueElement); + pmm, myOriginalMapperIndex, originalPropertyValueElement, + updatePropertyValueElement); updateInfoForAutoKeyUpdateRules.add(updateInfo); } } @@ -385,7 +386,7 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten else { UpdateInfoForAutoKeyUpdateRule updateInfo = new UpdateInfoForAutoKeyUpdateRule(property, i, - pmm, j, updatePropertyValue); + pmm, j, originalPropertyValue, updatePropertyValue); updateInfoForAutoKeyUpdateRules.add(updateInfo); } } @@ -417,7 +418,7 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten int myCount = updatePropertyTableData(cn, dialect, table, model, updateCondition, updateInfo.getProperty(), updateInfo.getPropertyModelMapper(), null, - originalPropertyValues[updateInfo.getPropertyIndex()], updatePropertyValue, null, false, + updateInfo.getOriginalPropertyValue(), updatePropertyValue, null, false, expressionEvaluationContext); if (myCount == 0) @@ -968,6 +969,8 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten private int propertyModelMapperIndex; + private Object originalPropertyValue; + private Object updatePropertyValue; public UpdateInfoForAutoKeyUpdateRule() @@ -976,13 +979,15 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten } public UpdateInfoForAutoKeyUpdateRule(Property property, int propertyIndex, - PropertyModelMapper propertyModelMapper, int propertyModelMapperIndex, Object updatePropertyValue) + PropertyModelMapper propertyModelMapper, int propertyModelMapperIndex, Object originalPropertyValue, + Object updatePropertyValue) { super(); this.property = property; this.propertyIndex = propertyIndex; this.propertyModelMapper = propertyModelMapper; this.propertyModelMapperIndex = propertyModelMapperIndex; + this.originalPropertyValue = originalPropertyValue; this.updatePropertyValue = updatePropertyValue; } @@ -1026,6 +1031,16 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten this.propertyModelMapperIndex = propertyModelMapperIndex; } + public Object getOriginalPropertyValue() + { + return originalPropertyValue; + } + + public void setOriginalPropertyValue(Object originalPropertyValue) + { + this.originalPropertyValue = originalPropertyValue; + } + public Object getUpdatePropertyValue() { return updatePropertyValue; diff --git a/datagear-web/src/main/java/org/datagear/web/convert/AbstractDataConverter.java b/datagear-web/src/main/java/org/datagear/web/convert/AbstractDataConverter.java index b5a2ab19..2084175c 100644 --- a/datagear-web/src/main/java/org/datagear/web/convert/AbstractDataConverter.java +++ b/datagear-web/src/main/java/org/datagear/web/convert/AbstractDataConverter.java @@ -293,11 +293,11 @@ public abstract class AbstractDataConverter /** * 将{@linkplain #REF_NAME}的值解析为引用目标对象。 * - * @param ref * @param refContext + * @param ref * @return */ - protected Object resolveRefTarget(String ref, RefContext refContext) + protected Object resolveRefTarget(RefContext refContext, String ref) { if (REF_VALUE_ROOT.equals(ref)) return refContext.getRoot(); @@ -603,6 +603,8 @@ public abstract class AbstractDataConverter private Map pathObjects = new HashMap(); + private Map lazyRefs = new HashMap(); + public RefContext() { super(); @@ -650,5 +652,20 @@ public abstract class AbstractDataConverter if (REF_VALUE_ROOT.equals(path)) this.root = object; } + + public boolean hasLazyRefs() + { + return (this.lazyRefs != null && !this.lazyRefs.isEmpty()); + } + + public Map getLazyRefs() + { + return lazyRefs; + } + + public void addLazyRefs(String path, String refValue) + { + this.lazyRefs.put(path, refValue); + } } } diff --git a/datagear-web/src/main/java/org/datagear/web/convert/ClassDataConverter.java b/datagear-web/src/main/java/org/datagear/web/convert/ClassDataConverter.java index 21120ade..8d542590 100644 --- a/datagear-web/src/main/java/org/datagear/web/convert/ClassDataConverter.java +++ b/datagear-web/src/main/java/org/datagear/web/convert/ClassDataConverter.java @@ -45,7 +45,13 @@ public class ClassDataConverter extends AbstractDataConverter */ public T convert(Object obj, Class type) throws ConverterException { - return convertObj(null, obj, type, new RefContext()); + RefContext refContext = new RefContext(); + + T target = convertObj(null, obj, type, refContext); + + handleLazyRefs(target, refContext); + + return target; } /** @@ -58,7 +64,13 @@ public class ClassDataConverter extends AbstractDataConverter */ public T[] convertToArray(Object obj, Class type) throws ConverterException { - return convertObjToArray(null, obj, type, new RefContext()); + RefContext refContext = new RefContext(); + + T[] target = convertObjToArray(null, obj, type, refContext); + + handleLazyRefs(target, refContext); + + return target; } /** @@ -73,7 +85,13 @@ public class ClassDataConverter extends AbstractDataConverter public Collection convertToCollection(Object obj, Class type, Class collectionType) throws ConverterException { - return convertObjToCollection(null, obj, type, collectionType, new RefContext()); + RefContext refContext = new RefContext(); + + Collection target = convertObjToCollection(null, obj, type, collectionType, refContext); + + handleLazyRefs(target, refContext); + + return target; } /** @@ -137,9 +155,18 @@ public class ClassDataConverter extends AbstractDataConverter if (isRefMap(map)) { - String ref = getRefValue(map); + String refValue = getRefValue(map); + Object refTarget = resolveRefTarget(refContext, refValue); - return (T) resolveRefTarget(ref, refContext); + // 引用有可能在目标未被解析前先被处理,此时需要延迟处理 + if (refTarget != null) + return (T) refTarget; + else + { + refContext.addLazyRefs(namePath, refValue); + + return null; + } } T re = createInstance(type); @@ -513,6 +540,121 @@ public class ClassDataConverter extends AbstractDataConverter return re; } + /** + * 处理延迟引用。 + * + * @param obj + * @param refContext + */ + protected void handleLazyRefs(Object obj, RefContext refContext) + { + if (obj == null) + return; + + if (!refContext.hasLazyRefs()) + return; + + Map lazyRefs = refContext.getLazyRefs(); + + for (Map.Entry entry : lazyRefs.entrySet()) + { + String refValue = entry.getValue(); + + Object target = resolveRefTarget(refContext, refValue); + + if (target != null) + { + PropertyPath propertyPath = PropertyPath.valueOf(entry.getKey()); + + setValue(obj, propertyPath, target); + } + } + } + + /** + * 设置对象属性值。 + * + * @param obj + * @param propertyPath + * @param value + */ + @SuppressWarnings("unchecked") + protected void setValue(Object obj, PropertyPath propertyPath, Object value) + { + Object owner = obj; + + for (int i = 0, len = propertyPath.length(); i < len; i++) + { + if (owner == null) + throw new ConverterException("The owner object of index [" + i + "] must not be null"); + + if (i == len - 1) + { + if (owner instanceof Map) + { + if (!propertyPath.isProperty(i)) + throw new ConverterException("The " + i + "-th must be property of [" + propertyPath + "]"); + + ((Map) owner).put(propertyPath.getPropertyName(i), value); + } + else if (owner instanceof Object[]) + { + if (!propertyPath.isElement(i)) + throw new ConverterException("The " + i + "-th must be element of [" + propertyPath + "]"); + + ((Object[]) owner)[propertyPath.getElementIndex(i)] = value; + } + else if (owner instanceof List) + { + if (!propertyPath.isElement(i)) + throw new ConverterException("The " + i + "-th must be element of [" + propertyPath + "]"); + + ((List) owner).set(propertyPath.getElementIndex(i), value); + } + else + { + if (!propertyPath.isProperty(i)) + throw new ConverterException("The " + i + "-th must be property of [" + propertyPath + "]"); + + BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(owner); + beanWrapper.setPropertyValue(propertyPath.getPropertyName(i), value); + } + } + else + { + if (owner instanceof Map) + { + if (!propertyPath.isProperty(i)) + throw new ConverterException("The " + i + "-th must be property of [" + propertyPath + "]"); + + owner = ((Map) owner).get(propertyPath.getPropertyName(i)); + } + else if (owner instanceof Object[]) + { + if (!propertyPath.isElement(i)) + throw new ConverterException("The " + i + "-th must be element of [" + propertyPath + "]"); + + owner = ((Object[]) owner)[propertyPath.getElementIndex(i)]; + } + else if (owner instanceof List) + { + if (!propertyPath.isElement(i)) + throw new ConverterException("The " + i + "-th must be element of [" + propertyPath + "]"); + + owner = ((List) owner).get(propertyPath.getElementIndex(i)); + } + else + { + if (!propertyPath.isProperty(i)) + throw new ConverterException("The " + i + "-th must be property of [" + propertyPath + "]"); + + BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(owner); + owner = beanWrapper.getPropertyValue(propertyPath.getPropertyName(i)); + } + } + } + } + /** * 获取属性类型信息。 *

diff --git a/datagear-web/src/main/java/org/datagear/web/convert/ModelDataConverter.java b/datagear-web/src/main/java/org/datagear/web/convert/ModelDataConverter.java index 4337e0c7..37c31495 100644 --- a/datagear-web/src/main/java/org/datagear/web/convert/ModelDataConverter.java +++ b/datagear-web/src/main/java/org/datagear/web/convert/ModelDataConverter.java @@ -17,9 +17,9 @@ import org.datagear.model.support.DefaultDynamicBean; import org.datagear.model.support.MU; import org.datagear.model.support.PropertyModel; import org.datagear.model.support.PropertyPath; +import org.datagear.model.support.PropertyPathInfo; import org.datagear.persistence.collection.SizeOnlyCollection; -import org.datagear.persistence.mapper.Mapper; -import org.datagear.persistence.mapper.RelationMapper; +import org.datagear.persistence.support.PMU; import org.springframework.core.convert.ConversionService; /** @@ -50,7 +50,13 @@ public class ModelDataConverter extends AbstractDataConverter */ public Object convert(Object obj, Model model) throws ConverterException { - return convertObj(null, obj, model, new RefContext()); + RefContext refContext = new RefContext(); + + Object target = convertObj(null, obj, model, refContext); + + handleLazyRefs(model, target, refContext); + + return target; } /** @@ -63,7 +69,13 @@ public class ModelDataConverter extends AbstractDataConverter */ public Object[] convertToArray(Object obj, Model model) throws ConverterException { - return convertObjToArray(null, obj, model, new RefContext()); + RefContext refContext = new RefContext(); + + Object[] target = convertObjToArray(null, obj, model, refContext); + + handleLazyRefs(model, target, refContext); + + return target; } /** @@ -78,7 +90,46 @@ public class ModelDataConverter extends AbstractDataConverter public Collection convertToCollection(Object obj, Model model, Class collectionType) throws ConverterException { - return convertObjToCollection(null, obj, model, collectionType, new RefContext()); + RefContext refContext = new RefContext(); + + Collection target = convertObjToCollection(null, obj, model, collectionType, refContext); + + handleLazyRefs(model, target, refContext); + + return target; + } + + /** + * 处理延迟引用。 + * + * @param model + * @param obj + * @param refContext + */ + protected void handleLazyRefs(Model model, Object obj, RefContext refContext) + { + if (obj == null) + return; + + if (!refContext.hasLazyRefs()) + return; + + Map lazyRefs = refContext.getLazyRefs(); + + for (Map.Entry entry : lazyRefs.entrySet()) + { + String refValue = entry.getValue(); + + Object target = resolveRefTarget(refContext, refValue); + + if (target != null) + { + PropertyPathInfo propertyPathInfo = PropertyPathInfo.valueOf(model, + PropertyPath.valueOf(entry.getKey()), obj); + + propertyPathInfo.setValueTail(target); + } + } } /** @@ -137,8 +188,18 @@ public class ModelDataConverter extends AbstractDataConverter if (isRefMap(map)) { - String ref = getRefValue(map); - return resolveRefTarget(ref, refContext); + String refValue = getRefValue(map); + Object refTarget = resolveRefTarget(refContext, refValue); + + // 引用有可能在目标未被解析前先被处理,此时需要延迟处理 + if (refTarget != null) + return refTarget; + else + { + refContext.addLazyRefs(namePath, refValue); + + return null; + } } Object re = model.newInstance(); @@ -191,7 +252,7 @@ public class ModelDataConverter extends AbstractDataConverter value = convertObj(myFullPropertyPath, rawValue, pmodel, refContext); } - setPropertyValue(pmodel, property, propertyModel, re, value); + setPropertyValue(model, property, propertyModel, re, value); } return re; @@ -579,55 +640,6 @@ public class ModelDataConverter extends AbstractDataConverter protected void setPropertyValue(Model model, Property property, PropertyModel propertyModel, Object obj, Object propertyValue) { - Model pmodel = propertyModel.getModel(); - - if (propertyValue == null) - { - if (pmodel.getType().isPrimitive()) - ; - else - property.set(obj, null); - } - else if (MU.isPrimitiveModel(pmodel)) - { - property.set(obj, propertyValue); - } - else - { - property.set(obj, propertyValue); - - RelationMapper relationMapper = property.getFeature(RelationMapper.class); - Mapper mapper = relationMapper.getMappers()[propertyModel.getIndex()]; - - String mappedTarget = null; - if (mapper.isMappedBySource()) - mappedTarget = mapper.getMappedByTarget(); - else if (mapper.isMappedByTarget()) - mappedTarget = mapper.getMappedBySource(); - - // 反向设置属性值 - if (mappedTarget != null) - { - Property mappedProperty = MU.getProperty(pmodel, mappedTarget); - - if (property.isCollection()) - { - @SuppressWarnings("unchecked") - Collection collection = (Collection) propertyValue; - - for (Object ele : collection) - mappedProperty.set(ele, obj); - } - else if (property.isArray()) - { - Object[] array = (Object[]) propertyValue; - - for (Object ele : array) - mappedProperty.set(ele, obj); - } - else - mappedProperty.set(propertyValue, obj); - } - } + PMU.setPropertyValue(model, property, propertyModel, obj, propertyValue); } }