| Summary: | Model resolution causes IllegalValueExceptions in comparisons | ||
|---|---|---|---|
| Product: | [Modeling] EMFCompare | Reporter: | Andreas Mayer <anma-e> |
| Component: | UI | Assignee: | EMF Compare <emf.compare-inbox> |
| Status: | RESOLVED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | abuzila, laurent.delaigue, laurent.goubet |
| Version: | 3.1.0 | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Windows NT | ||
| See Also: |
https://bugs.eclipse.org/bugs/show_bug.cgi?id=487119 https://git.eclipse.org/r/72942 https://git.eclipse.org/r/73258 https://git.eclipse.org/c/emfcompare/org.eclipse.emf.compare.git/commit/?id=cc727ea40711b293accea0337cfc32272151cd36 https://git.eclipse.org/c/emfcompare/org.eclipse.emf.compare.git/commit/?id=ca3b2c3a9cbc698838c64f17d6cf06bc83d514d3 |
||
| Whiteboard: | |||
| Attachments: | |||
Created attachment 254722 [details]
Example project to demonstrate the problem
The attached archive contains a small project that demonstrates the problem. The project contains an Ecore file and a GenModel with the following definitions:
package ui
class UI {
contains Menu[] menus
contains Command[] commands
}
abstract class MenuItem {
String name
}
class Menu extends MenuItem {
refers MenuItem[] items
}
class Command extends MenuItem {
}
In addition, the project contains one of the problematic instances ("example.ui") and a class ("Demo") that loads this instance first with a plain ResourceSetImpl (which completes without any error) and then with a SynchronizedResourceSet, which results in lots of InvalidValueExceptions.
Created attachment 254723 [details]
Output (including stacktraces) of the example project
Created attachment 254796 [details]
Example model to demonstrate the problem
Here is a very small Ecore model, which causes the same problem. Just place it in a folder along with two arbitrary EMF models A and B and compare A and B. The comparison editor will open with the "Problems" tab and show several InvalidValueExceptions in "trouble.ecore".
Here is what happens: In EClass "1" in trouble.ecore, we have the many-reference eSuperTypes a with forward reference to "0" and backward references to "2"..."7". When this many-reference is parsed with a SynchronizedResourceSet, at some point we will have the following call stack: NotifyingParserPool$NotifyingXMLHelper.setValue(EObject, EStructuralFeature, Object, int) line: 242 SAXXMIHandler(XMLHandler).setFeatureValue(EObject, EStructuralFeature, Object, int) line: 2692 SAXXMIHandler(XMLHandler).setFeatureValue(EObject, EStructuralFeature, Object) line: 2682 SAXXMIHandler(XMLHandler).setValueFromId(EObject, EReference, String) line: 2853 SAXXMIHandler(XMLHandler).setAttribValue(EObject, String, String) line: 2755 SAXXMIHandler.handleObjectAttribs(EObject) line: 74 ... setValueFromId() parses the reference ids, calls XMLHelper.setValue() for each backward reference (for which the EClasses have already been created) and collects all forward references (for which there are no EClasses yet) in a ManyReference. A ManyReference basically holds the reference owner, the reference feature, the values to be added to the feature, and the insertion points for those values. When the end of the document is reached, XMLHandler.handleForwardReferences(boolean) resolves all ManyReferences and inserts the resolved values into the corresponding features (which may or may not already contain values from backward references). Unfortunately, SynchronizedResourceSet (see line 92) uses a NotifyingParserPool with containmentOnly = true, in which case NotifyingParserPool.NotifyingXMLHelper.setValue() ignores the values of all non-containment features. So the values for the backward references are never being added to eSuperTypes. Because of this, when the values for the forward references are being inserted, the computed insertion points in the ManyReference objects are off and cause ArrayIndexOutOfBoundsExceptions. This should be changed: org.eclipse.emf.compare.ide.internal.utils.NotifyingParserPool.NotifyingXMLHelper.setValue(EObject, EStructuralFeature, Object, int) must always call its super implementation (maybe you can ignore attributes, which are no feature maps). Hi Andreas, Sorry for the late reply, this bug and a few others had been somehow swept in my junk mails. As you've noticed, our resource set implementation ignores a lot of things to try and load the models as fast as possible (we're disposing of these "partially loaded" models soon after, we're only doing this to determine the cross-resource references). We did not, however, expect failures with feature maps (I guess this bug is using them). We'll try and check this as soon as possible, thanks for the sample models, this will help a lot. (In reply to Laurent Goubet from comment #5) > We did not, however, expect failures with > feature maps (I guess this bug is using them). No feature maps are involved here. SynchronizedResourceSet tries to take a shortcut (because you only want to follow external references and not actually load the model), which is not viable (see #4). (In reply to Andreas Mayer from comment #3) > Here is a very small Ecore model, which causes the same problem. Just place > it in a folder along with two arbitrary EMF models A and B and compare A and > B. The comparison editor will open with the "Problems" tab and show several > InvalidValueExceptions in "trouble.ecore". This particular problem (displaying of errors from resources unrelated to the comparison) will be taken care of with bug 487119. (In reply to Alexandra Buzila from comment #7) > This particular problem (displaying of errors from resources unrelated to > the comparison) will be taken care of with bug 487119. The actual problem is the ArrayIndexOutOfBoundsException in the model resolution. This is caused by the fact that for certain features NotifyingParserPool skips setValue(), which is called for values resolved from backward references (referenced value is defined before the reference in the XMI file), but not setManyReference(), which is called for values resolved from forward references (referenced value is defined after the reference in the XMI file). setManyReference() then tries to insert values at specific insertion points, which are out of bounds, because the expected values for the backward references aren't there. I've now created a Gerrit change (https://git.eclipse.org/r/72942) that fixes this. The fix for bug 487119 only suppresses this issue if the offending model is not involved in the comparison. However, if you compare the model in attachment 254796 [details] (which is totally valid, by the way) with any other Ecore model, these spurious errors still pop up in the UI. New Gerrit change created: https://git.eclipse.org/r/72942 New Gerrit change created: https://git.eclipse.org/r/73258 Gerrit change https://git.eclipse.org/r/72942 was merged to [master]. Commit: http://git.eclipse.org/c/emfcompare/org.eclipse.emf.compare.git/commit/?id=cc727ea40711b293accea0337cfc32272151cd36 Gerrit change https://git.eclipse.org/r/73258 was merged to [3.2]. Commit: http://git.eclipse.org/c/emfcompare/org.eclipse.emf.compare.git/commit/?id=ca3b2c3a9cbc698838c64f17d6cf06bc83d514d3 This has been fixed by the related commit. |
Created attachment 254719 [details] Screenshot of a comparison with Eclipse Modeling Tools (Mars) This bug affects versions newer than 3.1.0.201410060749. At least that is the last version that didn't show this issue. For one of our Ecore models there are completely valid instances that cause IllegalValueExceptions during comparisons, even if totally different models are compared (see attached screenshot). These instances just have to be in the same folder as the models being compared. The comparison itself is not affected and provides a correct result. However, the exceptions are collected and shown in the comparison editor's problems tab. So you have to switch to the differences tab to see the result. If the comparison is repeated, it usually will finish without any exceptions. The cause of this problem seems to be the model resolution, which runs in background threads named EMFCompare-ResolvingThread-?. These threads use a SynchronizedResourceSet to read models in order to compute dependencies. It seems to me that SynchronizedResourceSet behaves differently than EMF's plain ResourceSetImpl, which handles these problematic model instances just fine.