Home » Modeling » TMF (Xtext) » dangling reference error in XBlockExpression when accessing properties(define JvmType of property programmatically)
dangling reference error in XBlockExpression when accessing properties [message #755124] |
Mon, 07 November 2011 13:26 |
Max Goltzsche Messages: 40 Registered: November 2011 |
Member |
|
|
Hallo,
I am new to Xtext and have a problem with my DSL. It is derived from the domainmodel example (using xtext 2.0.1):
...
Entity:
{Entity}
abstract?='abstract'? 'entity' name=ValidID ('extends' superType=[Entity|QualifiedName])? '{'
(properties+=Property ("," properties+=Property)*)?
methods+=Method*
'}';
Property:
ToOneAssociation | ... ;
ToOneAssociation:
{ToOneAssociation}
(protected?='#'|'-')?
name=ValidID ':' access=AccessConfig? 'ref'
fromMany?='*'?
entity=[Entity|QualifiedName]
('backref' backReference=[Property|ValidID])?
notNull?='notNull'?
unique?='unique'?
validator=[Validator|QualifiedName]?;
...
Entities and field types with getters and setters are mapped to JvmTypes in an IJvmModelInferrer like this:
@Inject extension IJvmModelAssociator jvmModelAssociator
@Inject TypeReferences types
@Inject extension IJvmModelAssociations associations
...
def transform(Entity entity) {
val jvmType = typesFactory.createJvmGenericType
jvmType.simpleName = entity.name
jvmType.packageName = entity.packageName
jvmType.visibility = JvmVisibility::PUBLIC
entity.associatePrimary(jvmType)
for (p : entity.properties)
associateProperty(p, jvmType)
newArrayList(jvmType as JvmDeclaredType)
}
def dispatch associateProperty(ToOneAssociation p, JvmGenericType jvmType) {
transformProperty(property, jvmTypeRef(property.entity), jvmType)
}
... {more dispatched associateProperty methods} ...
def void transformProperty(Property property, JvmTypeReference fieldType, JvmGenericType jvmType) {
val jvmField = typesFactory.createJvmField
val access = property.access
jvmField.simpleName = property.name
jvmField.type = cloneWithProxies(fieldType)
jvmField.visibility = jvmVisibility(property)
jvmType.members += jvmField
property.associatePrimary(jvmField)
if (access == null || access.getter) {
val jvmGetter = typesFactory.createJvmOperation
jvmGetter.simpleName = "get" + property.name.toFirstUpper
jvmGetter.returnType = cloneWithProxies(fieldType)
jvmGetter.visibility = JvmVisibility::PUBLIC
jvmType.members += jvmGetter
property.associatePrimary(jvmGetter)
}
if (access == null || access.setter) {
val jvmSetter = typesFactory.createJvmOperation
val parameter = typesFactory.createJvmFormalParameter
parameter.name = property.name.toFirstUpper
parameter.parameterType = cloneWithProxies(fieldType)
jvmSetter.simpleName = "set" + property.name.toFirstUpper
jvmSetter.visibility = JvmVisibility::PUBLIC
jvmSetter.parameters += parameter
jvmType.members += jvmSetter
property.associatePrimary(jvmSetter)
}
}
def JvmTypeReference jvmTypeRef(Entity type) {
var jvmType = type.jvmElements.filter(typeof(JvmType)).head
if (jvmType == null) {
transform(type)
jvmType = type.jvmElements.filter(typeof(JvmType)).head
if (jvmType == null)
throw new IllegalArgumentException("Cannot resolve type " + type.name)
}
types.createTypeRef(jvmType)
}
The following example code with my DSL shows what I want to do and contains my problem:
package test {
entity A {
created : java.util.Date,
propertyToB : ref B
testOp() : void {
propertyToB.[color=red]propertyToA[/color].created.^time
}
}
entity B {
propertyToA : ref A
}
}
I can access every property with autocompletion. But afterwards Eclipse marks the nested property access propertyToA as error but not the propertyB access before and not the following java.util.Date property which type is included by the xbase grammar rule JvmTypeReference.
The error says:
Quote:The feature 'feature' of 'org.eclipse.xtext.xbase.impl.XMemberFeatureCallImplCustom@2c405913{platform:/resource/Testxy/src/SampleEntities.crudsl#/0/@elements.3/@elements.1/@methods.0/@body/@expressions.1/@memberCallTarget}'
contains a dangling reference 'org.eclipse.xtext.common.types.impl.JvmOperationImpl@5b6a3d73{#///@members.7}' and eclipse throws a NullPointerException at org.eclipse.xtext.resource.IGlobalServiceProvider$ResourceServiceProviderImpl.findService(IGlobalServiceProvider.java:59)
I've read that every persistent element in an EMF model has to be registered in Resource.contents to be indexed. Makes sense. Although it says that xbase registers its used JvmTypes by itself in the model root I tried to register every entity's JvmType in the transform(entity) method by writingentity.eResource.contents.add(jvmType)
This makes my access error disappear but comes up with an eclipse exception with dialog window:
Quote:!MESSAGE org.eclipse.xtext.linking.lazy.LazyLinkingResource - resolution of uriFragment 'xtextLink_::0.0.3.1.2.4.0.6::1::/0' failed.
!STACK 0
org.eclipse.emf.common.util.BasicEList$BasicIndexOutOfBoundsException: index=3, size=0
at org.eclipse.emf.common.util.BasicEList.get(BasicEList.java:352)
at org.eclipse.xtext.linking.lazy.LazyURIEncoder.resolveShortFragment(LazyURIEncoder.java:100)
at org.eclipse.xtext.linking.lazy.LazyURIEncoder.decode(LazyURIEncoder.java:80)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:157)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:139)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:103)
at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:417)
at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:127)
at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:62)
at org.eclipse.xtext.ui.editor.validation.ValidationJob$1.exec(ValidationJob.java:79)
at org.eclipse.xtext.ui.editor.validation.ValidationJob$1.exec(ValidationJob.java:1)
at org.eclipse.xtext.util.concurrent.AbstractReadWriteAcces.readOnly(AbstractReadWriteAcces.java:32)
at org.eclipse.xtext.ui.editor.model.XtextDocument.readOnly(XtextDocument.java:86)
at org.eclipse.xtext.ui.editor.validation.ValidationJob.createIssues(ValidationJob.java:75)
at org.eclipse.xtext.ui.editor.validation.ValidationJob.run(ValidationJob.java:64)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
HELP, PLEASE!
Simply, I want to access properties with JvmTypes of my entities in a XBlockExpression having defined the JvmType of every property programmatically because I do not want users create associations to other java types than the defined entities.
regards,
Max
[Updated on: Tue, 08 November 2011 03:46] Report message to a moderator
|
|
|
Re: dangling reference error in XBlockExpression when accessing properties [message #755506 is a reply to message #755124] |
Tue, 08 November 2011 16:42 |
Max Goltzsche Messages: 40 Registered: November 2011 |
Member |
|
|
I am stuck on this problem!!!
I do not understand this.
My problem in a few words:
I want to have a grammar similar to that from the domain model example but without declaration of specific java types. Instead I want to define the types programmatically. In case of an entity reference I use the JvmGenericType declared for that entity but in the DSL the grammar rule for that is not [JvmTypeReference] but ref (*) [Entity]. Lists shall also not be declared as explicit java types in the DSL but as keywords list or set with the optional keyword * afterwards marking that property as manyToMany association. Inside the IJvmModelInferrer instance I declare properties with these keywords as JvmTypeReference of java.util.List/Set. With such limitations I want to be able to define the grammar context free but dependent of special types.
Shorter: I want to have a clear context free separation of *toMany/*toOne associations and normal attributes without analysing the given JvmTypeReferences and collection types.
Help, please!!!
regards,
Max
[Updated on: Tue, 08 November 2011 16:42] Report message to a moderator
|
|
| |
Re: dangling reference error in XBlockExpression when accessing properties [message #755569 is a reply to message #755548] |
Tue, 08 November 2011 20:08 |
Max Goltzsche Messages: 40 Registered: November 2011 |
Member |
|
|
Hey,
My grammar extends org.eclipse.xtext.xbase.Xbase.
Included in GenerateCrudsl.mwe2:
fragment = xbase.XbaseGeneratorFragment {}
For this reason generated in AbstractCrudslRuntime
public Class<? extends org.eclipse.xtext.linking.ILinker> bindILinker() {
return org.eclipse.xtext.xbase.jvmmodel.JvmModelXbaseLazyLinker.class;
}
Any other idea?
The example dsl code once again:
package test {
entity A {
propertyToB : ref B
testOp() : void {
propertyToB.propertyToA
}
}
entity B {
propertyToA : ref A
}
}
In testOp(): Access to propertyToB is valid. Access to propertyToA is marked as error:
The feature 'feature' of 'org.eclipse.xtext.xbase.impl.XMemberFeatureCallImplCustom@7ed655a8{platform:/resource/Testxy/src/SampleEntities.crudsl#/0/@elements.3/@elements.0/@methods.0/@body/@expressions.1/@memberCallTarget/@memberCallTarget}'
contains a dangling reference 'org.eclipse.xtext.common.types.impl.JvmOperationImpl@6a85a2b6{#///@members.4}'
regards,
Max
[Updated on: Tue, 08 November 2011 20:16] Report message to a moderator
|
|
| | | | |
Re: dangling reference error in XBlockExpression when accessing properties [message #756069 is a reply to message #755902] |
Thu, 10 November 2011 18:42 |
Max Goltzsche Messages: 40 Registered: November 2011 |
Member |
|
|
Thanks a lot!!! Very good approach.
But there seems to be a problem with the scope in the java code generator of Xtend:
class CrudslJvmModelInferrer extends AbstractModelInferrer {
@Inject extension JvmTypesBuilder
@Inject extension IQualifiedNameProvider
def dispatch infer(Type type, IAcceptor<JvmDeclaredType> acceptor, boolean prelinkingPhase) {
acceptor.accept(type.toJvmType())
}
def create jvmType: type.toClass(type.fullyQualifiedName, null) toJvmType(Type type) {
... {initialize: associate type's fields with jvmType's fields} ...
}
...
}
generates:
public JvmGenericType toJvmType(final Type type) {
final ArrayList<?>_cacheKey = CollectionLiterals.newArrayList(type);
final JvmGenericType _result;
synchronized (_createCache_toJvmType) {
if (_createCache_toJvmType.containsKey(_cacheKey)) {
return _createCache_toJvmType.get(_cacheKey);
}
-> CrudslJvmModelInferrer _CrudslJvmModelInferrer = CrudslJvmModelInferrer;
-> CrudslJvmModelInferrer _CrudslJvmModelInferrer_1 = CrudslJvmModelInferrer;
QualifiedName _fullyQualifiedName = _CrudslJvmModelInferrer_1._iQualifiedNameProvider.getFullyQualifiedName(type);
JvmGenericType _class = _CrudslJvmModelInferrer._jvmTypesBuilder.toClass(type, _fullyQualifiedName, null);
_result = _class;
_createCache_toJvmType.put(_cacheKey, _result);
}
_init_toJvmType(_result, type);
return _result;
}
"CrudslJvmModelInferrer _CrudslJvmModelInferrer = CrudslJvmModelInferrer;" is an error. It should be
"CrudslJvmModelInferrer _CrudslJvmModelInferrer = this;" and is not neccessary. "this" could also be used, directly.
Somehow, I cannot access "this"/extensions in the first expression of the create function.
Is it a bug or a feature?
regards,
Max
[Updated on: Thu, 10 November 2011 20:55] Report message to a moderator
|
|
|
Re: dangling reference error in XBlockExpression when accessing properties [message #756093 is a reply to message #756069] |
Thu, 10 November 2011 20:37 |
Sebastian Zarnekow Messages: 3118 Registered: July 2009 |
Senior Member |
|
|
Max,
thanks for the report. This was already fixed for 2.1.1 which will be
available tomorrow.
Regards,
Sebastian
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
On 10.11.11 19:42, Max wrote:
> Thanks a lot!!! Very good approach. But there seems to be a problem with
> the scope in the java code generator of Xtend:
> class CrudslJvmModelInferrer extends AbstractModelInferrer {
>
> @Inject extension JvmTypesBuilder
>
> @Inject extension IQualifiedNameProvider
>
> def dispatch infer(Type type, IAcceptor<JvmDeclaredType> acceptor,
> boolean prelinkingPhase) {
> acceptor.accept(type.toJvmType())
> }
>
> def create jvmType: type.toClass(type.fullyQualifiedName, null)
> toJvmType(Type type) {
> ... {initialize} ...
> }
>
> ...
> }
> generates:
> public JvmGenericType toJvmType(final Type type) {
> final ArrayList<?>_cacheKey = CollectionLiterals.newArrayList(type);
> final JvmGenericType _result;
> synchronized (_createCache_toJvmType) {
> if (_createCache_toJvmType.containsKey(_cacheKey)) {
> return _createCache_toJvmType.get(_cacheKey);
> }
> CrudslJvmModelInferrer _CrudslJvmModelInferrer = CrudslJvmModelInferrer;
> CrudslJvmModelInferrer _CrudslJvmModelInferrer_1 = CrudslJvmModelInferrer;
> QualifiedName _fullyQualifiedName =
> _CrudslJvmModelInferrer_1._iQualifiedNameProvider.getFullyQualifiedName(type);
>
> JvmGenericType _class =
> _CrudslJvmModelInferrer._jvmTypesBuilder.toClass(type,
> _fullyQualifiedName, null);
> _result = _class;
> _createCache_toJvmType.put(_cacheKey, _result);
> }
> _init_toJvmType(_result, type);
> return _result;
> }
> "CrudslJvmModelInferrer _CrudslJvmModelInferrer =
> CrudslJvmModelInferrer;" is an error. It should be
> "CrudslJvmModelInferrer _CrudslJvmModelInferrer = this;" and is not
> neccessary. "this" could also be used, directly.
>
> Is this a bug or do I not understand sth?
>
> regards,
> Max
|
|
| |
Re: dangling reference error in XBlockExpression when accessing properties [message #756320 is a reply to message #756098] |
Fri, 11 November 2011 23:22 |
Max Goltzsche Messages: 40 Registered: November 2011 |
Member |
|
|
Hey,
now I've installed Xtext 2.1.0 release + Xtext 2.1.1 nightly build but wiring bidirectional references does not work with this create function. It throws a StackOverflowError.
Xtend:
class CrudslJvmModelInferrer extends AbstractModelInferrer {
@Inject extension JvmTypesBuilder
@Inject extension IQualifiedNameProvider
@Inject extension TypeReferences types
def dispatch infer(Type type, IAcceptor<JvmDeclaredType> acceptor, boolean prelinkingPhase) {
acceptor.accept(type.jvmType)
}
def create jvmType: type.toClass(type.fullyQualifiedName, null) jvmType(Type type) {
for (p : entity.properties) {
val type = p.jvmTypeRef(jvmType)
jvmType.members += p.toField(p.name, type)
if (p.access == null || p.access.getter)
jvmType.members += p.toGetter(p.name, type)
if (p.access == null || p.access.setter)
jvmType.members += p.toSetter(p.name, type)
}
}
def dispatch JvmTypeReference jvmTypeRef(ToOneAssociation p, JvmGenericType jvmType) {
p.entity.jvmType.createTypeRef()
}
... {more dispatched jvmTypeRef() methods} ...
}
generated java:
...
public JvmGenericType jvmType(final Type type) {
final ArrayList<?>_cacheKey = CollectionLiterals.newArrayList(type);
final JvmGenericType _result;
synchronized (_createCache_jvmType) {
if (_createCache_jvmType.containsKey(_cacheKey)) {
return _createCache_jvmType.get(_cacheKey);
}
QualifiedName _fullyQualifiedName = this._iQualifiedNameProvider.getFullyQualifiedName(type);
JvmGenericType _class = this._jvmTypesBuilder.toClass(type, _fullyQualifiedName, null);
_result = _class;
_createCache_jvmType.put(_cacheKey, _result);
}
_init_jvmType(_result, type);
return _result;
}
...
Here the _init_jvmType() method is called directly after instantiating a new object. It doesn't work because initialization requires existing types, which are not yet instantiated. I thought somehow the create function's initializer is called after every element is instantiated?!
In the documentation it seems to be possible to map bidirectional references like this: http://www.eclipse.org/Xtext/documentation/2_1_0/02-Xtend_Classes_Functions.php#CreateFunctions.
What am I doing wrong?
regards,
Max
|
|
|
Re: dangling reference error in XBlockExpression when accessing properties [message #756322 is a reply to message #756320] |
Fri, 11 November 2011 23:43 |
|
Hi,
i guess you have a missunderstanding what a create function does:
(1) it looks up the parameter in a cache and if it finds something then this something is return
(2) else it creates a new instance using the "factory" expression
(3) then it calls the "initializer" expression
(4) the result is stored to the cache.
=> you can call the conversion to jvm class at every place you need it, so matter if it is at the for loop
when you iterate over all entities, nor if you want to get the jvm type of the references to another entity
since the caching is done before calling the initializer expression there should be no problem with an endless loop
/ stackoverflow.
=> is it really the jvmType function that causes the stackoverflow?
~Christian
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
[Updated on: Fri, 11 November 2011 23:45] Report message to a moderator
|
|
|
Re: dangling reference error in XBlockExpression when accessing properties [message #756325 is a reply to message #756322] |
Sat, 12 November 2011 01:24 |
Max Goltzsche Messages: 40 Registered: November 2011 |
Member |
|
|
Thank you for your answer.
You're right: The jvmType method works well but there seems to be a problem with the result of a create method passed to acceptor.accept(). It may be a proxy because my test eclipse instance has the StackOverflow while resolving proxies (stacktrace only visible when shutting eclipse down for some reason else I only get a window with that short error information):
Error while informing user about event loop exception:
java.lang.StackOverflowError
at org.eclipse.xtext.common.types.impl.JvmDeclaredTypeImpl.getMembers(JvmDeclaredTypeImpl.java:285)
at org.eclipse.xtext.common.types.impl.JvmDeclaredTypeImpl.eGet(JvmDeclaredTypeImpl.java:489)
at org.eclipse.xtext.common.types.impl.JvmGenericTypeImpl.eGet(JvmGenericTypeImpl.java:232)
at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1021)
at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1013)
at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eObjectForURIFragmentSegment(BasicEObjectImpl.java:533)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.getEObject(ResourceImpl.java:780)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.getEObject(ResourceImpl.java:756)
at org.eclipse.xtext.resource.XtextResource.access$1(XtextResource.java:1)
at org.eclipse.xtext.resource.XtextResource$1.getEObject(XtextResource.java:102)
at org.eclipse.xtext.resource.DefaultFragmentProvider.getEObject(DefaultFragmentProvider.java:26)
at org.eclipse.xtext.resource.XtextResource.getEObject(XtextResource.java:286)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:211)
at org.eclipse.xtext.xbase.resource.XbaseResource.access$0(XbaseResource.java:1)
at org.eclipse.xtext.xbase.resource.XbaseResource$2.exec(XbaseResource.java:227)
at org.eclipse.xtext.xbase.resource.XbaseResource$2.exec(XbaseResource.java:1)
at org.eclipse.xtext.util.OnChangeEvictingCache.execWithoutCacheClear(OnChangeEvictingCache.java:121)
at org.eclipse.xtext.xbase.resource.XbaseResource.getEObject(XbaseResource.java:225)
at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.getEObject(ResourceSetImpl.java:219)
at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:203)
at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:263)
at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eResolveProxy(BasicEObjectImpl.java:1483)
at org.eclipse.emf.ecore.util.EcoreEList.resolveProxy(EcoreEList.java:212)
at org.eclipse.emf.ecore.util.EcoreEList.resolve(EcoreEList.java:167)
at org.eclipse.emf.ecore.util.EObjectContainmentWithInverseEList$Resolving.resolve(EObjectContainmentWithInverseEList.java:111)
at org.eclipse.emf.common.util.BasicEList.get(BasicEList.java:354)
at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eObjectForURIFragmentSegment(BasicEObjectImpl.java:545)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.getEObject(ResourceImpl.java:780)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.getEObject(ResourceImpl.java:756)
at org.eclipse.xtext.resource.XtextResource.access$1(XtextResource.java:1)
at org.eclipse.xtext.resource.XtextResource$1.getEObject(XtextResource.java:102)
at org.eclipse.xtext.resource.DefaultFragmentProvider.getEObject(DefaultFragmentProvider.java:26)
at org.eclipse.xtext.resource.XtextResource.getEObject(XtextResource.java:286)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:211)
at org.eclipse.xtext.xbase.resource.XbaseResource.access$0(XbaseResource.java:1)
at org.eclipse.xtext.xbase.resource.XbaseResource$2.exec(XbaseResource.java:227)
at org.eclipse.xtext.xbase.resource.XbaseResource$2.exec(XbaseResource.java:1)
at org.eclipse.xtext.util.OnChangeEvictingCache.execWithoutCacheClear
...
works:
def dispatch void infer(Type type, IAcceptor<JvmDeclaredType> acceptor, boolean prelinkingPhase) {
acceptor.accept(type.toClass(type.fullyQualifiedName, null))
}
works:
def dispatch void infer(Type type, IAcceptor<JvmDeclaredType> acceptor, boolean prelinkingPhase) {
type.jvmType
}
results in the exception above:
def dispatch void infer(Type type, IAcceptor<JvmDeclaredType> acceptor, boolean prelinkingPhase) {
acceptor.accept(type.jvmType)
}
def create jvmType: type.toClass(type.fullyQualifiedName, null) jvmType(Type type) {
}
This is weird.
regards,
Max
[Updated on: Sat, 12 November 2011 01:32] Report message to a moderator
|
|
| |
Goto Forum:
Current Time: Wed Sep 25 17:29:15 GMT 2024
Powered by FUDForum. Page generated in 0.05405 seconds
|