Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 399954

Summary: Copy/paste of UML2 models with stereotypes using EcoreUtil.Copier sometimes changes order of stereotype applications
Product: [Modeling] EMF Reporter: Alain Le Guennec <alain.leguennec>
Component: CoreAssignee: Ed Merks <Ed.Merks>
Status: CLOSED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: eclipse-bugzilla, Kenn.Hussey, rschnekenburger, sebastien.gerard
Version: 2.8.0   
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
Whiteboard:
Bug Depends on:    
Bug Blocks: 397324    

Description Alain Le Guennec CLA 2013-02-05 04:55:24 EST
In the context of the MDT/Papyrus project, EcoreUtil.Copier is used to implement copy/paste of UML2 model fragment including attached stereotype applications.
The copy/paste implementation uses EcoreUtil.Copier with the set of root UML2 elements to be copied, together with the set of stereotype applications applied to the corresponding subtrees (the stereotype applications themselves not being in the content tree proper, even if they logically belong there).

After copy/paste, it sometimes happens that stereotype applications pertaining to a given copied UML2 element are not in the same order as the corresponding original stereotype applications, even though the stereotype applications are passed to the Copier in the right (partial) order.
The problem is only transient, in memory, and disappears if the model is saved then reloaded (the copied stereotype applications are in the "right" order in the XMI files).

It seems like this is due to EcoreUtil.Copier#copyReferences():
Indeed, this function iterates over the entry set of the underlying hashmap to transpose the references into the copied trees, which includes the special "base_<metaclass>" references of the stereotype applications.
However, the Copier being based on a HashMap, the entry set order is undefined, and therefore the "base_<metaclass>" references can be set in any order, not necessarily the order into which the stereotype applications were passed to the Copier.
As a consequence, the pseudo inverse non-navigable reference as returned by Element.getStereotypeApplications() does not reflect the original order.
Even if the order of stereotype applications is not supposed to be relevant,
it is actually sometimes used to determine the icon to be used by the model navigator.
And so after copy/paste, some elements might change icons.

A simple solution for this issue would be for Copier#copyReferences() to set the references by considering the source objects in the target tree in the same order as the original objects were put in the Copier.

I think this would automatically be the case, would the Copier be based on LinkedHashMap instead of HashMap (as the iteration order on the entry set is the order in which the objects are put in the map for a LinkedHashMap). 
Maybe the Copier could switch to a LinkedHashMap implementation?
Or there could be an alternative Copier using LinkedHashMap?
Or the Copier could hide which Map implementation is used? (just implementing the Map interface, and delegate storage to a map member whose implementation class could be substituted).
Comment 1 Ed Merks CLA 2013-02-07 03:29:52 EST
Given that a LinkedHashMap extends HashMap, I could change the base class of the Copier without binary incompatibility.  In any "normal" model the order in which the references are copied are irrelevant, in the case of bidirectional references that can be modified from both ends, the code already checks if the reference has already been added and moves it to the right place.  It's not clear why that ordering process isn't working for the reference you mention.  Perhaps it's marked as derived so it's simply not copied at all.  Of course it's possible to specialize the copier, so one could specialize it to iterate over the copied objects to modify the order of this feature in the copy to match that of the order in original.  That seems better than relying on some type of ordering in the copier...

I'd like Kenn's opinion before I make any changes that aren't based on a test case I can evaluate.
Comment 2 Kenn Hussey CLA 2013-02-08 23:39:48 EST
(In reply to comment #1)
> I'd like Kenn's opinion before I make any changes that aren't based on a
> test case I can evaluate.

I think it would be great if the Copier were a LinkedHashMap; indeed, UML2 has at least one case where ugly overrides had to be added to work around a similar issue.
Comment 4 Ed Merks CLA 2013-07-10 11:27:40 EDT
The changes are available in Kepler.