解决编辑集合属性值元素时,元素的引用属性值无法保存的问题,原因:后台处理参数转换时,没有延迟处理循环引用

This commit is contained in:
datagear 2019-01-23 10:09:21 +08:00
parent 9085fd981b
commit 7532ef0426
5 changed files with 333 additions and 70 deletions

View File

@ -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);
}
/**
* 设置属性值
* <p>
* 此方法会处理{@linkplain MappedBy}双向关联反向赋值
* </p>
* <p>
* 注意此方法不会处理反向集合属性因为此时obj仅是反向集合中的单个元素
* </p>
*
* @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<Object> collection = (Collection<Object>) 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);
}
}
}
}

View File

@ -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;

View File

@ -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<String, Object> pathObjects = new HashMap<String, Object>();
private Map<String, String> lazyRefs = new HashMap<String, String>();
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<String, String> getLazyRefs()
{
return lazyRefs;
}
public void addLazyRefs(String path, String refValue)
{
this.lazyRefs.put(path, refValue);
}
}
}

View File

@ -45,7 +45,13 @@ public class ClassDataConverter extends AbstractDataConverter
*/
public <T> T convert(Object obj, Class<T> 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> T[] convertToArray(Object obj, Class<T> 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 <T> Collection<T> convertToCollection(Object obj, Class<T> type, Class<? extends Collection> collectionType)
throws ConverterException
{
return convertObjToCollection(null, obj, type, collectionType, new RefContext());
RefContext refContext = new RefContext();
Collection<T> 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<String, String> lazyRefs = refContext.getLazyRefs();
for (Map.Entry<String, String> 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<String, Object>) 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<Object>) 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<String, Object>) 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<Object>) 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));
}
}
}
}
/**
* 获取属性类型信息
* <p>

View File

@ -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<Object> convertToCollection(Object obj, Model model, Class<? extends Collection> collectionType)
throws ConverterException
{
return convertObjToCollection(null, obj, model, collectionType, new RefContext());
RefContext refContext = new RefContext();
Collection<Object> 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<String, String> lazyRefs = refContext.getLazyRefs();
for (Map.Entry<String, String> 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<Object> collection = (Collection<Object>) 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);
}
}