Community
Participate
Working Groups
Build Identifier: 2.5.0.v200906151043 I'm using a (slightly) modified ChangeRecorder and ChangeDescription and I'm currently facing an issue that sounds to me as a bug in the EMF change model. As far as I know, it should be possible to call applyAndReverse repeatedly and the model would switch repeatedly between 2 states. Calling applyAndReverse twice should give me the exact same model as in the initial state. In order to track down the problem, I created a dummy model: <?xml version="1.0" encoding="UTF-8"?> <ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="test" nsURI="http://www.ruag.com/test/v1" nsPrefix=""> <eClassifiers xsi:type="ecore:EClass" name="A"> <eStructuralFeatures xsi:type="ecore:EReference" name="elements" upperBound="-1" eType="#//B" containment="true"/> </eClassifiers> <eClassifiers xsi:type="ecore:EClass" name="B"> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> <eStructuralFeatures xsi:type="ecore:EReference" name="children" upperBound="-1" eType="#//B" containment="true"/> </eClassifiers> </ecore:EPackage> Here comes the example: <?xml version="1.0" encoding="ASCII"?> <xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="http://www.ruag.com/test/v1" xmlns:change="http://www.eclipse.org/emf/2003/Change"> <A> <elements name="B group"> <children name="B0"/> <children name="B1"/> <children name="B2"/> <children name="B3"/> </elements> </A> <change:ChangeDescription> <objectChanges key="/0"> <value featureName="elements"> <listChanges index="0" referenceValues="/0/@elements.0/@children.0"/> <listChanges index="1" referenceValues="/0/@elements.0/@children.1"/> <listChanges index="2" referenceValues="/0/@elements.0/@children.2"/> <listChanges index="3" referenceValues="/0/@elements.0/@children.3"/> <listChanges kind="REMOVE" index="4"/> </value> </objectChanges> </change:ChangeDescription> </xmi:XMI> applyAndReverse <?xml version="1.0" encoding="ASCII"?> <xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.ruag.com/test/v1" xmlns:change="http://www.eclipse.org/emf/2003/Change"> <A> <elements name="B0"/> <elements name="B1"/> <elements name="B2"/> <elements name="B3"/> </A> <change:ChangeDescription> <objectChanges key="/0"> <value featureName="elements"> <listChanges index="4" referenceValues="/1/@objectsToAttach.0"/> <listChanges kind="REMOVE" index="3"/> <listChanges kind="REMOVE" index="2"/> <listChanges kind="REMOVE" index="1"/> <listChanges kind="REMOVE" index="0"/> </value> </objectChanges> <objectsToAttach xsi:type="B" name="B group"/> </change:ChangeDescription> </xmi:XMI> applyAndReverse <?xml version="1.0" encoding="ASCII"?> <xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.ruag.com/test/v1" xmlns:change="http://www.eclipse.org/emf/2003/Change"> <A> <elements name="B group"/> </A> <change:ChangeDescription> <objectChanges key="/0"> <value featureName="elements"> <listChanges index="0" referenceValues="/1/@objectsToAttach.0"/> <listChanges index="1" referenceValues="/1/@objectsToAttach.1"/> <listChanges index="2" referenceValues="/1/@objectsToAttach.2"/> <listChanges index="3" referenceValues="/1/@objectsToAttach.3"/> <listChanges kind="REMOVE" index="4"/> </value> </objectChanges> <objectsToAttach xsi:type="B" name="B0"/> <objectsToAttach xsi:type="B" name="B1"/> <objectsToAttach xsi:type="B" name="B2"/> <objectsToAttach xsi:type="B" name="B3"/> </change:ChangeDescription> </xmi:XMI> The change description after the first call to applyAndReverse seems to miss some information. And as you can see, after the second call to applyAndReverse, "B group" loses definitely its children :-( I observe the same behaviour in our model. Reproducible: Always
Created attachment 166752 [details] Test case that shows this issue The attached .zip is an Eclipse project.
There's definitely an issue with removing objects attached to the observed tree and adding those to something outside of the tree and then finally adding that external object to the tree. In particular, no changes are recorded about the how those removed objects are attached to the external object. A different order of processing improves the situation: List<B> elements = new ArrayList<B>(_root.getElements()); _root.getElements().add(b); b.getChildren().addAll(elements); So that's a good workaround until the problem is fixed. I.e., add the object that will be modified to the tree before modifying it. The problem looks pretty tricky to fix. :-(
Looking more closely, I'm not convinced it makes sense to try to fix this problem. The change recorder records changes to the initial set of objects and to any new objects added to the graph. It does not record changes made to objects that aren't part of the graph nor in particular, any changes made to such objects before they are part of the graph. A new object should either be immediately added to the graph before changing it, or it should be explicitly monitored by the change recorder in some other way, i.e., by adding the change recorder to its list of adapters. As such, I expect to return this as a permanent limitation, i.e., as won't fix.
I'll regard this as a permanent limitation. We can't track changes made to objects for which changes aren't being recorded.