manage eopposite references coming from imported metamodel [message #1765199] |
Wed, 07 June 2017 13:13 |
Fy Za Messages: 245 Registered: March 2010 |
Senior Member |
|
|
Hi everybody,
I have this metamodel
I create a Xtext grammar from this metamodel
// automatically generated by Xtext
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
import "http://www.xtext.org/example/mydsl/MyDsl"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
Model returns Model:
{Model}
'Model'
name=ID
'{'
('classAs' '{' classAs+=ClassA ( "," classAs+=ClassA)* '}' )?
'}';
ClassA returns ClassA:
{ClassA}
'ClassA'
name=ID
'{'
// ('referingbs' '(' referingbs+=[ClassB|ID] ( "," referingbs+=[ClassB|ID])* ')' )?
('classb' '{' classb+=ClassB ( "," classb+=ClassB)* '}' )?
'}';
ClassB returns ClassB:
'ClassB'
name=ID
'{'
'target' target=[ClassA|ID]
'}';
My models are saved as XMI using a mechanism described in previous posts (That is not the issue).
The problem comes from the "referingbs" reference which is an eopposite reference to "target" reference.
When I create a model containing an instance of ClassB that refers to ClassA instance via target reference,
Xtext throws an error
java.lang.RuntimeException: Could not serialize ClassA:
ClassA.referingbs violates the upper bound: It holds 1 values, but only 0 are allowed.
Semantic Object: Model'model1'.classAs[0]->ClassA'class1'
URI: temp.my
Context: ClassA returns ClassA
at org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic$ExceptionThrowingAcceptor.accept(ISerializationDiagnostic.java:131)
at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.createSequence(BacktrackingSemanticSequencer.java:503)
at org.xtext.example.mydsl.serializer.MyDslSemanticSequencer.sequence_ClassA(MyDslSemanticSequencer.java:59)
at org.xtext.example.mydsl.serializer.MyDslSemanticSequencer.sequence(MyDslSemanticSequencer.java:38)
at org.eclipse.xtext.serializer.sequencer.AbstractSemanticSequencer.createSequence(AbstractSemanticSequencer.java:67)
at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptEObjectRuleCall(SequenceFeeder.java:325)
at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptRuleCall(SequenceFeeder.java:352)
at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.accept(SequenceFeeder.java:263)
at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.accept(BacktrackingSemanticSequencer.java:434)
at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.createSequence(BacktrackingSemanticSequencer.java:501)
at org.xtext.example.mydsl.serializer.MyDslSemanticSequencer.sequence_Model(MyDslSemanticSequencer.java:92)
at org.xtext.example.mydsl.serializer.MyDslSemanticSequencer.sequence(MyDslSemanticSequencer.java:44)
at org.eclipse.xtext.serializer.sequencer.AbstractSemanticSequencer.createSequence(AbstractSemanticSequencer.java:67)
at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:115)
at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:128)
at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:192)
at org.eclipse.xtext.resource.XtextResource.doSave(XtextResource.java:386)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.save(ResourceImpl.java:1430)
I found this message https://www.eclipse.org/forums/index.php?t=msg&th=1079030&goto=1737136&#msg_1737136
that proposes to customize ITransientValueService feature.
I customize it by adding the following
class MyDslRuntimeModule extends AbstractMyDslRuntimeModule {
def Class<? extends LegacyTransientValueService> bindITransientValueService2() {
MyDslTransientValueService
}
}
public class MyDslTransientValueService extends LegacyTransientValueService {
@Override
public ValueTransient isValueTransient(EObject semanticObject, EStructuralFeature feature) {
if (feature == MyDslPackage.Literals.CLASS_A__REFERINGBS) {
return ValueTransient.YES;
}
return super.isValueTransient(semanticObject, feature);
}
}
However the original error always appears (ClassA.referingbs violates the upper bound: It holds 1 values, but only 0 are allowed).
My question: how can I resolve this eopposite issue in Xtext?
I share the complete case-study containing an example (in the org.eclipse.example.mydsl.example project)
if someone is interested to reproduce.
best regards
|
|
|
Re: manage eopposite references coming from imported metamodel [message #1765223 is a reply to message #1765199] |
Wed, 07 June 2017 16:08 |
|
does this unittest reproduce your problem?
package org.xtext.example.mydsl.tests
import com.google.inject.Inject
import com.google.inject.Provider
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecore.resource.ResourceSet
import org.eclipse.xtext.serializer.ISerializer
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.XtextRunner
import org.junit.Test
import org.junit.runner.RunWith
import myDsl.MyDslFactory
@RunWith(XtextRunner)
@InjectWith(MyDslInjectorProvider)
class MyDslParsingTest {
@Inject
extension ISerializer ser
@Inject Provider<ResourceSet> rsp
@Test
def void loadModel() {
val rs = rsp.get
val r = rs.createResource(URI.createURI("dummy.my"))
val m = MyDslFactory.eINSTANCE.createModel => [
name = "m"
val a = MyDslFactory.eINSTANCE.createClassA => [
name = "a"
]
val b = MyDslFactory.eINSTANCE.createClassB => [
name = "b"
]
classAs += a
a.classb += b
b.target = a
]
r.contents += m
println(m.serialize)
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
|
Re: manage eopposite references coming from imported metamodel [message #1765224 is a reply to message #1765223] |
Wed, 07 June 2017 16:11 |
Fy Za Messages: 245 Registered: March 2010 |
Senior Member |
|
|
Thank you Chrisitan for reply
The test shows the same error
java.lang.RuntimeException: Could not serialize ClassA:
ClassA.referingbs violates the upper bound: It holds 1 values, but only 0 are allowed.
Semantic Object: Model'm'.classAs[0]->ClassA'a'
URI: dummy.my
Context: ClassA returns ClassA
at org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic$ExceptionThrowingAcceptor.accept(ISerializationDiagnostic.java:131)
at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.createSequence(BacktrackingSemanticSequencer.java:503)
at org.xtext.example.mydsl.serializer.MyDslSemanticSequencer.sequence_ClassA(MyDslSemanticSequencer.java:59)
at org.xtext.example.mydsl.serializer.MyDslSemanticSequencer.sequence(MyDslSemanticSequencer.java:38)
at org.eclipse.xtext.serializer.sequencer.AbstractSemanticSequencer.createSequence(AbstractSemanticSequencer.java:67)
at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptEObjectRuleCall(SequenceFeeder.java:325)
at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptRuleCall(SequenceFeeder.java:352)
at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.accept(SequenceFeeder.java:263)
at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.accept(BacktrackingSemanticSequencer.java:434)
at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.createSequence(BacktrackingSemanticSequencer.java:501)
at org.xtext.example.mydsl.serializer.MyDslSemanticSequencer.sequence_Model(MyDslSemanticSequencer.java:92)
at org.xtext.example.mydsl.serializer.MyDslSemanticSequencer.sequence(MyDslSemanticSequencer.java:44)
at org.eclipse.xtext.serializer.sequencer.AbstractSemanticSequencer.createSequence(AbstractSemanticSequencer.java:67)
at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:115)
at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:128)
at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:178)
at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:55)
at org.xtext.example.mydsl.tests.MyDslParsingTest.loadModel(MyDslParsingTest.java:62)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.eclipse.xtext.testing.XtextRunner$1.evaluate(XtextRunner.java:49)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
[Updated on: Wed, 07 June 2017 16:13] Report message to a moderator
|
|
|
|
|
|
|
|
|
Re: manage eopposite references coming from imported metamodel [message #1765255 is a reply to message #1765251] |
Wed, 07 June 2017 21:01 |
|
no i meant this
import com.google.inject.Inject
import myDsl.Model
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.XtextRunner
import org.eclipse.xtext.testing.util.ParseHelper
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(XtextRunner)
@InjectWith(MyDslInjectorProvider)
class MyDslParsingTest {
@Inject
ParseHelper<Model> parseHelper
@Test
def void loadModel() {
val result = parseHelper.parse('''
Model model1 { classAs { ClassA classa1 { classb { ClassB classb1 { target classa1 } } } } }
''')
Assert.assertNotNull(result)
Assert.assertTrue(result.eResource.errors.isEmpty)
println(result.classAs.head.referingbs)
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
|
|
|
|
Re: manage eopposite references coming from imported metamodel [message #1765263 is a reply to message #1765262] |
Wed, 07 June 2017 21:23 |
|
and i thought we were already at this point 2 weeks ago with the fsm stuff.
class MyDslDerivedStateComputer implements IDerivedStateComputer {
override discardDerivedState(DerivedStateAwareResource resource) {
if (!resource.contents.empty) {
val model = resource.contents.head as Model
for (a : model.classAs) {
a.referingbs.clear
}
}
}
override installDerivedState(DerivedStateAwareResource resource, boolean preLinkingPhase) {
if (!resource.contents.empty) {
val model = resource.contents.head as Model
for (a : model.classAs) {
println(a.name)
for (ai : model.classAs) {
for (bi : ai.classb) {
val name = NodeModelUtils.findNodesForFeature(bi, MyDslPackage.Literals.CLASS_B__TARGET).head?.text?.trim
println(name)
if (a.name == name) {
println("found")
val EObject proxy = EcoreUtil.create(MyDslPackage.Literals.CLASS_B) (proxy as InternalEObject).eSetProxyURI(EcoreUtil.getURI(a));
(proxy as InternalEObject).eSetProxyURI(EcoreUtil.getURI(bi))
a.referingbs += proxy as ClassB
}
}
}
}
}
}
}
(dont know how this stuff will behave cross file, maybe you need another approach for that - maybe ed can help)
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.06789 seconds