Home > Xtext > IQualifiedNameProviders in Xtext 2.0

IQualifiedNameProviders in Xtext 2.0

Xtext 2.0 come with a change to the IQualifiedNameProvider interface. This interface is used to calculate a name for EObjects. The Name is used in Xtext’s index, for cross referencing and much more.

public interface IQualifiedNameProvider extends Function<EObject, QualifiedName> {

	QualifiedName getFullyQualifiedName(EObject obj);

}

Here we see the API change: There is a rename of the getQualifiedName method to getFullyQualifedName. In Xtext 1.0.x the qualified name was a simple String, now it is a wrapper class that holds the segements of the qualified name.

There are two default implementations for a IQualifiedNameProviderSimpleNameProvider and DefaultDeclarativeQualifiedNameProvider. Consider we have a grammar like

grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Package:
	"package" name=ID "{"
		elements+=Element*
	"}"
;

Element:
	"element" name=ID
;

and a sample model like

package TestPackage {
	element A
	element B
}

Then with SimpleNameProvider we would have following qualified names.

  • TestPackage for the package
  • A and B for the elements

And with DefaultDeclarativeQualifiedNameProvider we would have following qualified names.

  • TestPackage for the package
  • TestPackage.A and TestPackage.B for the elements
Both Providers take the name EAttribute of our Package and Element to do the calculation. The DefaultDeclarativeQualifiedNameProvider  uses the Elements parents qualified name too. (a fully qualified name ;-))
But it won’t work e.g. if our grammar would look like
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Package:
	"package" name=ID "{"
		elements+=Element*
	"}"
;

Element:
	"element" id=ID
;
with Element having and id and not a name. We can easily change this by creating and binding our own IQualifiedNameProvider e.g. by extending DefaultDeclarativeQualifiedNameProvider
package org.xtext.example.mydsl;

import org.eclipse.xtext.naming.DefaultDeclarativeQualifiedNameProvider;
import org.eclipse.xtext.naming.QualifiedName;
import org.xtext.example.mydsl.myDsl.Element;
import org.xtext.example.mydsl.myDsl.Package;

public class MyDslQNP extends DefaultDeclarativeQualifiedNameProvider{

	QualifiedName qualifiedName(Element e) {
		Package p = (Package) e.eContainer();
		return QualifiedName.create(p.getName(), e.getId());
	}

}

We simply write a method qualifiedName that is called from the polymorpthic dispatcher when calculating the name of an Element

package org.xtext.example.mydsl;

import org.eclipse.xtext.naming.IQualifiedNameProvider;

/**
 * Use this class to register components to be used at runtime / without the Equinox extension registry.
 */
public class MyDslRuntimeModule extends org.xtext.example.mydsl.AbstractMyDslRuntimeModule {

	@Override
	public Class<? extends IQualifiedNameProvider> bindIQualifiedNameProvider() {
		return MyDslQNP.class;
	}

}
About these ads
Categories: Xtext Tags: ,
  1. caner
    July 19, 2011 at 13:47

    Hello Christian
    Thank you so much for this great expression

    Look forward to read more about Xtext 2.0 on your blog
    BR
    Caner

  2. gch
    October 27, 2011 at 05:22

    well written und precise! gch

  3. Mischa
    April 7, 2012 at 21:04

    Hi Chrisitan,

    thanks allot. Your blog help avoiding a lot of trouble casued by ‘out-of-date’.

    One needs to update the XText-Grammar docu which still describes the frist “ID” terminal rule used for as key for linking. As described in your blog it’s always just the “name” feature if available like hard coded in the DefaultDeclarativeQualifiedNameProvider.

    The ‘out-of-date’ docu section can be found here:

    http://www.eclipse.org/Xtext/documentation/2_1_0/020-grammar-language.php#cross_reference

    • April 8, 2012 at 05:21

      Hi, i guess the doc is talking only about the left (grammar) side of cross references and wants to state that ref=[Type] is short for ref=[Type|ID]

  4. Stefan
    May 8, 2014 at 12:03

    Hi :)

    I am creating a language from which I want to reference elements of a UML model. You have another post about this situation, however I am having problem with qualified names, so I am asking this here.

    So, I have extended and binded DefaultDeclarativeQualifiedNameProvider and overrided its methods for getting qualified names of UML elements.

    On purpose, from each getQualifiedName() method for UML types, I return the simple name of the element (e.g. Product, and not webstore.Product) as I don’t want to have fully qualified names everywhere in my language, but to use imported namespaces..

    Now this works perfect in editor, but when I want to load a model of my language, I get poblems with loading referred UML elements (some names clash since it calls the getQualifiedName() again which gives only simple names).

    How do I find a way out of this? I have searched so much on internet and in documentation (which is sooo short to my opinion) without any luck..

    Is there a way to have more then one QualifiedNameProvider binded, one for editor and one for loading the model?

    Thank you so much in advance.

    Best,
    Stefan

    • May 8, 2014 at 18:57

      yes you can bind the iqualified name provider in the runtime module and in the ui module but i dont get your problem. what is your exact problem loading?!?

  5. Stefan
    May 8, 2014 at 13:40

    @Edit of previous post:

    What I now understand is that when I call resource.resolveAll() on the resource containing my model with references to UML (actually, for the purpose of supporting more than just UML I am referring to EObject from Ecore), for each UML element it finds an EObject with a given simple name, which then goes wrong of course..

    So what I would really need is that the reference to the element get serialized as a fully qualified name, and only simple name is presented in the editor.. How to do this?

    I hope my explanation is not to complicated :)

    • May 8, 2014 at 18:58

      Standaline you have to add all resources to the resourceset. the dsl resources and the uml resources.
      and you have to make sure the resourceserviceprovider is initited (e.g. using the umlsupport class)

  6. Stefan
    May 9, 2014 at 09:53

    I think probably I am trying to solve my problem using the wrong approach :)

    This is the problem: When using import statements for referencing elements from another DSL, only references of the top level (those which are at the same level as import statements) have the benefit from those import statements.

    I need to nest references to the other DSL within the elements of my DSL. So for example:

    import somePackage.*

    myDslElement reference SomeClass { attribute SomeClass.someAttribute }

    So in this example I had to use SomeClass.someAttribute, in order for resolving the references to work.. How do I enable nesting the references and then make a qualified name of a reference based on its nesting?

    I could have used instead:

    import somePackage.*
    import somePackage.SomeClass.*

    myDslElement reference SomeClass { attribute someAttribute }

    But this is an ugly solution, and it also doesn’t work if another class, e.g. SomeClassB has an attribute with the same name someAttribute..

    I thought QUalifiedNameProvider can solve this, but maybe I am suppose to do it using some other approach..

    Thanks so much for replying so far! :)

  7. Stefan
    May 9, 2014 at 09:58

    p.s. In the example above I know that someAttribute has to be an attribute of the SomeClass, thus I want to use this knowledge and build the complete qualifiedName of someAttribute, and not to directly specify this in my model..

  8. Stefan
    June 22, 2014 at 11:26

    Hi Christian :)
    I am still stuck with this issue. and I think its an important one..

    As I understood from your example in the post about mixing UML and Xtext DSL,
    it looks like you anyway need to use complete qualified names in order for resource resolving to work..

    How could I reconstruct qualified name and where exactly in the code could I do this, based on the structure of my DSL model, not only by having access to the referenced UML model in the qualified name provider, as you shown here?

    Please help :)

    • June 22, 2014 at 20:59

      i dont really get your problem. you may post all what is needed to reproduce in xtexts eclipse forum

  9. Stefan
    September 26, 2014 at 07:41

    Hey hope you can help me.
    i’m writing a little DSL for defining via ERM a database. So i need to make a cross reference when i want a ‘foreign key’ –> i rode a lot on stackoverflow and so on and got a good solution but not the Solution.
    so at the moment it looks like that:

    … (‘foreign key’ verweis = [column|QualifiedName])? …

    ….
    QualifiedName:
    ID (‘.’ ID)*;

    when i want to create a DSL it works fine – but i only want to reference to an other Table.column. Cause so how it is its also possible to refernece to a column in the same Table (so want to have something that the user have to type first an other tablename and then gets only the columns in this table)

    Hope you can help me

    • September 26, 2014 at 10:35

      Hi i do not get your point. maybe you want to adapt scoping

      • Stefan
        September 26, 2014 at 10:49

        ya something like that. as is wrote. at the moment when i type: “foreign key” the editor will give me all columns from the whole database
        my grammar is something like that:
        Database:
        tables+=Table*
        dataTypes += DataType*
        ;

        Table:
        ‘Table’ name=ID ‘{‘
        columns+=column*
        ‘}';

        column:
        ‘Spalte’ name=ID (‘:’ type = [DataType]) (‘primarykey’ pk ?= Bool (‘startValue’ sv = INT)?’,’)? (‘auto increment’ ai = Bool ‘,’)? (‘foreign key’ verweis = [Spalte|QualifiedName])?
        ;

        not complete so far..
        and as in my first post the Qualifiedname
        so when i want to type the foreign key i get all columns – thats the probelem. i need a solution how i can only for this case change the scope or something to make it only possible to choose a column from an other Table – cause referencing on him self or others in the same Table isnt that what i want to.

        sure i could make a validator but then i would be a contradiction cause why should it be an error when the editor suggest it.

        hope its more clear what my problem is

      • September 26, 2014 at 11:03

        i still do not get the point. yes you get all colums but that is indented if you do want to restrict this (i did not get the criteria so far) you have to adapt scoping e.g. by filtering delegateGetScope or by manually adding all possible colums to the scope.

  10. Stefan
    September 26, 2014 at 11:28

    okay.. sorry for my questions.your answers are right but i search for an how to.. cause i only want that in that case of foreign key and not always or is there something i didnt get – got some tutorials for filtering scope but i thought that will filter the scope always? sorry thats my first time using xtext and its a little difficult for me. so i found that point in a book – i will read that part.
    thanks anyways

    • September 26, 2014 at 11:39

      ok in the xtext forum at eclipse there are tons of examples as well

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: