Eclipse Xtext Naming

Name Provider

The name provider is responsible for giving a name to an object so that it may be referenced. The following uses naming:

The default behavior uses the following conventions:

If an object has a feature with a string-type, whose name is 'name', the default name provider implementation will use the value of that feature for calculating the name of an object.

Magic Names

Generally names can be anything except the following have special meaning:

Syntax Element Means
name Supports cross referencing. If an object has a feature with a string-type, whose name is 'name', the default name provider implementation will use the value of that feature for calculating the name of an object.

URI of a model file whose objects should be made visible. Supports URI import of a particular file like this:
Import: 'import' importURI=STRING;

Where STRING is a rule with string value

importedNamespace A namespace import normally looks as follows:
Import: 'import' importedNamespace=FqnWithWildCard;
FqnWithWildCard: Fqn('.*')?;

There is more information about how these are used on this page also on this Itimus blog.


Why does this grammar work?

Import returns EuclidImport :
'import' (
  | importedNamespace=QualifiedNameWithWildCard) ';'?

But not this?

Import returns EuclidImport :
'import'  importedNamespace=QualifiedName ('.' '*')?  ';'?

Qualified Names

When we build an EMF model using xtext then there is a natural heirarchy (tree structure). When a rule is used within another rule this generates a containment relationship.

We can therefore specify any object incidence of an in the runtime model by using its qualified name. This is a string formed from the names of the objects, starting at the model root and ending at the object instance required. These names can be separated with a dot '.' to form a single string.

qualified names

If we specify the QualifiedNamesFragment in the mwe2 file:
fragment = exporting.QualifiedNamesFragment {}

and we have a rule like this:

QualifiedName: ID ('.' ID)*;

in our grammar then we can identify any object in the files containment heirchy by specifying its heirchy of names separated by dots '.'. Provided that each level has a name.

qualified name

For a quide to value convertors see the screencast on the Boris Brodski site.

Runtime Issues

We have looked at how QualifiedNames are defined in the grammar file and so get into the Ecore model. We now need to know how these are used at runtime when our DSL is working and how this can be used as a destination for our non-containment links. naming index table

I think it would help with debugging programs if there were a utility that could be run in the runtime UI(second instance of Eclipse) so that, when the user clicked on an object, its qualified name were dispayed if it had one.

Since I can't find such a tool, I have appropriated the 'outline view' for such a purpose by setting the labels to the qualified name. Obviously this is not the best solution since we probably wan't to use the outline view for other things. It would be good if the developers could provide a view for this purpose.
package com.euclideanspace.importTest.ui.labeling;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.xtext.naming.IQualifiedNameProvider;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.xbase.ui.labeling.XbaseLabelProvider; 

 * Provides labels for a EObjects.
public class MyTestLabelProvider extends XbaseLabelProvider {

	public MyTestLabelProvider(AdapterFactoryLabelProvider delegate) {

	private IQualifiedNameProvider nameProvider;

	public String text(EObject eObject) {
	  QualifiedName qn = nameProvider.getFullyQualifiedName(eObject);
	  if (qn==null) return "no qualified name";
	  return qn.toString();

Other Naming Conventions

STRING enclosed in single or double quotes

Simple Test Example

So lets build a very simple xtext project to experiment with naming.

I just created an xtext project, entered the grammar below and generated the project

naming 1
grammar com.euclideanspace.naming.Example with org.eclipse.xtext.common.Terminals

generate example ""

Model: a+=A*;
A: 'a' name=ID
  ('{' b+=B* '}')?;

B: 'b' name=ID;
When we start this program up in a new instance of eclipse we can enter in various names such as the input text below. naming 2
a tom
a dick
a tom
a dick {b harry b tom}

There does not appear to be any restriction on the names, for instance, there is nothing to stop us from using duplicate names.

As you can see, the names are used to represent the elements in the outline view.

If we want to force names to be unique then we need to uncomment the following line in the mwe2 file in the JavaValidatorFragment . Then regenerate: naming 3
composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
Now names are forced to be unique. But only within a given object, we can reuse the same name across two different objects. We can see here that the name 'tom' is used in object 'a' and again in object 'b' without error. It can also be reused in different outer objects. Its only duplications within the same object that are prevented. naming 4

So to summarise, the checking of names depends on the fragments included in the mwe2 file:

Fragments Included Effect on Naming
exporting.SimpleNamesFragment duplicates allowed,
no '.' allowed in names
exporting.QualifiedNamesFragment duplicates allowed

composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator

duplicates prevented anywhere within the whole file.

composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator


duplicates prevented only within a given object.

Further Reading

QualifiedName implements Comparable
QualifiedName structures a name as a list of segments.
some of the methods availible are:

public static QualifiedName create(String... segments)
public static QualifiedName create(List segments)
public static QualifiedName create(String singleSegment)
public static  Function<F, QualifiedName> wrapper(final Function<F, String> nameFunction)
return new Function<F, QualifiedName>()
public QualifiedName apply(F from)
public boolean isEmpty()
public List<String> getSegments()
public int getSegmentCount()
public String getSegment(int index)
public String getLastSegment()
public String getFirstSegment()
public QualifiedName append(String segment)
public QualifiedName append(QualifiedName relativeQualifiedName)
public QualifiedName skipFirst(int skipCount)
public QualifiedName skipLast(int skipCount)
public QualifiedName toLowerCase()
public QualifiedName toUpperCase()
public interface IQualifiedNameProvider extends Function<EObject, QualifiedName>
/** return the qualified name for the given object*/
QualifiedName getFullyQualifiedName(EObject obj);

abstract class AbstractImpl implements IQualifiedNameProvider {
public QualifiedName apply(EObject from) {
return getFullyQualifiedName(from);
@Inject private IQualifiedNameConverter qualifiedNameConverter;

public QualifiedName getFullyQualifiedName(EObject obj) 
public interface EObjectDescription extends EObject, IEObjectDescription
String getFragment();
void setFragment(String value);
EMap<String, String> getUserData();
void unsetUserData();
boolean isSetUserData();

metadata block
see also: itemis blog
Correspondence about this page

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2022 Martin John Baker - All rights reserved - privacy policy.