| Summary: | QVTo: java.lang.UnsupportedOperationException (subsetting & redefining properties) | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Product: | [Modeling] QVTo | Reporter: | Nicolas Rouquette <nicolas.f.rouquette> | ||||||
| Component: | Engine | Assignee: | Project Inbox <mmt-qvt.operational-inbox> | ||||||
| Status: | NEW --- | QA Contact: | |||||||
| Severity: | normal | ||||||||
| Priority: | P3 | CC: | christopher.gerking, ed, serg.boyko2011 | ||||||
| Version: | unspecified | ||||||||
| Target Milestone: | --- | ||||||||
| Hardware: | Macintosh | ||||||||
| OS: | Mac OS X | ||||||||
| Whiteboard: | |||||||||
| Bug Depends on: | 433025 | ||||||||
| Bug Blocks: | |||||||||
| Attachments: |
|
||||||||
|
Description
Nicolas Rouquette
Created attachment 174548 [details]
A simple transformation showing a typical misuse of UML redefined properties
This particular transformation reflects a potential mistake a user can legitimately make. The error produced is absolutely unclear:
[qvto:transformation] !ENTRY org.eclipse.m2m.qvt.oml 4 0 2010-07-16 15:00:22.384
[qvto:transformation] !MESSAGE Unexpected runtime exception caught during execution
[qvto:transformation] !STACK 0
[qvto:transformation] java.lang.UnsupportedOperationException
[qvto:transformation] at org.eclipse.emf.common.util.BasicEList$UnmodifiableEList.clear(BasicEList.java:995)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEvaluationEnv.callSetter(QvtOperationalEvaluationEnv.java:532)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitAssignExp(QvtOperationalEvaluationVisitorImpl.java:411)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitAssignExp(QvtGenericEvaluationVisitor.java:341)
[qvto:transformation] at org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.impl.AssignExpImpl.accept(AssignExpImpl.java:404)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitObjectExp(QvtOperationalEvaluationVisitorImpl.java:948)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitObjectExp(QvtGenericEvaluationVisitor.java:406)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.ObjectExpImpl.accept(ObjectExpImpl.java:176)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitOperationBody(QvtOperationalEvaluationVisitorImpl.java:983)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitMappingBody(QvtOperationalEvaluationVisitorImpl.java:569)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitMappingBody(QvtGenericEvaluationVisitor.java:376)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.MappingBodyImpl.accept(MappingBodyImpl.java:122)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitMappingOperation(QvtOperationalEvaluationVisitorImpl.java:732)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitMappingOperation(QvtGenericEvaluationVisitor.java:386)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.MappingOperationImpl.accept(MappingOperationImpl.java:220)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.executeImperativeOperation(QvtOperationalEvaluationVisitorImpl.java:1613)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.doVisitOperationCallExp(QvtOperationalEvaluationVisitorImpl.java:638)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitOperationCallExp(QvtOperationalEvaluationVisitorImpl.java:597)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitMappingCallExp(QvtOperationalEvaluationVisitorImpl.java:587)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitMappingCallExp(QvtGenericEvaluationVisitor.java:381)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.MappingCallExpImpl.accept(MappingCallExpImpl.java:112)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitAssignExp(QvtOperationalEvaluationVisitorImpl.java:353)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitAssignExp(QvtGenericEvaluationVisitor.java:341)
[qvto:transformation] at org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.impl.AssignExpImpl.accept(AssignExpImpl.java:404)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitObjectExp(QvtOperationalEvaluationVisitorImpl.java:948)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitObjectExp(QvtGenericEvaluationVisitor.java:406)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.ObjectExpImpl.accept(ObjectExpImpl.java:176)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitOperationBody(QvtOperationalEvaluationVisitorImpl.java:983)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitMappingBody(QvtOperationalEvaluationVisitorImpl.java:569)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitMappingBody(QvtGenericEvaluationVisitor.java:376)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.MappingBodyImpl.accept(MappingBodyImpl.java:122)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitMappingOperation(QvtOperationalEvaluationVisitorImpl.java:732)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitMappingOperation(QvtGenericEvaluationVisitor.java:386)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.MappingOperationImpl.accept(MappingOperationImpl.java:220)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.executeImperativeOperation(QvtOperationalEvaluationVisitorImpl.java:1613)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.doVisitOperationCallExp(QvtOperationalEvaluationVisitorImpl.java:638)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitOperationCallExp(QvtOperationalEvaluationVisitorImpl.java:597)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitMappingCallExp(QvtOperationalEvaluationVisitorImpl.java:587)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitMappingCallExp(QvtGenericEvaluationVisitor.java:381)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.MappingCallExpImpl.accept(MappingCallExpImpl.java:112)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitOperationBody(QvtOperationalEvaluationVisitorImpl.java:983)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitEntryOperation(QvtOperationalEvaluationVisitorImpl.java:458)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitEntryOperation(QvtGenericEvaluationVisitor.java:485)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.EntryOperationImpl.accept(EntryOperationImpl.java:67)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.executeImperativeOperation(QvtOperationalEvaluationVisitorImpl.java:1613)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.runMainEntry(QvtOperationalEvaluationVisitorImpl.java:2126)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl$1.invoke(QvtOperationalEvaluationVisitorImpl.java:922)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.doVisitTransformation(QvtOperationalEvaluationVisitorImpl.java:896)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitModule(QvtOperationalEvaluationVisitorImpl.java:750)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitModule(QvtGenericEvaluationVisitor.java:396)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.expressions.impl.ModuleImpl.accept(ModuleImpl.java:632)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.runtime.project.QvtInterpretedTransformation.evaluate(QvtInterpretedTransformation.java:177)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.runtime.project.QvtInterpretedTransformation.run(QvtInterpretedTransformation.java:118)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.doLaunch(QvtLaunchConfigurationDelegateBase.java:184)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.runtime.ant.QvtoAntTransformationTask$1.run(QvtoAntTransformationTask.java:317)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.common.launch.SafeRunner$SameThreadRunner.run(SafeRunner.java:33)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.common.launch.SafeRunner$1.run(SafeRunner.java:26)
[qvto:transformation] at org.eclipse.m2m.internal.qvt.oml.runtime.ant.QvtoAntTransformationTask.execute(QvtoAntTransformationTask.java:325)
[qvto:transformation] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
[qvto:transformation] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[qvto:transformation] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[qvto:transformation] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[qvto:transformation] at java.lang.reflect.Method.invoke(Method.java:597)
[qvto:transformation] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
[qvto:transformation] at org.apache.tools.ant.Task.perform(Task.java:348)
[qvto:transformation] at org.apache.tools.ant.Target.execute(Target.java:357)
[qvto:transformation] at org.apache.tools.ant.Target.performTasks(Target.java:385)
[qvto:transformation] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1337)
[qvto:transformation] at org.apache.tools.ant.Project.executeTarget(Project.java:1306)
[qvto:transformation] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[qvto:transformation] at org.eclipse.ant.internal.core.ant.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
[qvto:transformation] at org.apache.tools.ant.Project.executeTargets(Project.java:1189)
[qvto:transformation] at org.eclipse.ant.internal.core.ant.InternalAntRunner.run(InternalAntRunner.java:662)
[qvto:transformation] at org.eclipse.ant.internal.core.ant.InternalAntRunner.run(InternalAntRunner.java:495)
[qvto:transformation] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[qvto:transformation] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[qvto:transformation] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[qvto:transformation] at java.lang.reflect.Method.invoke(Method.java:597)
[qvto:transformation] at org.eclipse.ant.core.AntRunner.run(AntRunner.java:378)
[qvto:transformation] at org.eclipse.ant.internal.launching.launchConfigurations.AntLaunchDelegate$1.run(AntLaunchDelegate.java:298)
[qvto:transformation] at java.lang.Thread.run(Thread.java:637)
[qvto:transformation] org.eclipse.m2m.internal.qvt.oml.evaluator.QvtRuntimeException: Unexpected runtime exception caught during execution
[qvto:transformation] at SetUnmodifiableCollection::toActivity(SetUnmodifiableCollection.qvto:20)
[qvto:transformation] at SetUnmodifiableCollection::toPackage(SetUnmodifiableCollection.qvto:7)
[qvto:transformation] at SetUnmodifiableCollection::main(SetUnmodifiableCollection.qvto:5)
Created attachment 174549 [details]
Proposed patch
With the proposed patch, the same transformation, when ran from Ant, will produce a more useful explanation:
[qvto:transformation] org.eclipse.m2m.internal.qvt.oml.evaluator.QvtRuntimeException: Cannot modify feature: uml::InvocationAction::argument
[qvto:transformation] at SetUnmodifiableCollection::toActivity(SetUnmodifiableCollection.qvto:20)
[qvto:transformation] at SetUnmodifiableCollection::toPackage(SetUnmodifiableCollection.qvto:7)
[qvto:transformation] at SetUnmodifiableCollection::main(SetUnmodifiableCollection.qvto:5)
I don't quite like the idea of detecting unmodifiable lists via instanceof. Isn't there a mechanism outside QVTo to make this error detectable at compile time by setting the feature to derived / not unsettable / not changeable ? By now there isn't even an UnsupportedOperationException because UnionEObjectEList overrides the throwing inside UnmodifiableEList.clear(). (In reply to Christopher Gerking from comment #3) > I don't quite like the idea of detecting unmodifiable lists via instanceof. I agree. The subsets/redefines EAnnotations are required to support the full capabilities of a UML model when manipulating an 'Ecore' instance. My first instinct is that this is crazy, but it is actually most of what the UML2 project is about, so it should 'just work'. When subsets are in use, the UML2 support requires that the most derived feature is used for write access. (At least this is my interpreation of a number of bugs that have occurred in Papyrus.) So it is just necessary to have a helper to analyze the EStructuralFeature and its EAnnotations. Then the error message might even identify the writeable candidates. UMLUtil may already have such a helper. [If you are really going to handle UML properly you will need to support 'redefines' and the new 'originalName' annotation so that the UML package is spelled 'UML' rather than 'uml'. It would be good to get this right, but I see it as low priority. Just possibly it will be easier if/when QVTo migrates to the Pivot model where this stuff is more helpfully modelled.] (In reply to Ed Willink from comment #4) > (In reply to Christopher Gerking from comment #3) > > I don't quite like the idea of detecting unmodifiable lists via instanceof. > > I agree. > > The subsets/redefines EAnnotations are required to support the full > capabilities of a UML model when manipulating an 'Ecore' instance. > > My first instinct is that this is crazy, but it is actually most of what the > UML2 project is about, so it should 'just work'. > > When subsets are in use, the UML2 support requires that the most derived > feature is used for write access. (At least this is my interpreation of a > number of bugs that have occurred in Papyrus.) So it is just necessary to > have a helper to analyze the EStructuralFeature and its EAnnotations. Then > the error message might even identify the writeable candidates. UMLUtil may > already have such a helper. > > [If you are really going to handle UML properly you will need to support > 'redefines' and the new 'originalName' annotation so that the UML package is > spelled 'UML' rather than 'uml'. > > It would be good to get this right, but I see it as low priority. Just > possibly it will be easier if/when QVTo migrates to the Pivot model where > this stuff is more helpfully modelled.] I also don't like to use 'instanceof' for detecting read-only properties. However the analysis of given script shows: 1. Class UMLUtil defines properties for "subsets" and "redefines" annotations (protected static final String ANNOTATION__REDEFINES = "redefines"). Those properties are referenced only in UMLUtil::Ecore2UMLConverter and UMLUtil::UML2EcoreConverter classes for internal processing. There's no public method which can be used on Ecore(UML) metamodel. 2. As those annotations are specific for UML metamodel their utilizing will establish an implicit dependency to *.uml. 3. Actually 'SendObjectAction.arguments' property is the exceptional case when UnionEObjectEList is used for overriding the property from the base class (InvocationAction in this case). Overall I think that 'instanceof EcoreEList.UnmodifiableEList<?>' is not such a bad choice. Some negative consequence is that the solution applies only at runtime and can't be used during compilation/validation phase. (In reply to Sergey Boyko from comment #5) The problem is not reproducible with the UML 2.5 support for Luna. The UnmodifiableEList is now a UnionEObjectEList which doesn't barf on a reset(). ---- The real bug is that var send := object UML::SendObjectAction {}; send.argument := send_pin; fails to detect that "argument" is redefined and so "argument" is not an available feature. (Downstream assignmments to it are unlikely to succeed whether through a crash or silent no behavior). Arguably the UML2 support should arrange for getEAllStructuralFeatures to omit the features that do not exist; then UML2 would 'just work' in Ecore-only tools such as QVTo. However I'm sure that there are numerous compatibility reasons that make such a chage impossible; not even worth asking. Given that the UML2 support provides an extended Ecore, we might more realistically look for an ExtendedEcoreUtil in which helper functions provided an Ecore-like view of Ecore models with subsets/redefines EAnnotations. Bug 433025 raised. (In reply to Ed Willink from comment #6) > > Arguably the UML2 support should arrange for getEAllStructuralFeatures to > omit the features that do not exist; then UML2 would 'just work' in > Ecore-only tools such as QVTo. However I'm sure that there are numerous > compatibility reasons that make such a chage impossible; not even worth > asking. > > Given that the UML2 support provides an extended Ecore, we might more > realistically look for an ExtendedEcoreUtil in which helper functions > provided an Ecore-like view of Ecore models with subsets/redefines > EAnnotations. Bug 433025 raised. Ed, thank you for your effort! Really interested on what MDT.UML2 will suggest on the case. |