| <!DOCTYPE html> |
| <html> |
| |
| <head> |
| <meta charset="UTF-8"> |
| <title>Xtext - Configuration</title> |
| |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <meta name="description" |
| content="The website of Eclipse Xtext, an open-source framework for development of programming languages and domain-specific languages"> |
| <meta name="author" content="Sven Efftinge"> |
| <meta name="author" content="Miro Spoenemann"> |
| <!-- styles --> |
| <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements --> |
| <!--[if lt IE 9]> |
| <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> |
| <![endif]--> |
| |
| <!-- Le fav and touch icons --> |
| <link rel="shortcut icon" href="/Xtext/images/favicon.png"> |
| |
| <link href="/Xtext/css/bootstrap.css" rel="stylesheet" type='text/css'> |
| <link href="/Xtext/css/bootstrap-responsive.css" rel="stylesheet" type='text/css'> |
| <link href="/Xtext/css/shield-responsive.css" rel="stylesheet" type='text/css'> |
| <link href='/Xtext/css/fonts.css' rel='stylesheet' type='text/css'> |
| <link href="/Xtext/css/prettyPhoto.css" rel="stylesheet" media="screen" type='text/css'> |
| <link href="/Xtext/css/prettify.css" type="text/css" rel="stylesheet"/> |
| <link href="/Xtext/css/style.css" rel="stylesheet" type='text/css'> |
| <!-- cover flow --> |
| <link href="/Xtext/css/coverflow.css" rel="stylesheet" type='text/css'> |
| <!--[if lt IE 9]> |
| <link href="/css/iebugs.css" rel="stylesheet" type='text/css'> |
| <![endif]--> |
| |
| <!-- BEGIN Cookie Consent |
| <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.css" /> |
| <script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.js"></script> |
| <script> |
| window.addEventListener("load", function(){ |
| window.cookieconsent.initialise({ |
| "palette": { |
| "popup": { |
| "background": "#000" |
| }, |
| "button": { |
| "background": "#f1d600" |
| } |
| }, |
| "theme": "edgeless", |
| "type": "opt-in", |
| onInitialise: function (status) { |
| var type = this.options.type; |
| var didConsent = this.hasConsented(); |
| if (type == 'opt-in' && didConsent) { |
| // TODO: enable cookies |
| } |
| if (type == 'opt-out' && !didConsent) { |
| // TODO: disable cookies |
| } |
| }, |
| onStatusChange: function(status, chosenBefore) { |
| var type = this.options.type; |
| var didConsent = this.hasConsented(); |
| if (type == 'opt-in' && didConsent) { |
| // TODO: enable cookies |
| } |
| if (type == 'opt-out' && !didConsent) { |
| // TODO: disable cookies |
| } |
| }, |
| onRevokeChoice: function() { |
| var type = this.options.type; |
| if (type == 'opt-in') { |
| // TODO: disable cookies |
| } |
| if (type == 'opt-out') { |
| // TODO: enable cookies |
| } |
| }, |
| "content": { |
| "href": "http://www.eclipse.org/legal/privacy.php" |
| } |
| })}); |
| </script> |
| END Cookie Consent --> |
| </head> |
| |
| |
| <body> |
| |
| <header class="site-header"> |
| |
| <!-- Navbar --> |
| <div class="navbar navbar-fixed-top"> |
| <div class="navbar-inner"> |
| <div class="container"> |
| <a class="btn btn-navbar" data-toggle="collapse" |
| data-target=".nav-collapse"> <span class="icon-bar"></span> <span |
| class="icon-bar"></span> <span class="icon-bar"></span> |
| </a> <a class="brand" href="/Xtext/index.html"></a> |
| <div class="nav-collapse collapse" style="height: 0px;"> |
| <ul class="nav"> |
| <!--li ><a href="/Xtext/news.html">News</a></li--> |
| <li ><a href="/Xtext/download.html">Download</a></li> |
| <li ><a href="/Xtext/documentation/index.html">Documentation</a></li> |
| <li ><a href="/Xtext/community.html">Community</a></li> |
| <li class="dropdown"> |
| <a class="dropdown-toggle" data-toggle="dropdown" href="#">Support & Trainings<span class="caret"></span></a> |
| <ul class="dropdown-menu"> |
| <li><a href="https://www.itemis.com/en/xtext/support-and-team/" target="_blank">itemis</a></li> |
| <li><a href="https://www.typefox.io/language-engineering/" target="_blank">TypeFox</a></li> |
| </ul> |
| </li> |
| <li ><a href="http://xtend-lang.org">Xtend</a></li> |
| </ul> |
| <!--div class="nav pull-right"> |
| <li ><a><iframe src="https://ghbtns.com/github-btn.html?user=eclipse&repo=xtext&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px"></iframe></a></li> |
| </div--> |
| </div> |
| <!--/.nav-collapse --> |
| </div> |
| </div> |
| </div> |
| <!-- Navbar End --> |
| |
| </header> |
| |
| |
| <div class="page-content"> |
| <script> |
| function startSearch(event) { |
| if (event.keyCode == 13) { |
| var q = 'site:eclipse.org/Xtext/documentation+' + event.target.value; |
| window.open('https://www.google.com/search?q=' + q, "_self"); |
| } |
| } |
| </script> |
| <div class="wrapper"> |
| <div id="page"> |
| <div class="inner"> |
| <div id="maincontainer" class="container"> |
| <span class="edit-on-github pull-right"> |
| <a href="https://github.com/eclipse/xtext/edit/website-published/xtext-website/documentation/302_configuration.md">Edit on Github</a> |
| </span> |
| <div class="span3" style="margin-left: 0px;"> |
| <div class="search-bar"> |
| <img src="/Xtext/images/search-gray.png"/> |
| <input type="search" id="google-search" onkeyup="startSearch(event);"/> |
| </div> |
| <ul id="nav-outline" style="margin-left: 0px;"> |
| <li class="nav-part">Getting Started</li> |
| <li><a href="102_domainmodelwalkthrough.html">15 Minutes Tutorial</a></li> |
| <li><a href="103_domainmodelnextsteps.html">15 Minutes Tutorial - Extended</a></li> |
| <li><a href="104_jvmdomainmodel.html">Five simple steps to your JVM language</a></li> |
| |
| <li class="nav-part">Reference Documentation</li> |
| <li><a href="301_grammarlanguage.html">The Grammar Language</a></li> |
| <li><a href="302_configuration.html">Configuration</a></li> |
| <li><a href="303_runtime_concepts.html">Language Implementation</a></li> |
| <li><a href="305_xbase.html">Integration with Java</a></li> |
| <li><a href="307_special_languages.html">Typical Language Configurations</a></li> |
| <li><a href="308_emf_integration.html">Integration with EMF</a></li> |
| <li><a href="310_eclipse_support.html">Eclipse Support</a></li> |
| <li><a href="330_web_support.html">Web Editor Support</a></li> |
| <li><a href="340_lsp_support.html">LSP Support</a></li> |
| <li><a href="350_continuous_integration.html">Continuous Integration</a></li> |
| </ul> |
| </div> |
| <div class="span8 doc-contents"> |
| <h1 id="configuration">Configuration</h1> |
| |
| <p>Xtext offers two levels on which you can configure your language: the language generator and dependency injection. The language generator uses a special DSL called MWE2 to configure the generator.</p> |
| |
| <h2 id="short-intro-to-mwe">A Short Introduction to MWE2</h2> |
| |
| <p>MWE2 (Modeling Workflow Engine) allows to compose object graphs declaratively in a very compact manner. The nice thing about it is that it just instantiates Java classes and the configuration is done through public setter and adder methods as known from Java Beans encapsulation principles. More in-depth information can be found in the <a href="https://github.com/eclipse/mwe/blob/master/documentation/mwe2.md">MWE2 documentation</a>.</p> |
| |
| <p>Given the following simple Java class (POJO):</p> |
| |
| <pre><code class="language-java">package com.mycompany; |
| |
| public class Person { |
| |
| private String name; |
| |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| private final List<Person> children = new ArrayList<Person>(); |
| |
| public void addChild(Person child) { |
| this.children.add(child); |
| } |
| } |
| </code></pre> |
| |
| <p>One can create a family tree with MWE2 easily by describing it in a declarative manner without writing a single line of Java code and without the need to compile classes:</p> |
| |
| <pre><code class="language-mwe2">module com.mycompany.CreatePersons |
| |
| Person { |
| name = "Grandpa" |
| child = Person { |
| name = "Father" |
| child = { |
| name = "Son" |
| } |
| } |
| } |
| </code></pre> |
| |
| <p>These few lines will, when interpreted by MWE2, result in an object tree consisting of three instances of <em>com.mycompany.Person</em>. The interpreter will basically do the same as the following <em>main</em> method:</p> |
| |
| <pre><code class="language-java">package com.mycompany; |
| |
| public class CreatePersons { |
| public static void main(String[] args) { |
| Person grandpa = new Person(); |
| grandpa.setName("Grandpa"); |
| Person father = new Person(); |
| father.setName("Father"); |
| grandpa.addChild(father); |
| Person son = new Person(); |
| son.setName("Son"); |
| father.addChild(son); |
| } |
| } |
| </code></pre> |
| |
| <p>And this is how it works: The root element is a plain Java class name. As this MWE2 module is a sibling to the class <em>com.mycompany.Person</em> it is not necessary to use fully qualified name. The constructed objects are furthermore configured according to the declaration in the module, i.e. a second instance of Person is created and added to the list of children of “Grandpa” while the third person becomes a child of “Father”. All three instances will have their respective <em>name</em> assigned via a reflective invocation of the <em>setName</em> method. Note that in this example the <em>Person</em> type for “Father” is given explicitly, while for “Son” it is inferred from the assigned feature <em>child</em>.</p> |
| |
| <p><em>Hint: Whenever you are in an *.mwe2 file and wonder what kind of configuration the underlying component may accept: Just use content assist (ctrl + space) in the MWE2 Editor or navigate directly to the declaration of the underlying Java implementation by means of F3 (Go To Declaration).</em></p> |
| |
| <p>Another frequently used feature of MWE2 is <em>variables</em>, which can be declared with <code>var</code> as shown below. Such a variable can be reset from outside when calling the module, e.g. allowing to use different settings when calling it from a Maven build. You can refer the variables inside strings using the <code>${variable-name}</code> notation.</p> |
| |
| <pre><code class="language-mwe2">module com.mycompany.CreatePersons |
| |
| var surname = "Johnson" |
| |
| Person { |
| name = "John ${surname}" |
| child = { |
| name = "Jim ${surname}" |
| } |
| child = { |
| name = "Jane ${surname}" |
| } |
| } |
| </code></pre> |
| |
| <p>Although arbitrary Java classes can be used, the standard root element for MWE2 files is <a href="https://github.com/eclipse/mwe/blob/v2.12.1/plugins/org.eclipse.emf.mwe2.runtime/src/org/eclipse/emf/mwe2/runtime/workflow/Workflow.java">Workflow</a>, which is part of the very slim runtime model shipped with MWE2. It accepts <em>beans</em> and <em>components</em>.</p> |
| |
| <ul> |
| <li> |
| <p>The method Workflow.addBean(Object) provides a means to apply global side-effects, which unfortunately is required sometimes. For instance, <a href="https://github.com/eclipse/mwe/blob/v2.12.1/plugins/org.eclipse.emf.mwe.utils/src/org/eclipse/emf/mwe/utils/StandaloneSetup.java">StandaloneSetup</a> can be used to initialize global EMF metadata such as the <a href="https://git.eclipse.org/r/plugins/gitiles/emf/org.eclipse.emf/+/refs/tags/R2_20_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EPackage.java">EPackage.Registry</a>.</p> |
| </li> |
| <li> |
| <p>The method Workflow.addComponent(..) accepts instances of <a href="https://github.com/eclipse/mwe/blob/v2.12.1/plugins/org.eclipse.emf.mwe2.runtime/src/org/eclipse/emf/mwe2/runtime/workflow/IWorkflowComponent.java">IWorkflowComponent</a>, which is the primary concept of the workflow model of MWE2. The language generator component itself is an instance of IWorkflowComponent and can therefore be used within MWE2 workflows.</p> |
| </li> |
| </ul> |
| |
| <p>We will now have a look at the component model used to configure the Xtext language generator.</p> |
| |
| <h2 id="generator">The Language Generator</h2> |
| |
| <p>Xtext provides a lot of generic implementations for the infrastructure of your language, but also uses code generation to create specialized components. Such generated components are for instance the parser, the serializer, the inferred Ecore model (if any) and a couple of convenient base classes for further configuration. The generator also contributes to shared project resources such as the <em>plugin.xml</em>, <em>MANIFEST.MF</em> and the <a href="#guicemodules">Guice modules</a>.</p> |
| |
| <p>This documentation is about the new generator infrastructure introduced with Xtext 2.9. In order to migrate an older Xtext project to this new infrastructure, the recommended approach is to create a new Xtext project and copy the grammar and existing configuration from the old project to the new one step by step.</p> |
| |
| <p>The entry point for Xtext code generation is <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/XtextGenerator.java">XtextGenerator</a>, which is composed of a <em>general configuration</em> and a set of <em>language configurations</em>. The general configuration describes the structure of your project as well as general settings for generating code. Each language configuration corresponds to a specific grammar file and allows to configure the generated code for the respective language. The actual code generation is performed by <em>generator fragments</em> contained in a language configuration.</p> |
| |
| <p>In the following we see an exemplary language generator configuration written in MWE2:</p> |
| |
| <pre><code class="language-mwe2">module org.example.domainmodel.GenerateDomainmodel |
| |
| import org.eclipse.xtext.xtext.generator.* |
| import org.eclipse.xtext.xtext.generator.model.project.* |
| |
| var rootPath = ".." |
| |
| Workflow { |
| component = XtextGenerator { |
| configuration = { |
| project = StandardProjectConfig { |
| baseName = "org.example.domainmodel" |
| rootPath = rootPath |
| eclipsePlugin = { |
| enabled = true |
| } |
| createEclipseMetaData = true |
| } |
| code = { |
| encoding = "UTF-8" |
| } |
| } |
| language = StandardLanguage { |
| name = "org.example.domainmodel.Domainmodel" |
| fileExtensions = "dmodel" |
| |
| serializer = { |
| generateStub = false |
| } |
| } |
| } |
| } |
| </code></pre> |
| |
| <p>This example is similar to the workflows generated by the Xtext project wizard when you create new projects. It uses two convenience classes <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/model/project/StandardProjectConfig.java">StandardProjectConfig</a> and <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/StandardLanguage.java">StandardLanguage</a>, both of which are designed to apply default configurations that work for the majority of language projects.</p> |
| |
| <h3 id="project-configuration">Project Configuration</h3> |
| |
| <p>The Xtext generator needs to know the structure of your project in order to generate code into the correct paths. The base class for describing the project structure is <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/model/project/XtextProjectConfig.java">XtextProjectConfig</a>. It is composed of several descriptors for the individual subprojects:</p> |
| |
| <ul> |
| <li><code>runtime</code> – The basic language features: grammar definition, parser, serializer, scoping, validation, etc.</li> |
| <li><code>runtimeTest</code> – Unit tests for <code>runtime</code></li> |
| <li><code>genericIde</code> – Platform-independent IDE features such as services for content assist</li> |
| <li><code>eclipsePlugin</code> – Integration plug-in for Eclipse</li> |
| <li><code>eclipsePluginTest</code> – Unit tests for <code>eclipsePlugin</code></li> |
| <li><code>web</code> – Integration into web applications</li> |
| </ul> |
| |
| <p>These subprojects are of type <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/model/project/SubProjectConfig.java">SubProjectConfig</a> and offer important parameters:</p> |
| |
| <ul> |
| <li><code>enabled</code> – whether the subproject is present or not</li> |
| <li><code>name</code> – the name of the subproject</li> |
| <li><code>root</code> – the path to the root folder of the subproject</li> |
| <li><code>src</code> – the path to the folder for Java source files</li> |
| <li><code>srcGen</code> – the path to the folder for generated Java source files</li> |
| <li><code>manifest</code> – configuration for the MANIFEST.MF file</li> |
| <li><code>pluginXml</code> – configuration for the plugin.xml file</li> |
| </ul> |
| |
| <p>Since setting all these parameters manually would be tedious and the structure of most Xtext projects is quite similar, it is advisable to use the <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/model/project/StandardProjectConfig.java">StandardProjectConfig</a> as shown in our example above. This specialized project configuration applies default values to all parameters, so you only have to specify those where you wish to override the defaults. For example, given the configuration</p> |
| |
| <pre><code class="language-mwe2">project = StandardProjectConfig { |
| baseName = "org.example.domainmodel" |
| rootPath = rootPath |
| eclipsePlugin = { |
| enabled = true |
| } |
| createEclipseMetaData = true |
| } |
| </code></pre> |
| |
| <p>we obtain a runtime project with the name <code>org.example.domainmodel</code>, an Eclipse integration project with the name <code>org.example.domainmodel.ui</code>, and a generic IDE project with the name <code>org.example.domainmodel.ide</code> (the generic IDE project is enabled automatically if any integration project is enabled). The source folder, MANIFEST.MF and plugin.xml paths are set to the defaults for Eclipse plug-in projects. If you don’t want a separate IDE project you can merge its content into another subproject by assigning it the same name:</p> |
| |
| <pre><code class="language-mwe2">project = StandardProjectConfig { |
| baseName = "org.example.domainmodel" |
| rootPath = rootPath |
| genericIde = { |
| name = "org.example.domainmodel.ui" |
| } |
| eclipsePlugin = { |
| enabled = true |
| } |
| createEclipseMetaData = true |
| } |
| </code></pre> |
| |
| <p>This leads to the generic IDE code being generated into the Eclipse integration plug-in.</p> |
| |
| <h3 id="other-general-configuration">Other General Configuration</h3> |
| |
| <p>The configuration block of our generator workflow example above contains a <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/CodeConfig.java">CodeConfig</a> as sibling of <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/model/project/StandardProjectConfig.java">StandardProjectConfig</a>. As the name suggests, the parameters of CodeConfig influence the generated code:</p> |
| |
| <ul> |
| <li><code>encoding</code> – The character encoding</li> |
| <li><code>fileHeader</code> – The file header comment to insert at the beginning of each file</li> |
| <li><code>preferXtendStubs</code> – Whether to prefer Xtend over Java for stub files to be implemented manually; this option applies only to files in <code>src</code> folders, while for <code>src-gen</code> folders Java files are always generated.</li> |
| </ul> |
| |
| <p>The container for the <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/model/project/StandardProjectConfig.java">StandardProjectConfig</a> and <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/CodeConfig.java">CodeConfig</a> is of type <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/DefaultGeneratorModule.java">DefaultGeneratorModule</a> and is assigned to the property <code>configuration</code> of the <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/XtextGenerator.java">XtextGenerator</a>. The DefaultGeneratorModule is actually a <a href="https://github.com/google/guice">Guice</a> module, which can be subclassed in a similar way as explained in <a href="#dependency-injection">Dependency Injection</a> for overriding default configurations. This allows to alter the configuration in places that are not accessible through MWE2. For instance, you could bind your own subclass of <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/XtextGeneratorNaming.java">XtextGeneratorNaming</a> in order to influence the names of generated classes.</p> |
| |
| <h3 id="language-configuration">Language Configuration</h3> |
| |
| <p>The base class for describing a language configuration is <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/XtextGeneratorLanguage.java">XtextGeneratorLanguage</a>, whose most important parameters are</p> |
| |
| <ul> |
| <li><code>name</code> – The name of the language exactly as specified in the first line of your grammar definition</li> |
| <li><code>grammarUri</code> – A <a href="https://git.eclipse.org/r/plugins/gitiles/emf/org.eclipse.emf/+/refs/tags/R2_20_0/plugins/org.eclipse.emf.common/src/org/eclipse/emf/common/util/URI.java">URI</a> pointing to the grammar definition file; if omitted, the grammar file is assumed to be in the Java source folder of the runtime project and to be named according to the language name.</li> |
| <li><code>fileExtensions</code> – A comma-separated list of file extensions for the language</li> |
| <li><code>referencedResources</code> – Additional resources to load (see <a href="#importing-metamodels">Importing Existing Metamodels</a>)</li> |
| </ul> |
| |
| <p>The actual code generation is performed by <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/IXtextGeneratorFragment.java">generator fragments</a>, which can be added to a language configuration using the <code>fragment</code> property. The Xtext project wizard creates a workflow that employs the <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/StandardLanguage.java">StandardLanguage</a>, which specializes XtextGeneratorLanguage in a similar way as StandardProjectConfig specializes XtextProjectConfig (see <a href="#project-configuration">Project Configuration</a>). The main contribution of StandardLanguage is a default list of generator fragments that includes all features of Xtext. These fragments automatically adapt their generated code to your language and project configuration. Some fragments offer their own configuration parameters, hence each fragment can be accessed via a dedicated property in StandardLanguage. For instance, in the language configuration</p> |
| |
| <pre><code class="language-mwe2">language = StandardLanguage { |
| name = "org.example.domainmodel.Domainmodel" |
| fileExtensions = "dmodel" |
| |
| serializer = { |
| generateStub = false |
| } |
| } |
| </code></pre> |
| <p>we see the <code>generateStub</code> parameter disabled for the <code>serializer</code> fragment, which means that the fragment should not create any stub file for customizing serialization.</p> |
| |
| <p>It is not possible to remove fragments from the <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/StandardLanguage.java">StandardLanguage</a>. If you need a language configuration where one or more of the default fragments are omitted, you can do so by using <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/XtextGeneratorLanguage.java">XtextGeneratorLanguage</a> instead and listing the required fragments explicitly. You can take the following configuration as a template:</p> |
| |
| <pre><code class="language-mwe2">language = XtextGeneratorLanguage { |
| name = "org.example.domainmodel.Domainmodel" |
| fileExtensions = "dmodel" |
| referencedResource = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel" |
| |
| fragment = grammarAccess.GrammarAccessFragment2 {} |
| fragment = ecore.EMFGeneratorFragment2 {} |
| fragment = serializer.SerializerFragment2 {} |
| fragment = resourceFactory.ResourceFactoryFragment2 {} |
| fragment = parser.antlr.XtextAntlrGeneratorFragment2 {} |
| fragment = validation.ValidatorFragment2 {} |
| fragment = scoping.ImportNamespacesScopingFragment2 {} |
| fragment = exporting.QualifiedNamesFragment2 {} |
| fragment = builder.BuilderIntegrationFragment2 {} |
| fragment = generator.GeneratorFragment2 {} |
| fragment = formatting.Formatter2Fragment2 {} |
| fragment = ui.labeling.LabelProviderFragment2 {} |
| fragment = ui.outline.QuickOutlineFragment2 {} |
| fragment = ui.outline.OutlineTreeProviderFragment2 {} |
| fragment = ui.quickfix.QuickfixProviderFragment2 {} |
| fragment = ui.contentAssist.ContentAssistFragment2 {} |
| fragment = junit.JunitFragment {} |
| fragment = ui.refactoring.RefactorElementNameFragment2 {} |
| fragment = types.TypesGeneratorFragment2 {} |
| fragment = xbase.XtypeGeneratorFragment2 {} |
| fragment = xbase.XbaseGeneratorFragment2 {} |
| fragment = ui.templates.CodetemplatesGeneratorFragment2 {} |
| fragment = ui.compare.CompareFragment2 {} |
| fragment = web.WebIntegrationFragment { |
| framework = "Ace" |
| } |
| fragment = ui.projectWizard.TemplateProjectWizardFragment {} |
| fragment = ui.fileWizard.TemplateFileWizardFragment {} |
| } |
| </code></pre> |
| |
| <h3 id="importing-metamodels">Importing Existing Metamodels</h3> |
| |
| <p>As explained in the <a href="301_grammarlanguage.html#epackage-import">grammar language reference</a> it is possible to import existing metamodels into your language definition.</p> |
| |
| <p>You can use namespace URIs in your grammar file in order to import existing EPackages. This is generally preferable, and other URI schemes are considered deprecated. With a namespace URI the package will be read from the Xtext index and therefore your grammar is independent from the concrete location of the respective ecore file. You have to make sure though that the ecore file is contained in a project that is managed by Xtext. Therefore the project has to have the Xtext project nature attached. Ecore files that reside in referenced Java archives (JARs) are automatically picked up and indexed if the referencing project itself is an Xtext project.</p> |
| |
| <p>In order to be able to find the referenced package in the language generator, its Ecore generator model has to be mentioned in the language configuration:</p> |
| |
| <pre><code class="language-mwe2">language = StandardLanguage { |
| name = "org.example.domainmodel.Domainmodel" |
| fileExtensions = "dmodel" |
| referencedResource = |
| "platform:/resource/org.example.domainmodel/model/Domainmodel.genmodel" |
| } |
| </code></pre> |
| |
| <p>If you are importing more than one metamodel, you can add more <code>referencedResource</code> declarations as required.</p> |
| |
| <p>In some occasions this simple way of referencing metamodels is not sufficient; you can then use the <a href="https://github.com/eclipse/mwe/blob/v2.12.1/plugins/org.eclipse.emf.mwe.utils/src/org/eclipse/emf/mwe/utils/StandaloneSetup.java">StandaloneSetup</a> as a Workflow bean for fine-tuning your EMF setup. Example:</p> |
| |
| <pre><code class="language-mwe2">bean = StandaloneSetup { |
| platformUri = "${rootPath}" |
| scanClassPath = true |
| registerGeneratedEPackage = "my.project.DomainmodelPackage" |
| registerGenModelFile = "platform:/resource/my.project/model/Domainmodel.genmodel" |
| } |
| </code></pre> |
| |
| <hr /> |
| |
| <h2 id="dependency-injection">Dependency Injection</h2> |
| |
| <p>All Xtext components are assembled by means of dependency injection (DI). This means basically that whenever some code is in need for functionality (or state) from another component, one just declares the dependency rather than stating how to resolve it, i.e. obtaining that component.</p> |
| |
| <p>For instance when some code wants to use a scope provider, it just declares a field (or method or constructor) and adds the <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Inject.html">Inject</a> annotation:</p> |
| |
| <pre><code class="language-java">public class MyLanguageLinker extends Linker { |
| |
| @Inject |
| private IScopeProvider scopeProvider; |
| |
| } |
| </code></pre> |
| |
| <p>It is not the duty of the client code to care about where the <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/scoping/IScopeProvider.java">IScopeProvider</a> implementation comes from or how it is created. When the above class is instantiated, Guice sees that it requires an instance of IScopeProvider and assigns it to the specified field or method parameter. This of course only works if the object itself is created by Guice. In Xtext almost every instance is created that way and therefore the whole dependency net is controlled and configured by the means of Guice.</p> |
| |
| <p>Guice of course needs to know how to instantiate real objects for declared dependencies. This is done in so-called Modules. A <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Module.html">Module</a> defines a set of mappings from types to either existing instances, instance providers or concrete classes. Modules are implemented in Java. Here’s an example:</p> |
| |
| <pre><code class="language-java">public class MyDslRuntimeModule implements Module { |
| |
| @Override |
| public void configure(Binder binder) { |
| binder |
| .bind(IScopeProvider.class) |
| .to(MyConcreteScopeProvider.class); |
| } |
| } |
| </code></pre> |
| |
| <p>With plain Guice modules one implements a method called configure and gets a <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Binder.html">Binder</a> passed in. That binder provides a fluent API to define the mentioned mappings.</p> |
| |
| <h3 id="guicemodules">The Module API</h3> |
| |
| <p>After running the Xtext generator you get several different modules for your language: one for the base project, one for the generic ide project, and one for each platform integration project. For instance, for a language named <em>Domainmodel</em> we would have a <em>DomainmodelRuntimeModule</em>, a <em>DomainmodelIdeModule</em> (IDE independent UI services), a <em>DomainmodelUiModule</em> (for the Eclipse integration), and a <em>DomainmodelWebModule</em>. The bindings from the runtime module are shared by all integration projects.</p> |
| |
| <p>Xtext comes with a slightly enhanced module API. The abstract base class <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/service/AbstractGenericModule.java">AbstractGenericModule</a> looks reflectively for certain methods in order to find declared bindings. The most common kind of method is</p> |
| |
| <pre><code class="language-java">public Class<? extends IScopeProvider> bindIScopeProvider() { |
| return MyConcreteScopeProvider.class; |
| } |
| </code></pre> |
| |
| <p>which would do the same as the code snippet above. It simply declares a binding from <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/scoping/IScopeProvider.java">IScopeProvider</a> to <em>MyConcreteScopeProvider</em>. That binding will make Guice instantiate and inject a new instance of <em>MyConcreteScopeProvider</em> whenever a dependency to <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/scoping/IScopeProvider.java">IScopeProvider</a> is declared.</p> |
| |
| <p>Having one method per binding allows to deactivate individual bindings by overriding the corresponding methods and either change the binding by returning a different target type or removing that binding completely by returning null.</p> |
| |
| <p>There are two additional kinds of binding-methods supported. The first one allows to configure a <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Provider.html">Provider</a>, which is like a factory for one specific type. This one can be used if you need a hook whenever an instance of a certain type is created. For instance if you want to provide lazy access to a singleton or you need to do some computation each time an instance is created (i.e. factory). If you want to point to a provider rather than to a concrete class you can use the following binding method.</p> |
| |
| <pre><code class="language-java">public Class<? extends Provider<IScopeProvider>> provideIScopeProvider() { |
| return MyConcreteScopeProviderFactory.class; |
| } |
| </code></pre> |
| |
| <p>Note: Please forgive us the overuse of the term <em>provider</em>. The <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/scoping/IScopeProvider.java">IScopeProvider</a> is not a Guice <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Provider.html">Provider</a>.</p> |
| |
| <p>That binding tells Guice to instantiate <em>MyConcreteScopeProviderFactory</em> and invoke get() in order to obtain an instance of <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/scoping/IScopeProvider.java">IScopeProvider</a> for clients having declared a dependency to that type. Both mentioned binding methods are allowed to return an instance instead of a type. This may be useful if some global state should be shared in the application. For a simple instance this would be</p> |
| |
| <pre><code class="language-java">public IScopeProvider bindIScopeProvider() { |
| return new MyConcreteScopeProvider(); |
| } |
| </code></pre> |
| |
| <p>and for a provider binding</p> |
| |
| <pre><code class="language-java">public Provider<IScopeProvider> provideIScopeProvider() { |
| return new MyConcreteScopeProviderFactory(); |
| } |
| </code></pre> |
| |
| <p>The third binding method provided by Xtext allows to do anything you can do with the binding API of Guice, since it allows you to use the <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Binder.html">Binder</a> directly. The name of the method has to start with the ‘configure’, the return type must be <code>void</code>, and it must accept one argument of type <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Binder.html">Binder</a>:</p> |
| |
| <pre><code class="language-java">public void configureIScopeProvider(Binder binder) { |
| binder.bind(IScopeProvider.class).to(MyConcreteScopeProvider.class); |
| } |
| </code></pre> |
| |
| <p>These are the basic ideas around Guice and the small extension Xtext provides on top. For more information we strongly encourage you to read through the documentation on <a href="https://github.com/google/guice">the website of Google Guice</a>.</p> |
| |
| <h3 id="obtaining-an-injector">Obtaining an Injector</h3> |
| |
| <p>In every application wired up with Guice there is usually one point where you initialize an <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Injector.html">Injector</a> using the modules declared. Usually this is done with the static methods of <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Guice.html">Guice</a>. In Xtext, however, you should never instantiate the injector of your language yourself.</p> |
| |
| <p>Xtext may be used in different environments which introduce different constraints. Especially important is the difference between OSGi managed containers and plain vanilla Java programs. To honor these differences Xtext uses the concept of <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/ISetup.java">ISetup</a> implementations in normal mode and uses the extension mechanism of Eclipse when it should be configured in an OSGi environment.</p> |
| |
| <h4 id="runtime-setup">Runtime Setup</h4> |
| |
| <p>For each language there is an implementation of <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/ISetup.java">ISetup</a> generated. It implements a method called <code>createInjectorAndDoEMFRegistration()</code>, which can be called to do the initialization of the language infrastructure.</p> |
| |
| <pre><code class="language-java">public static void main(String[] args) { |
| Injector injector = new MyDslStandaloneSetup().createInjectorAndDoEMFRegistration(); |
| MyApplication application = injector.getInstance(MyApplication.class); |
| application.run(); |
| } |
| </code></pre> |
| |
| <p>The setup method returns an <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Injector.html">Injector</a>, which can further be used to obtain a parser, etc. It also registers the <a href="https://git.eclipse.org/r/plugins/gitiles/emf/org.eclipse.emf/+/refs/tags/R2_20_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/resource/Resource.java">Resource.Factory</a> and generated <a href="https://git.eclipse.org/r/plugins/gitiles/emf/org.eclipse.emf/+/refs/tags/R2_20_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EPackage.java">EPackages</a> to the respective global registries provided by EMF. So basically after having run the setup you can start using EMF API to load and store models of your language.</p> |
| |
| <p><strong>Caveat:</strong> The <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/ISetup.java">ISetup</a> class is intended to be used for runtime and for unit testing, only. If you use it in an Equinox scenario, you will very likely break the running application because entries to the global registries will be overwritten.</p> |
| |
| <h4 id="equinox-setup">Setup within Eclipse-Equinox (OSGi)</h4> |
| |
| <p>Within Eclipse we have a generated <em>Activator</em>, which creates a Guice <a href="https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Injector.html">Injector</a> using the <a href="#guicemodules">modules</a>. In addition an <a href="http://help.eclipse.org/luna/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IExecutableExtensionFactory.html">IExecutableExtensionFactory</a> is generated for each language, which is used to create <a href="http://help.eclipse.org/luna/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IExecutableExtension.html">IExecutableExtensions</a>. This means that everything which is created via extension points is managed by Guice as well, i.e. you can declare dependencies and get them injected upon creation.</p> |
| |
| <p>The only thing you have to do in order to use this factory is to prefix the class with the generated <em>ExecutableExtensionFactory</em> name followed by a colon.</p> |
| |
| <pre><code class="language-xml"><extension point="org.eclipse.ui.editors"> |
| <editor |
| class= |
| "example.MyDslExecutableExtensionFactory:org.eclipse.xtext.ui.editor.XtextEditor" |
| contributorClass= |
| "org.eclipse.ui.editors.text.TextEditorActionContributor" |
| default="true" |
| extensions="mydsl" |
| id="org.eclipse.xtext.example.MyDsl" |
| name="MyDsl Editor"> |
| </editor> |
| </extension> |
| </code></pre> |
| |
| <hr /> |
| |
| <h2 id="logging">Logging</h2> |
| |
| <p>Xtext uses <a href="http://logging.apache.org/log4j/">Apache Log4j</a> for logging. It is configured using files named <em>log4j.properties</em>, which are looked up in the root of the Java class path. If you want to change or provide configuration at runtime (i.e. non-OSGi), all you have to do is putting such a <em>log4j.properties</em> in place and make sure that it is not overridden by other <em>log4j.properties</em> in previous class path entries.</p> |
| |
| <p>In OSGi you provide configuration by creating a fragment for <em>org.apache.log4j</em>. In this case you need to make sure that there is not any second fragment contributing a <em>log4j.properties</em> file.</p> |
| |
| <hr /> |
| |
| <p><strong><a href="303_runtime_concepts.html">Next Chapter: Language Implementation</a></strong></p> |
| |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <footer class="site-footer"> |
| <div id="extra"> |
| <div class="inner"> |
| <div class="container"> |
| <div class="row"> |
| <div class="span6"> |
| <h3 class="footer-links-header">Quick Links</h3> |
| <ul class="footer-links clearfix"> |
| <li><a href="http://www.eclipse.org/legal/privacy.php">Privacy Policy</a></li> |
| <li><a href="http://www.eclipse.org/legal/termsofuse.php">Terms of Use</a></li> |
| <li><a href="http://www.eclipse.org/legal/copyright.php">Copyright Agent</a></li> |
| <li><a href="http://www.eclipse.org/legal/">Legal</a></li> |
| </ul> |
| <ul class="footer-links clearfix"> |
| <li><a href="http://www.eclipse.org">Eclipse Home</a></li> |
| <li><a href="http://marketplace.eclipse.org/">Market Place</a></li> |
| <li><a href="http://www.planeteclipse.org/">Eclipse Planet</a></li> |
| <li><a href="https://www.eclipse.org/forums/index.php/f/27/">Xtext Forum</a></li> |
| </ul> |
| </div> |
| <div class="span6"> |
| <!-- Social Media Links --> |
| <h3 class="footer-links-header"">Social Media</h3> |
| <ul class="footer-links clearfix"> |
| <li> |
| <a href="https://twitter.com/xtext"><img src="/Xtext/images/Twitter-bird-darkgray.png" class="img-responsive" style="margin-right: 5px;height: 1em;" alt="Twitter icon">@xtext on Twitter</a> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <a href="#" class="scrollup fadeOutRight animated" style="display: none;">ScrollUp</a> |
| <!-- Le javascript |
| ================================================== --> |
| <!-- Placed at the end of the document so the pages load faster --> |
| |
| <script src="/Xtext/js/jquery-1.11.3.min.js"></script> |
| <script src="/Xtext/js/bootstrap.min.js"></script> |
| <script src="/Xtext/js/jquery.easing.1.3.js" type="text/javascript"></script> |
| <script src="/Xtext/js/jquery.prettyPhoto.js" type="text/javascript"></script> |
| <script src="/Xtext/js/prettify.js" type="text/javascript"></script> |
| <script src="/Xtext/js/lang-xtend.js" type="text/javascript"></script> |
| <script src="/Xtext/js/lang-common.js" type="text/javascript"></script> |
| <script src="/Xtext/js/custom.js" type="text/javascript"></script> |
| <!--script src="https://apis.google.com/js/platform.js" async defer></script--> |
| <!--script type="text/javascript"> |
| var _gaq = _gaq || []; |
| _gaq.push([ '_setAccount', 'UA-2429174-3' ]); |
| _gaq.push([ '_trackPageview' ]); |
| (function() { |
| var ga = document.createElement('script'); |
| ga.type = 'text/javascript'; |
| ga.async = true; |
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' |
| : 'http://www') |
| + '.google-analytics.com/ga.js'; |
| var s = document.getElementsByTagName('script')[0]; |
| s.parentNode.insertBefore(ga, s); |
| })(); |
| </script--> |
| <script src="/Xtext/js/coverflow.min.js" type="text/javascript"></script> |
| <script> |
| $(function() { |
| $('#coverflow').coverflow({ |
| active : 1, |
| visibleAside: 2, |
| overlap : 0.5, |
| scale : 0.9, |
| angle : 20, |
| trigger : { |
| "itemfocus" : true, |
| "swipe" : true, |
| "mousewheel" : false |
| } |
| }); |
| $('#coverflow :hidden').toggle(); |
| $(window).resize(function() { |
| $('#coverflow').coverflow(); |
| }); |
| }); |
| |
| </script> |
| </footer> |
| |
| |
| </body> |
| |
| </html> |