mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2026-09-16 18:13:17 +00:00
This commit is contained in:
+2
-2
@@ -1250,7 +1250,7 @@
|
||||
"filename": "repository/src/main/resources/alfresco/repository.properties",
|
||||
"hashed_secret": "84551ae5442affc9f1a2d3b4c86ae8b24860149d",
|
||||
"is_verified": false,
|
||||
"line_number": 779,
|
||||
"line_number": 784,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
@@ -1845,5 +1845,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2026-05-07T12:42:51Z"
|
||||
"generated_at": "2026-05-12T12:14:02Z"
|
||||
}
|
||||
|
||||
@@ -115,6 +115,8 @@ public abstract class VersionServiceImpl extends AbstractVersionServiceImpl impl
|
||||
|
||||
protected Comparator<Version> versionComparatorDesc;
|
||||
|
||||
protected boolean preserveUnsetProperties;
|
||||
|
||||
/**
|
||||
* Sets the db node service, used as the version store implementation
|
||||
*
|
||||
@@ -164,13 +166,21 @@ public abstract class VersionServiceImpl extends AbstractVersionServiceImpl impl
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException(
|
||||
"Failed to create a Comparator<Version> using the class name " +
|
||||
versionComparatorClass,
|
||||
e);
|
||||
"Failed to create a Comparator<Version> using the class name " + versionComparatorClass, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setPreserveUnsetProperties(boolean preserveUnsetProperties)
|
||||
{
|
||||
this.preserveUnsetProperties = preserveUnsetProperties;
|
||||
}
|
||||
|
||||
public boolean isPreserveUnsetProperties()
|
||||
{
|
||||
return preserveUnsetProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register version label policy for the specified type
|
||||
*
|
||||
@@ -1400,10 +1410,14 @@ public abstract class VersionServiceImpl extends AbstractVersionServiceImpl impl
|
||||
{
|
||||
// Copy the properties (along with their aspect)
|
||||
Map<QName, PropertyDefinition> propertyDefinitions = classDefinition.getProperties();
|
||||
Map<QName, Serializable> sourceProperties = this.nodeService.getProperties(nodeRef);
|
||||
for (QName propertyName : propertyDefinitions.keySet())
|
||||
{
|
||||
Serializable propValue = this.nodeService.getProperty(nodeRef, propertyName);
|
||||
nodeDetails.addProperty(classRef, propertyName, propValue);
|
||||
Serializable propValue = sourceProperties.get(propertyName);
|
||||
if (sourceProperties.containsKey(propertyName) || !isPreserveUnsetProperties())
|
||||
{
|
||||
nodeDetails.addProperty(classRef, propertyName, propValue);
|
||||
}
|
||||
}
|
||||
// Also copy the aspect with no properties in its definition
|
||||
if (classDefinition.isAspect() && !nodeDetails.getAspects().contains(classRef))
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
<property name="useVersionAssocIndex">
|
||||
<value>${version.store.useVersionAssocIndex}</value>
|
||||
</property>
|
||||
<property name="preserveUnsetProperties">
|
||||
<value>${version.store.preserveUnsetProperties}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="versionNodeService" class="org.alfresco.repo.version.Node2ServiceImpl">
|
||||
|
||||
@@ -399,6 +399,11 @@ version.store.versionComparatorClass=
|
||||
# Please, see MNT-22715 for details.
|
||||
version.store.useVersionAssocIndex=false
|
||||
|
||||
# Optional to preserve unset properties when creating a new version. With this setting enabled,
|
||||
# we no longer set all optional properties as null on the version node and preserve the unset
|
||||
# properties from the source instead.
|
||||
version.store.preserveUnsetProperties=false
|
||||
|
||||
# Folders for storing people
|
||||
system.system_container.childname=sys:system
|
||||
system.people_container.childname=sys:people
|
||||
|
||||
@@ -3224,4 +3224,124 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* With preserveUnsetProperties disabled (default), a type property that was never set on the source node (and has no model default) is still written to the version node with a null value.
|
||||
*/
|
||||
@Test
|
||||
public void testPreserveUnsetPropertiesDisabled()
|
||||
{
|
||||
// MULTI_PROP has no <default> in the model so it is absent when not set
|
||||
NodeRef node = createNodeWithoutMultiProp();
|
||||
|
||||
Version version = this.versionService.createVersion(node, this.versionProperties);
|
||||
|
||||
Map<QName, Serializable> frozenProps = dbNodeService.getProperties(VersionUtil.convertNodeRef(version.getFrozenStateNodeRef()));
|
||||
assertTrue("PROP_1 should be in the version node", frozenProps.containsKey(PROP_1));
|
||||
assertEquals("PROP_1 value should match source", VALUE_1, frozenProps.get(PROP_1));
|
||||
assertTrue("Unset MULTI_PROP should be present in the version node with null value when preserveUnsetProperties is disabled", frozenProps.containsKey(MULTI_PROP));
|
||||
assertNull("MULTI_PROP value should be null in the version node", frozenProps.get(MULTI_PROP));
|
||||
}
|
||||
|
||||
/**
|
||||
* With preserveUnsetProperties enabled, a type property that was never set on the source node (and has no model default) is omitted from the version node entirely.
|
||||
*/
|
||||
@Test
|
||||
public void testPreserveUnsetPropertiesEnabled()
|
||||
{
|
||||
VersionServiceImpl versionServiceImpl = (VersionServiceImpl) versionService;
|
||||
versionServiceImpl.setPreserveUnsetProperties(true);
|
||||
try
|
||||
{
|
||||
NodeRef node = createNodeWithoutMultiProp();
|
||||
|
||||
Version version = this.versionService.createVersion(node, this.versionProperties);
|
||||
|
||||
Map<QName, Serializable> frozenProps = dbNodeService.getProperties(VersionUtil.convertNodeRef(version.getFrozenStateNodeRef()));
|
||||
assertTrue("PROP_1 should be in the version node", frozenProps.containsKey(PROP_1));
|
||||
assertEquals("PROP_1 value should match source", VALUE_1, frozenProps.get(PROP_1));
|
||||
assertFalse("Unset MULTI_PROP should be absent from the version node when preserveUnsetProperties is enabled", frozenProps.containsKey(MULTI_PROP));
|
||||
}
|
||||
finally
|
||||
{
|
||||
versionServiceImpl.setPreserveUnsetProperties(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* With preserveUnsetProperties enabled, a property that IS explicitly set on the source node is still copied to the version node.
|
||||
*/
|
||||
@Test
|
||||
public void testPreserveUnsetPropertiesEnabledCopiesSetProperties()
|
||||
{
|
||||
VersionServiceImpl versionServiceImpl = (VersionServiceImpl) versionService;
|
||||
versionServiceImpl.setPreserveUnsetProperties(true);
|
||||
try
|
||||
{
|
||||
NodeRef node = createNodeWithoutMultiProp();
|
||||
dbNodeService.setProperty(node, MULTI_PROP, (Serializable) multiValue);
|
||||
|
||||
Version version = this.versionService.createVersion(node, this.versionProperties);
|
||||
|
||||
Map<QName, Serializable> frozenProps = dbNodeService.getProperties(VersionUtil.convertNodeRef(version.getFrozenStateNodeRef()));
|
||||
assertTrue("MULTI_PROP should be in the version node when explicitly set on source", frozenProps.containsKey(MULTI_PROP));
|
||||
assertEquals("MULTI_PROP value should match source", multiValue, frozenProps.get(MULTI_PROP));
|
||||
}
|
||||
finally
|
||||
{
|
||||
versionServiceImpl.setPreserveUnsetProperties(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverting a version must not set null for properties that were never set on the source node when preserveUnsetProperties is enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testPreserveUnsetPropertiesEnabledRevertDoesNotWriteNullForUnsetProperties()
|
||||
{
|
||||
VersionServiceImpl versionServiceImpl = (VersionServiceImpl) versionService;
|
||||
versionServiceImpl.setPreserveUnsetProperties(true);
|
||||
try
|
||||
{
|
||||
// Create a node where MULTI_PROP was never set (no model default either)
|
||||
NodeRef node = createNodeWithoutMultiProp();
|
||||
|
||||
// Version 1: MULTI_PROP is absent
|
||||
Version version1 = this.versionService.createVersion(node, this.versionProperties);
|
||||
|
||||
// Modify the source node so it differs from version 1
|
||||
this.dbNodeService.setProperty(node, PROP_1, UPDATED_VALUE_1);
|
||||
|
||||
// Revert back to version 1
|
||||
this.versionService.revert(node, version1);
|
||||
|
||||
// MULTI_PROP must remain truly absent — not present with a null value — after the revert
|
||||
Map<QName, Serializable> propsAfterRevert = dbNodeService.getProperties(node);
|
||||
assertFalse(
|
||||
"MULTI_PROP must not be written back as null when reverting to a version where it was never set and preserveUnsetProperties is enabled",
|
||||
propsAfterRevert.containsKey(MULTI_PROP));
|
||||
}
|
||||
finally
|
||||
{
|
||||
versionServiceImpl.setPreserveUnsetProperties(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a versionable node with PROP_1 set but MULTI_PROP never set. MULTI_PROP has no model default so it will not be present when doing getProperties().
|
||||
*/
|
||||
private NodeRef createNodeWithoutMultiProp()
|
||||
{
|
||||
Map<QName, Serializable> props = new HashMap<>();
|
||||
props.put(PROP_1, VALUE_1);
|
||||
props.put(ContentModel.PROP_CONTENT, new ContentData(null, "text/plain", 0L, "UTF-8"));
|
||||
NodeRef node = dbNodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}preserveUnsetPropsNode"),
|
||||
TEST_TYPE_QNAME,
|
||||
props).getChildRef();
|
||||
dbNodeService.addAspect(node, ContentModel.ASPECT_VERSIONABLE, new HashMap<>());
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user