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 08:26  |
Eclipse User |
|
|
|
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: Mon, 07 November 2011 22:46] by Moderator
|
|
| | | | | | | |
Re: dangling reference error in XBlockExpression when accessing properties [message #756069 is a reply to message #755902] |
Thu, 10 November 2011 13:42   |
Eclipse User |
|
|
|
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 15:55] by Moderator
|
|
|
Re: dangling reference error in XBlockExpression when accessing properties [message #756093 is a reply to message #756069] |
Thu, 10 November 2011 15:37   |
Eclipse User |
|
|
|
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 18:22   |
Eclipse User |
|
|
|
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 #756325 is a reply to message #756322] |
Fri, 11 November 2011 20:24   |
Eclipse User |
|
|
|
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: Fri, 11 November 2011 20:32] by Moderator
|
|
| |
Goto Forum:
Current Time: Wed Jul 23 15:12:38 EDT 2025
Powered by FUDForum. Page generated in 0.04706 seconds
|