Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Strange behavior of JvmTypeReference assignments
Strange behavior of JvmTypeReference assignments [message #987875] Wed, 28 November 2012 08:26 Go to next message
Espinosa CZ is currently offline Espinosa CZ
Messages: 27
Registered: July 2009
Junior Member
Hi guys,

I would have a curious question about a strange behaviour of JvmTypeReference assignments I have recently observed.

Let's have this simple language definition fragment:

RootCloner:
        type=JvmTypeReference name=ID? '{'
                 (fields += FieldCloner)*
        '}'
        // ..several assignments, not relevant..
;

FieldCloner:
        // ..several assignments, not relevant..
;

AbstractClonerType:
        {AbstractClonerType} (inferredType=JvmTypeReference)?
;

AbstractClonerRule returns AbstractClonerType:
        // this cause RootCloner, FieldCloner be but under same interface - AbstractClonerType
        // Nice! They will share inferredType property - getInferredType() / setInferredType()
        RootCloner | FieldCloner
;


During validation phase - as a sort of post-processing - I fill compute inferredType recursively based on parent type and field name and fill them back to the model. User has to specify explicitly only the type of RootCloner. Everything else is inferred.

The issues is with RootCloner. For RootCloner inferredType == type. To keep whole model consistent, that is to have inferredType set for ALL cloners, root or not, I have to do this assignment:

JvmTypeReference type = rootCloner.getType()
rootCloner.setInferredType(type);


However, the second command, the setInferredType(), the setter of JvmTypeReference, also sets to null the original field, that is rootCloner.type.
Why?

As a consequence, when validation is repeatedly called, and it sure is, in integration tests it is called with every assertion (why??) then the validation does not work since the root type is now null.

I look inside generated setInferredType() code, and it is quite complex method.
What are these eInverseRemove() and eInverseAdd() and basicSetType() are?
What is the purpose?

I search internet and it seems it is quite normal for any JvmTypeReference value assignment setter.

Side note: "inferredType" is indeed transient type, and yes, it gave me headaches when dealing with serialization, until I implemented and plugged in ITransientValuesService and specified that "inferredType" really is transient and should be ignored when serializing.

I found a solution for my problem by creating a "defensive copy" JvmTypeReference:
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.common.types.util.TypeReferences;

@Inject TypeReferences typeReferences;

public JvmTypeReference createDefensiveCopyOfJvmTypeReference(JvmTypeReference typeReference) {
    return typeReferences.createTypeRef(typeReference.getType());
}
...
JvmTypeReference type = createDefensiveCopyOfJvmTypeReference(rootCloner.getType());
rootCloner.setInferredType(type);
...

..and this works.
I am just curious why is that?
Guys, did I overseen some parts of your documentation?

Espinosa
Re: Strange behavior of JvmTypeReference assignments [message #988192 is a reply to message #987875] Wed, 28 November 2012 13:35 Go to previous messageGo to next message
Hallvard Traetteberg is currently offline Hallvard Traetteberg
Messages: 594
Registered: July 2009
Location: Trondheim, Norway
Senior Member
Hi,

I guess type and inferredType are both containment references, and since
an EObject cannot be contained in more than one container by more than
one feature, it is removed from the type feature when linked to by the
inferredType feature. You'll need to use EcoreUtil.copy or the create a
copy like you explained.

Hallvard

On 28.11.12 05.26, Espinosa CZ wrote:
> Hi guys,
>
> I would have a curious question about a strange behaviour of
> JvmTypeReference assignments I have recently observed.
>
> Let's have this simple language definition fragment:
>
>
> RootCloner:
> type=JvmTypeReference name=ID? '{'
> (fields += FieldCloner)*
> '}'
> // ..several assignments, not relevant..
> ;
>
> FieldCloner:
> // ..several assignments, not relevant..
> ;
>
> AbstractClonerType:
> {AbstractClonerType} (inferredType=JvmTypeReference)?
> ;
>
> AbstractClonerRule returns AbstractClonerType:
> // this cause RootCloner, FieldCloner be but under same
> interface - AbstractClonerType
> // Nice! They will share inferredType property -
> getInferredType() / setInferredType()
> RootCloner | FieldCloner
> ;
>
>
> During validation phase - as a sort of post-processing - I fill compute
> inferredType recursively based on parent type and field name and fill
> them back to the model. User has to specify explicitly only the type of
> RootCloner. Everything else is inferred.
>
> The issues is with RootCloner. For RootCloner inferredType == type. To
> keep whole model consistent, that is to have inferredType set for ALL
> cloners, root or not, I have to do this assignment:
>
> JvmTypeReference type = rootCloner.getType()
> rootCloner.setInferredType(type);
>
> However, the second command, the setInferredType(), the setter of
> JvmTypeReference, also sets to null the original field, that is
> rootCloner.type.
> Why?
>
> As a consequence, when validation is repeatedly called, and it sure is,
> in integration tests it is called with every assertion (why??) then the
> validation does not work since the root type is now null.
>
> I look inside generated setInferredType() code, and it is quite complex
> method.
> What are these eInverseRemove() and eInverseAdd() and basicSetType() are?
> What is the purpose?
>
> I search internet and it seems it is quite normal for any
> JvmTypeReference value assignment setter.
>
> Side note: "inferredType" is indeed transient type, and yes, it gave me
> headaches when dealing with serialization, until I implemented and
> plugged in ITransientValuesService and specified that "inferredType"
> really is transient and should be ignored when serializing.
>
> I found a solution for my problem by creating a "defensive copy"
> JvmTypeReference:
>
> import org.eclipse.xtext.common.types.JvmTypeReference;
> import org.eclipse.xtext.common.types.util.TypeReferences;
>
> @Inject TypeReferences typeReferences;
>
> public JvmTypeReference
> createDefensiveCopyOfJvmTypeReference(JvmTypeReference typeReference) {
> return typeReferences.createTypeRef(typeReference.getType());
> }
> ..
> JvmTypeReference type =
> createDefensiveCopyOfJvmTypeReference(rootCloner.getType());
> rootCloner.setInferredType(type);
> ..
>
> .and this works. I am just curious why is that?
> Guys, did I overseen some parts of your documentation?
>
> Espinosa
Re: Strange behavior of JvmTypeReference assignments [message #988198 is a reply to message #987875] Wed, 28 November 2012 13:35 Go to previous messageGo to next message
Hallvard Traetteberg is currently offline Hallvard Traetteberg
Messages: 594
Registered: July 2009
Location: Trondheim, Norway
Senior Member
Hi,

I guess type and inferredType are both containment references, and since
an EObject cannot be contained in more than one container by more than
one feature, it is removed from the type feature when linked to by the
inferredType feature. You'll need to use EcoreUtil.copy or the create a
copy like you explained.

Hallvard

On 28.11.12 05.26, Espinosa CZ wrote:
> Hi guys,
>
> I would have a curious question about a strange behaviour of
> JvmTypeReference assignments I have recently observed.
>
> Let's have this simple language definition fragment:
>
>
> RootCloner:
> type=JvmTypeReference name=ID? '{'
> (fields += FieldCloner)*
> '}'
> // ..several assignments, not relevant..
> ;
>
> FieldCloner:
> // ..several assignments, not relevant..
> ;
>
> AbstractClonerType:
> {AbstractClonerType} (inferredType=JvmTypeReference)?
> ;
>
> AbstractClonerRule returns AbstractClonerType:
> // this cause RootCloner, FieldCloner be but under same
> interface - AbstractClonerType
> // Nice! They will share inferredType property -
> getInferredType() / setInferredType()
> RootCloner | FieldCloner
> ;
>
>
> During validation phase - as a sort of post-processing - I fill compute
> inferredType recursively based on parent type and field name and fill
> them back to the model. User has to specify explicitly only the type of
> RootCloner. Everything else is inferred.
>
> The issues is with RootCloner. For RootCloner inferredType == type. To
> keep whole model consistent, that is to have inferredType set for ALL
> cloners, root or not, I have to do this assignment:
>
> JvmTypeReference type = rootCloner.getType()
> rootCloner.setInferredType(type);
>
> However, the second command, the setInferredType(), the setter of
> JvmTypeReference, also sets to null the original field, that is
> rootCloner.type.
> Why?
>
> As a consequence, when validation is repeatedly called, and it sure is,
> in integration tests it is called with every assertion (why??) then the
> validation does not work since the root type is now null.
>
> I look inside generated setInferredType() code, and it is quite complex
> method.
> What are these eInverseRemove() and eInverseAdd() and basicSetType() are?
> What is the purpose?
>
> I search internet and it seems it is quite normal for any
> JvmTypeReference value assignment setter.
>
> Side note: "inferredType" is indeed transient type, and yes, it gave me
> headaches when dealing with serialization, until I implemented and
> plugged in ITransientValuesService and specified that "inferredType"
> really is transient and should be ignored when serializing.
>
> I found a solution for my problem by creating a "defensive copy"
> JvmTypeReference:
>
> import org.eclipse.xtext.common.types.JvmTypeReference;
> import org.eclipse.xtext.common.types.util.TypeReferences;
>
> @Inject TypeReferences typeReferences;
>
> public JvmTypeReference
> createDefensiveCopyOfJvmTypeReference(JvmTypeReference typeReference) {
> return typeReferences.createTypeRef(typeReference.getType());
> }
> ..
> JvmTypeReference type =
> createDefensiveCopyOfJvmTypeReference(rootCloner.getType());
> rootCloner.setInferredType(type);
> ..
>
> .and this works. I am just curious why is that?
> Guys, did I overseen some parts of your documentation?
>
> Espinosa
Re: Strange behavior of JvmTypeReference assignments [message #989363 is a reply to message #987875] Wed, 05 December 2012 15:41 Go to previous message
Espinosa CZ is currently offline Espinosa CZ
Messages: 27
Registered: July 2009
Junior Member
Quote:
I guess type and inferredType are both containment references, and since
an EObject cannot be contained in more than one container by more than
one feature ...


Ah, it gives sense.
Thank you Hallvard!
Previous Topic:[CDO/XText int
Next Topic:Customizable formatting for the Xtext editor
Goto Forum:
  


Current Time: Tue Jul 22 11:40:16 EDT 2014

Powered by FUDForum. Page generated in 0.02467 seconds