| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <meta name="generator" content="Asciidoctor 2.0.15"> |
| <title>N4JS Tutorial</title> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> |
| <!-- ************* Meta ************* --> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> |
| |
| <!-- ************* OpenGraph ************--> |
| <meta name="description" content="The Eclipse N4JS language and its IDE enable high-quality JavaScript development for large Node.js projects."> |
| |
| <meta property="og:site_name" content="Eclipse N4JS"/> |
| <meta property="og:title" content="Eclipse N4JS Language and IDE"/> |
| <meta property="og:url" content="https://numberfour.github.io/n4js"/> |
| <meta property="og:description" content="The Eclipse N4JS language and its IDE enable high-quality JavaScript development for large Node.js projects."/> |
| <meta property="og:image" content="../images/n4js.png"> |
| |
| <!-- ************* Favicon ************--> |
| <link rel="icon" href="../images/favicon.ico" /> |
| <link rel="icon" type="image/png" href="../images/favicon-32x32.png" sizes="32x32" /> |
| <link rel="icon" type="image/png" href="../images/favicon-16x16.png" sizes="16x16" /> |
| |
| <!-- ************* Back-to-top JQuery ************* --> |
| <script src="https://code.jquery.com/jquery-1.12.4.js"></script> |
| <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script> |
| |
| <!-- ************* Prism.js Syntax Highlighter ******--> |
| <link href="../styles/prism.min.css" rel="stylesheet"/> |
| <script src="../scripts/prism.js"></script> |
| |
| <!-- ************* Styles ************* --> |
| |
| <link rel="stylesheet" type="text/css" href="../styles/n4js-adoc.css"> |
| |
| <!-- ****************** NavBar ****************** --> |
| <div id="menubar"> |
| <div class="banner"> |
| <a href="../index.html"><img id="logo" src="../images/n4js-logo.png" alt="N4JS Language and IDE"></a> |
| </div> |
| <ul> |
| <li><a href="../downloads.html"></i>Download</a></li> |
| <li><a href="../community.html"></i>Community</a></li> |
| <li><a href="index.html">Documentation</a></li> |
| </ul> |
| </div> |
| <button id="tocbutton">TOC</button> |
| |
| </head> |
| <body class="book toc2 toc-right"> |
| <div id="header"> |
| <div id="toc" class="toc2"> |
| <div id="toctitle">Jump to topic:</div> |
| <ul class="sectlevel0"> |
| <li><a href="#_n4js_tutorial">N4JS Tutorial</a> |
| <ul class="sectlevel1"> |
| <li><a href="#_using_n4js_to_implement_a_node_js_application">Using N4JS to Implement a Node.js Application</a></li> |
| <li><a href="#_creating_a_new_n4js_project">Creating a new N4JS Project</a> |
| <ul class="sectlevel2"> |
| <li><a href="#_the_domain_model">The Domain Model</a></li> |
| <li><a href="#_creating_new_classes_and_modules">Creating new classes and modules</a></li> |
| <li><a href="#_add_an_enumeration">Add an Enumeration</a></li> |
| <li><a href="#_the_storage_layer">The Storage Layer</a></li> |
| <li><a href="#_implement_the_interface">Implement the Interface</a></li> |
| <li><a href="#_edit_the_manifest">Edit the Manifest</a></li> |
| </ul> |
| </li> |
| <li><a href="#_running_a_module">Running a Module</a></li> |
| <li><a href="#_extend_entities_with_spec_constructor">Extend Entities with Spec-Constructor</a></li> |
| <li><a href="#_creating_a_task_manager">Creating a Task Manager</a> |
| <ul class="sectlevel2"> |
| <li><a href="#_make_the_storage_asynchronous">Make the Storage Asynchronous</a></li> |
| <li><a href="#_testing">Testing</a></li> |
| </ul> |
| </li> |
| <li><a href="#_storage_using_mongodb">Storage using MongoDB</a></li> |
| <li><a href="#_dependency_injection">Dependency Injection</a></li> |
| <li><a href="#_web_ui_module">Web UI module</a></li> |
| <li><a href="#_export_as_npm">Export as npm</a></li> |
| <li><a href="#_run_from_command_line_with_node_js">Run from command line with Node.js</a></li> |
| <li><a href="#_bibliography">Bibliography</a></li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div id="content"> |
| <h1 id="_n4js_tutorial" class="sect0"><a class="link" href="#_n4js_tutorial">N4JS Tutorial</a></h1> |
| <div class="openblock partintro"> |
| <div class="content"> |
| <div class="paragraph"> |
| <div class="title">N4JS Tutorial</div> |
| <p><strong>The flexibility of JavaScript with the type safety of Java</strong></p> |
| </div> |
| <div class="paragraph"> |
| <p>N4JS is a language and IDE designed for developers who need to build scalable projects whose code should be |
| modular, reusable and easily maintainable over time. N4JS bridges the strengths of ECMAScript |
| (also known as JavaScript) and Java. The result is a typed JavaScript superset that is dynamic, |
| flexible and type-safe.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Experience with JavaScript or Java?</strong></p> |
| </div> |
| <div class="paragraph"> |
| <p>Developers who are experienced with JavaScript can easily apply their knowledge in N4JS. As N4JS is a |
| typed superset of ECMAScript, it is possible to use plain ECMAScript in N4JS. Most of the important |
| features from ECMAScript 2015 are supported, such as <strong>modules</strong> with import and export, |
| <strong>classes</strong>, <strong>iterables</strong> and <strong>destructuring</strong> of arrays |
| and objects. Developers with Java experience will be familiar with features from Java 8 |
| such as <strong>nominal typing</strong>, <strong>interfaces</strong> and <strong>generic classes |
| and methods</strong>; even dependency injection and testing look similar.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Development Environment</strong></p> |
| </div> |
| <div class="paragraph"> |
| <p>N4JS has an IDE based on Eclipse. It comes with its own workspace, libraries and plugins. The |
| IDE has a transpiler (i.e. a compiler that translates from one language to another) which validates |
| N4JS code and then transforms it to JavaScript. The transpiler also performs imports from ECMAScript |
| to N4JS. The benefit of type safety means that errors in code are noticed while editing in the |
| IDE, allowing for problem-solving before code is ever deployed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Developers who have previous experience using Eclipse will be familiar with most of the common UI features |
| such as Editor, Project Outline, Project Explorer and Console views. The arrangement of views |
| can be easily selected using the perspectives icons as highlighted in the upper-right of the window.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_using_n4js_to_implement_a_node_js_application"><a class="link" href="#_using_n4js_to_implement_a_node_js_application">Using N4JS to Implement a Node.js Application</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The following screenshot shows |
| the most important views of the IDE:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/ide.png" alt="N4JS IDE"> |
| </div> |
| <div class="title">Figure 1. N4JS IDE</div> |
| </div> |
| <div class="paragraph"> |
| <p>In order to illustrate some of the features of N4JS, we shall look at building a Node.js-based |
| server of a Task Manager which serves as a reminder or to-do list application. As we build this |
| basic example, we shall add improvements step-by-step, introducing new features with each |
| increment in order to demonstrate some of the strengths of the language and IDE through a |
| simple practical model.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Before we dive in and start creating our example, it is worth briefly describing the architecture |
| of our application in order to have a considered approach to the concept. In this particular |
| example, we can think of a multi-tiered client-server structure. The idea here is that when we |
| have the application separated, each tier can be reused for different purposes.</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/architecture.svg" alt="Architecture"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>We will start with modeling and implementing the domain model before implementing a first |
| version of the storage tier which will enable our first tests. The controller is then built |
| using a test-driven approach. We later improve the storage tier using a real database |
| before adding a REST API with <a href="http://expressjs.com/">Express</a> and, finally, a simple Web UI.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_creating_a_new_n4js_project"><a class="link" href="#_creating_a_new_n4js_project">Creating a new N4JS Project</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Let’s begin by creating a new N4JS Project that contains our whole application. In case of |
| larger applications, we might want to create projects for each component (or tier) of the |
| application. In order to keep this example small, we will use only one project.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The "New N4JS Project" wizard can be accessed at <span class="menuseq"><b class="menu">File</b> <i class="fa fa-angle-right caret"></i> <b class="submenu">New</b> <i class="fa fa-angle-right caret"></i> <b class="menuitem">N4JS Project</b></span> (Or using the |
| keyboard shortcuts <span class="keyseq"><kbd>⌘</kbd>+<kbd>n</kbd></span> for Mac, <span class="keyseq"><kbd>Alt</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd></span> on Windows)</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/newprojectwizard.png" alt="New Project Wizard" width="700"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When we select <kbd>Finish</kbd>, a new project folder is created with the following content:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>folder <strong>src</strong>: contains the .n4js source files for the project.</p> |
| </li> |
| <li> |
| <p>folder <strong>src-gen</strong>: contains the transpiled JavaScript that is generated after compiling n4js |
| files. The IDE automatically transpiles n4js files on save.</p> |
| </li> |
| <li> |
| <p><strong>manifest.n4mf</strong>: project description file, containing description of dependencies.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect2"> |
| <h3 id="_the_domain_model"><a class="link" href="#_the_domain_model">The Domain Model</a></h3> |
| <div class="paragraph"> |
| <p>Before we start implementing the domain model, we shall take a look at a UML diagram of it:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/domainmodel.svg" alt="domainmodel"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The UML diagram illustrates how the entities of our domain model are related |
| and which features the classes of the model will have. |
| We will begin by defining Task which is extended by Appointment and Todo.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_creating_new_classes_and_modules"><a class="link" href="#_creating_new_classes_and_modules">Creating new classes and modules</a></h3> |
| <div class="paragraph"> |
| <p>In our new N4JS project, we can begin creating our entities. The easiest way to |
| do this is to utilize the New N4JS Class wizard, accessed via <span class="menuseq"><b class="menu">File</b> <i class="fa fa-angle-right caret"></i> <b class="submenu">New</b> <i class="fa fa-angle-right caret"></i> <b class="menuitem">N4JS Class</b></span></p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/newclasswizard.png" alt="newclasswizard" width="700"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>N4JS supports modules introduced by ECMAScript 2015. A module contains functions, |
| classes and other declarations and code. The declared elements can be exported |
| and imported by other modules. We will use a single module for all classes of our |
| domain model. In larger projects, one might follow the Java convention to create |
| a single file per class.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The module specifier is the full path name of the module file, relative to the source |
| folder. We use Unix-like path separators, that is forward slashes "/". In the Class |
| Wizard (and later in import statements) we will omit the file extension.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the above figure, we are creating a new class named Task which will be saved in |
| the module <strong>model</strong> in the project source folder.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_implement_the_entity_classes"><a class="link" href="#_implement_the_entity_classes">Implement the entity classes</a></h4> |
| <div class="paragraph"> |
| <p>The class wizard has already created a file and the empty class "Task". We will |
| manually enhance this class as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export abstract class Task { <i class="conum" data-value="1"></i><b>(1)</b> |
| public id: string?; |
| public label: string?; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>In the first line of code, we have defined an <strong>abstract class</strong> named Task. Classes in |
| N4JS are similar to classes in ECMAScript 2015 or Java. The concept of an abstract |
| class is borrowed from Java. This means that we cannot have a <em>direct instance</em> |
| of Task in our model, but we may have <em>subclasses</em> of Task.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>We are populating the class with fields which are simple data fields of the class. This |
| is also borrowed from Java. The transpiler will move the field (with possible |
| initializers) into the constructor. The two data fields of Task are id and label |
| which we have annotated with types. The N4JS transpiler will later remove these type annotations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The type annotations declare the type of the data field. The type checker will issue |
| errors if we later assign values of a non-compatible type to the variables. The question |
| mark ? is a <strong>type modifier</strong> declaring the value as optional. That means that a new Task |
| may or may not have values assigned for their id and label.</p> |
| </div> |
| <div class="paragraph"> |
| <p>N4JS also provides the concept of <strong>access modifiers</strong> similar to Java with the modifiers |
| public, protected, project and private. Access modifiers constrain the visibility |
| of elements, that is, they restrict from where an element can be accessed.</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>public</code> means that the element can be accessed from everywhere,</p> |
| </li> |
| <li> |
| <p><code>protected</code> may only be accessed from subclasses,</p> |
| </li> |
| <li> |
| <p><code>project</code> only from within the project (this is the default visibility)</p> |
| </li> |
| <li> |
| <p><code>private</code> accessed only from within the same module.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>We now manually add two classes to the same file:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">model.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">/** An appointment. */ <i class="conum" data-value="1"></i><b>(1)</b> |
| export class Appointment extends Task { <i class="conum" data-value="2"></i><b>(2)</b> |
| public time: Date; <i class="conum" data-value="3"></i><b>(3)</b> |
| public place: string; <i class="conum" data-value="3"></i><b>(3)</b> |
| } |
| |
| export class Todo extends Task { |
| public dueDate: Date?; |
| public done = false; <i class="conum" data-value="4"></i><b>(4)</b> |
| } </code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Appointment is prefaced with a <strong>JSDoc</strong> annotation (a comment beginning with /** and |
| closed with */ which documents that it is a single Appointment task. JSDoc comments are |
| used to provide markup annotation of your code. The content of these comments is displayed when |
| you hover over a reference to that element.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>The class Appointment is a <strong>subclass</strong> of Task. This is achieved by using the keyword |
| extends and demonstrates <strong>inheritance</strong>. N4JS supports single class inheritance similar |
| to ECMAScript 2015 or Java. The subclass Appointment will inherit the members |
| id and label with types from Task.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>We add the members time and place with <strong>type annotations</strong>. The |
| type annotations of the members in Appointment are more strict than before, since |
| the optional modifier (denoted by the question mark) is missing. We will see the effects |
| of these different modifiers later on.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="4"></i><b>4</b></td> |
| <td>Class Todo has a data field without type annotation but with an <strong>initializer</strong>. The N4JS |
| type checker can infer the type of the initializer, in this case a boolean literal, |
| and implicitly sets the type of the field to boolean.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>In all classes we have defined above, we are using the ECMAScript 2015 export |
| keyword so that Appointment and Task can be imported and reused in other modules. |
| As the project grows, the benefits of having individual, reusable <strong>modules</strong> become |
| more and more useful in that they can be imported into other modules or even other projects.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_add_an_enumeration"><a class="link" href="#_add_an_enumeration">Add an Enumeration</a></h3> |
| <div class="paragraph"> |
| <p>We also want to add a priority field to the <code>Todo</code> class. We will modify the |
| <code>Todo</code> class and add a new type <code>Priority</code> as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">model.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export class Todo extends Task { |
| public dueDate: Date?; |
| public priority = Priority.NORMAL; |
| public done = false; |
| } |
| |
| @StringBased <i class="conum" data-value="1"></i><b>(1)</b> |
| export enum Priority { |
| LOW, NORMAL, HIGH |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Use string-based <code>enum</code> to simplify (de-)serialization</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>Enumerations allow us to represent a fixed set of constants: <code>LOW</code>, <code>NORMAL</code> and <code>HIGH</code>. |
| The reason we use an enumeration here is because we know all possible values for Priority |
| at compile-time so we may limit it to these constants. N4JS provides two kinds of |
| enumerations: "ordinary" and "string-based". The former |
| will be translated to objects, enabling extended reflection (for example to get the type of |
| the enumeration or get all literals). The latter will be translated to strings. Literals of |
| string-based enumerations are, in fact, represented as plain strings in the JavaScript |
| output code. As a result, they offer less reflection capabilities.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_the_storage_layer"><a class="link" href="#_the_storage_layer">The Storage Layer</a></h3> |
| <div class="paragraph"> |
| <p>Let’s first have a look at the UML diagram describing out storage tier:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/storage.svg" alt="storage"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The storage tier is responsible for persisting our entities. We will create two |
| different kinds of "persistence". We will start with a simple in-memory peristence, |
| which can be used for testing. Later on, we will add a proper persistence layer using MongoDB.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_defining_an_interface"><a class="link" href="#_defining_an_interface">Defining an Interface</a></h4> |
| <div class="paragraph"> |
| <p>We can create the storage module with the New Class wizard. |
| We call it "Storage.n4js", following Java’s convention of naming the module similar |
| to the contained class or interface. We will manually edit the file as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">Storage.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Task } from "model" |
| |
| export public interface Storage { |
| |
| size(): int |
| clear() |
| |
| getTasks(): Array<Task> |
| storeTask(task: Task): string |
| |
| isEmpty(): boolean { |
| return (this.size()) === 0; |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The very first line of code displays ECMAScript 2015’s import statement. |
| It is a so-called "named import": We import the element "Task", in |
| our case a class, from the module with the specifier "model".</p> |
| </div> |
| <div class="paragraph"> |
| <p>This time, we do not define a class but an interface "Storage". N4JS |
| supports <strong>interfaces</strong> which operate similar to those in Java 8. Interfaces |
| are similar to classes, but they cannot be instantiated. In N4JS it is |
| however possible to use the "instanceof" operator with interfaces. Usually |
| interfaces contain abstract methods, but they can contain data fields, |
| getters and setters as well. Similar to Java 8, interface methods can |
| provide a default implementation. Here, we provide a default implementation for the method isEmpty. |
| Classes implementing the interface can either rely on the default |
| implementation or provide a more efficient one. As in Java, a class |
| can implement multiple interfaces, and also interfaces can extend multiple interfaces.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_implement_the_interface"><a class="link" href="#_implement_the_interface">Implement the Interface</a></h3> |
| <div class="paragraph"> |
| <p>Since we cannot instantiate an interface, we need a class implementing the |
| interface. We will create a new module for a class called "StorageInMemory.n4js". |
| This module will simply keep all entities in memory. If you copy-paste the |
| following code snippet in your IDE, you will see a few errors. Do not fret, |
| it is expected and we will deal with them shortly.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">StorageInMemory.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Storage } from "Storage" |
| import { Task } from "model" |
| |
| export class StorageInMemory implements Storage { <i class="conum" data-value="2"></i><b>(2)</b> |
| |
| private lowestUnusedId = 1; |
| @Final |
| private tasks = new Map<string,Task>(); <i class="conum" data-value="1"></i><b>(1)</b> |
| |
| @Override |
| public size(): int { |
| return this.tasks.size; |
| } |
| |
| @Override |
| public storeTask(task: Task): string { |
| let id = 'id' + this.lowestUnusedId++; |
| this.tasks.set(id, task); |
| task.id = id; |
| return id; |
| } |
| |
| @Override |
| public clear() { |
| this.lowestUnusedId = 1; |
| this.tasks.clear(); |
| } |
| |
| @Override |
| public getTasks(): Array<Task> { |
| return Array.from(this.tasks.values()); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>The IDE will show an error here!</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>We use the keyword implements (known from Java) to define that this class implements |
| the interface. We have to provide specific implementation of the methods of the Storage |
| interface by using the <code>@Override</code> annotation to define <code>size</code>, <code>clear</code>, <code>getTasks</code> |
| and <code>storeTasks</code> (not all methods are shown here). This annotation is similar to |
| the annotation used in Java. It ensures that whenever a method in the interface is |
| changed, the type checker can issue a warning. This can be a lifesaver when larger |
| projects are to be maintained over time or across several development teams.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>The above code will raise a compile error because type <code>Map</code> is not available |
| in ECMAScript Version 5. We’ll have to tell N4JS that our example is intended |
| to run as ECMAScript 2015. Before doing this in the following section, let’s |
| first look at the other parts of the above class declaration in more detail.</p> |
| </div> |
| <div class="paragraph"> |
| <p>We use a data field <code>tasks</code> to store all the tasks in a map. The type Map stems from |
| ECMAScript 2015. It is a generic type similar to Array, which the observant reader may |
| have already seen in the Storage interface. N4JS provides support for generic types and methods |
| is similar to Java 8.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_edit_the_manifest"><a class="link" href="#_edit_the_manifest">Edit the Manifest</a></h3> |
| <div class="paragraph"> |
| <p>By default, N4JS provides all the types known by ECMAScript 5. In order to use elements |
| (types, functions or variables) defined by a newer JavaScript version, we have to add |
| a corresponding runtime library as project dependency to the manifest. This has no direct |
| effect on the compiled code, it simply tells the type checker to assume that certain |
| types of a newer JavaScript version will be available at runtime (provided by the JavaScript |
| engine the code is intended for).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Such meta information about an N4JS project is kept in a so-called <strong>manifest file</strong>. |
| We need to open the <code>manifest.n4mf</code> file and edit a dependency. The default manifest |
| files created by the New Project wizard look like the following:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">manifest.n4mf</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4mf" data-lang="n4mf">ProjectId: n4js.example.tasks |
| ProjectType: library |
| ProjectVersion: 0.0.1 |
| VendorId: eu.mycompany |
| VendorName: "MyCompany AG" |
| Output: "src-gen" |
| Sources { |
| source { |
| "src" |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>We need to add the following section at the end. Note that the manifest editor supports content |
| assist similar to the N4JS editor.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4mf" data-lang="n4mf">RequiredRuntimeLibraries { |
| n4js-runtime-es2015 |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This will add all additionally defined types of ECMAScript 2015. It will also add new methods |
| to types already defined in ECMAScript 5.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_running_a_module"><a class="link" href="#_running_a_module">Running a Module</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Having created the first version of our domain model and storage tier, we are ready to try it out. |
| For that, we create a module "Runner.n4js" with the following code:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { StorageInMemory } from "StorageInMemory" |
| import { Todo } from "model" |
| |
| let sim = new StorageInMemory(); |
| let todo = new Todo(); |
| todo.done = false; |
| todo.dueDate = new Date(); |
| todo.label = "Test TODO"; |
| sim.storeTask(todo); |
| |
| console.log(sim.getTasks());</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>We then launch this module with Node.js. The easiest way to do that is with the context menu |
| (accessed by right-clicking in the editor) and selecting "Launch in Node.js". as shown in the |
| following screenshot:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/firstlaunch.png" alt="firstlaunch"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This will run the module currently opened in the editor. The output will be printed to the console |
| view, for example</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/firstlaunchconsole.png" alt="firstlaunchconsole"> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1 language-n4js"> |
| <h2 id="_extend_entities_with_spec_constructor"><a class="link" href="#_extend_entities_with_spec_constructor">Extend Entities with Spec-Constructor</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>When we look at the runner code, creating a new task is quite annoying: It has to be created with |
| a new expression, and then every data field has to be set separately. To simplify this, we add |
| a constructor to our base entity class Task as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">model.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export abstract class Task { |
| // ... |
| |
| constructor(@Spec spec: ~i~this=undefined) { |
| // code for initialization will be generated due to @Spec annotation |
| } |
| } |
| ...</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The concept of constructors is taken from ECMAScript 2015. However, the parameter is very special |
| to N4JS. We briefly describe the type expression <code>~i~this=undefined</code> used here. The part <code>=undefined</code> declares |
| the default initializer of the parameter <code>spec</code> (c.f. ECMAScript 2015 cite:[ECMA11a]). Parameters which have default |
| initializers are optional, hence N4JS allows for omitting them in function calls (or in case of |
| constructors, in the <code>NewExpression</code>). |
| <code>this</code> is a known keyword in ECMAScript, it usually refers to the receiver of a property or, in case of classes, |
| method call. But here we use it as a type expression, referring to the type of the <code>this</code> |
| keyword. This is usually the class in which the method or constructor is defined. That is, |
| in case of Task it will be <code>Task</code>. However, we have two subclasses of <code>Task</code>. We do not |
| define a new constructor in these classes, instead we let these classes inherit <code>this</code> |
| constructor. In case of <code>Todo</code>, the <code>this</code> type will become <code>Todo</code> and in case of <code>Appointment</code>, |
| <code>Appointment</code>. Simply referring to the <code>this</code> type wouldn’t make any sense in the constructor, |
| since we would need a first instance in order to create another one - but how could we |
| create the first one? The solution comes with the <code>~i~</code> prefix.</p> |
| </div> |
| <div class="paragraph"> |
| <p>As discussed in the feature sheet, N4JS supports nominal and structural typing. Structural typing |
| is activated in N4JS with the tilde <code>~</code>. Two structural types are compatible, if they provide |
| the same properties, or in case of classes, public members. In the constructor, we only need to |
| set the fields. In N4JS, we can use <code>~~</code> to refer to the so-called <strong>field structural type</strong>. Two |
| field structural types are compatible, if they provide the same fields - methods are |
| ignored in these cases. Actually, optional fields are also ignored. This explains why we marked |
| some of the fields with the optional modifier. Note that fields with an initializer are also |
| treated as optional (since the initializer provides a default value). Actually, N4JS can do even |
| more. There are several modifiers to further filter the properties or members to be considered: |
| <code>~r~</code> only considers getters or data fields, <code>~w~</code> only setters and data fields. <code>~i~</code> is used |
| for initializer parameters: For every setter or (non-optional) data field in the type, the |
| <code>~i~</code>-type needs to provide at least a getter (or a readable data field). Optional fields |
| are also treated as optional in the field structural types.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For the concrete class <code>Todo</code>, the <code>~i~</code>-type is not required to contain any property since all |
| its fields are either optional or have an initializer. It contains the optional fields <code>id</code>, |
| <code>label</code>, <code>dueDate</code>, <code>priority</code> and <code>done</code>. <code>~i~Appointment</code> contains the required properties <code>time</code> and |
| <code>place</code>, and the optional fields <code>id</code> and <code>label</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In most cases, we need this information in the constructor to set the fields accordingly. |
| For Task we would write:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">constructor(spec: ~i~this=undefined) { |
| this.id = spec.id; |
| this.label = spec.label; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In order to simplify the code, the annotation <code>@Spec</code> tells the transpiler to add exactly this |
| code automatically. Even better: Since <code>Appointment</code> and <code>Todo</code> inherit the constructor, the |
| transpiler will add constructor code in these classes to set the additional fields also. That |
| is, with this single constructor, the <code>@Spec</code> annotation and the <code>~i~this</code> type expression, |
| we have solved the problem of initialization for all our entity classes with a single stroke!</p> |
| </div> |
| <div class="paragraph"> |
| <p>Using this <code>@Spec</code> constructor would then look similar to this:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">let todo = new Todo({dueDate: new Date(), label: "Test TODO"}); |
| sim.storeTask(todo);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Short summary</strong></p> |
| </div> |
| <div class="paragraph"> |
| <p>The main concepts demonstrated so far by our example are:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>Modules</strong> with import and export</p> |
| </li> |
| <li> |
| <p><strong>Classes</strong> with inheritance and constructors</p> |
| </li> |
| <li> |
| <p><strong>Interfaces</strong> with default methods</p> |
| </li> |
| <li> |
| <p><strong>Enumeration</strong></p> |
| </li> |
| <li> |
| <p>Special strategies for structural types</p> |
| </li> |
| <li> |
| <p><strong>Manifest.n4mf</strong> file and runtime library dependencies</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>We can now proceed to implement a Task Manager.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_creating_a_task_manager"><a class="link" href="#_creating_a_task_manager">Creating a Task Manager</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>We will now create the controller tier. This tier uses the entity and storage classes to provide |
| functionality that is actually useful for the user of the application.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Since we eventually want to implement a REST API (and use a real database), we need to introduce |
| asynchronous functions. So before we actually implement any controller class, we have to adjust our storage |
| tier to support asynchronous functions.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_make_the_storage_asynchronous"><a class="link" href="#_make_the_storage_asynchronous">Make the Storage Asynchronous</a></h3> |
| <div class="paragraph"> |
| <p>If we would like to use a real database, all calls to the database will be asynchronous. Asynchronous |
| programming is a typical task in ECMAScript and there are several solutions to do this.</p> |
| </div> |
| <div class="paragraph"> |
| <p>ECMAScript 2015 introduced a new class Promise which is supposed to be used with in these cases. Its methods |
| accept callback functions which are called once the asynchronous event has been triggered. Since these |
| callback functions tend to call other asynchronous functions, ECMAScript programmers easily end up in the so |
| called 'callback hell'. There is a proposal for upcoming ECMAScript versions to use special constructs in |
| the language to get rid of this callback hell. The idea is to mark asynchronous functions as "async" and, |
| when these functions are called, the program can "await" the result. This async/await feature is already |
| supported by several JavaScript frameworks and it is also built-in to N4JS including validation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>First we have to change the Storage interface and mark all methods which are supposed to be asynchronous as |
| <code>async</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">Storage.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Task } from "model" |
| |
| export public interface Storage { |
| |
| async size(): int <i class="conum" data-value="1"></i><b>(1)</b> |
| async clear() |
| |
| async getTasks(): Array<Task> |
| async storeTask(task: Task): string |
| |
| async isEmpty(): boolean { |
| return (await this.size()) === 0; |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Adding "async" to the size method and without adding the "await" keyword, you will get a |
| warning in method <code>isEmpty</code> similar to the following:</td> |
| </tr> |
| </table> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/awaitwarning.png" alt="awaitwarning"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You will also get a lot of other errors in other files:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/asyncerrors.png" alt="asyncerrors"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Without an async/await and type aware IDE you probably would have missed one or the other of these errors. |
| We can easily fix that by simply adding <code>async</code> to all the indicated methods.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If you still have the runner module, you probably will get a warning there as well. If you ignore that |
| warning and run it again, you will get the following</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">Promise { <pending> }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>instead of the expected output. We are not going to fix this problem now as we will introduce a better way |
| of testing the code after the next step.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Create TaskManager</strong></p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">TaskManager.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Todo } from "model" |
| import { Task } from "model" |
| import { Storage } from "Storage" |
| import { StorageInMemory } from "StorageInMemory" |
| |
| export public class TaskManager { |
| |
| private storage: Storage = new StorageInMemory(); |
| |
| public async getTasks(): Array<Task> { |
| return await this.storage.getTasks(); |
| } |
| |
| public async createTodo(label: string): string { |
| let newTodo = new Todo({label: label}); |
| let newId = await this.storage.storeTask(newTodo); |
| return newId; |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This class does not reveal any new concepts, but how do we test it? For that, we are going to use the N4JS |
| test framework.</p> |
| </div> |
| <div class="paragraph"> |
| <p>By utilizing the built-in test suite, classes and modules will not become polluted with superfluous test- |
| code. In addition, it is possible to overcome some access modifiers restrictions so there’s no need to |
| restructure or rewrite your code specifically to run tests.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Since we use a tier architecture, it is quite easy to add a test: We simply replace one tier with |
| appropriate tests:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/controllertest.svg" alt="controllertest"> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_testing"><a class="link" href="#_testing">Testing</a></h3> |
| <div class="paragraph"> |
| <p>Since we do not want to mix up the application with the tests, we create a new project. We use the new |
| project wizard</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/createtestproject.png" alt="createtestproject"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>We adjust the <code>manifest.n4mf</code> accordingly:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Define which project we test in the <strong>TestedProjects</strong> section.</p> |
| </li> |
| <li> |
| <p>Change the <strong>source</strong> folder to <strong>test</strong> folder. This way the IDE knows where to look for tests later on.</p> |
| </li> |
| <li> |
| <p>Add project dependencies to the built-in test framework "Mangelhaft", which also provides a comprehensive |
| collection of assert methods.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>After adding these changes, the manifest of the test project will look as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">manifest.n4mf (in project n4js.example.tasks.tests)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4mf" data-lang="n4mf">… |
| TestedProjects { |
| n4js.example.tasks |
| } |
| Output: "src-gen" |
| Sources { |
| test { |
| "src" |
| } |
| } |
| ProjectDependencies { |
| org.eclipse.n4js.mangelhaft, |
| org.eclipse.n4js.mangelhaft.assert |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>We can now write our first test. Again, we use the class wizard to create a module "TaskManagerTest" |
| containing a class with the same name. The first test should look like that:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">TaskManagerTest.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { TaskManager } from "TaskManager" |
| import { Assert } from "n4/mangel/assert/Assert" |
| |
| export public class TaskManagerTest { |
| |
| mgr: TaskManager = new TaskManager(); |
| |
| @Test |
| async testCreateTodo() { |
| await this.mgr.createTodo("test todo"); |
| Assert.equal("test todo", (await this.mgr.getTasks())[0].label); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Mangelhaft is an xUnit-like test framework. For the sake of simplicity, N4JS uses the same annotations as |
| the popular Java test framework JUnit. In our case, we have a single test method which needs to be annotated |
| with <code>@Test</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Since we are testing asynchronous code, the test method needs to be asynchronous as well and we need to |
| "await" the results of the methods we call. Mangelhaft supports asynchronous code so we do not have to |
| bother about that any further. This is the nice thing about using <code>async</code>/<code>await</code> and N4JS: asynchronous |
| programming becomes as simple as synchronous programming!</p> |
| </div> |
| <div class="paragraph"> |
| <p>We can run the test via the IDE. This works similar to launching the code with Node.js by simply using the |
| context menu. The IDE will detect a test and it will automatically add the correct menu entry to the context |
| menu:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/testinnodejs.png" alt="testinnodejs"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This will run the test and the test view will show the result of the first test:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/firsttestresults.png" alt="firsttestresults"> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_storage_using_mongodb"><a class="link" href="#_storage_using_mongodb">Storage using MongoDB</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Instead of "storing" the entities in memory, we want to use a real database. In this example, we are going |
| to use <a href="https://www.mongodb.com/">MongoDB</a>. To follow along this section on your own computer, |
| you must have MongoDB installed and start a data base server instance via the command line as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-bash" data-lang="bash">mongod --dbpath /db</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In order to use MongoDB from N4JS, we need the appropriate npm package which allows MongoDB access from |
| ECMAScript. Adding this npm and making it available in N4JS is as simple as adding any project dependency. |
| We have to open the manifest editor (of the tasks project) and add the following project dependency:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">ProjectDependencies { |
| mongodb |
| }</code></pre> |
| </div> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/quickfixnpminstall.png" alt="quickfixnpminstall"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The quick-fix will automatically download all required npm packages, that is mongodb and all its |
| dependencies. We can now use mongodb from our N4JS code.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To let N4JS know about the types a particular npm package provides, an N4JS definition file with extension <code>. |
| n4jsd</code> is required (the same applies if you use a plain JavaScript file from N4JS). For some npm packages, |
| definition files are provided at <a href="https://github.com/NumberFour/n4jsd">github.com/NumberFour/n4jsd</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Let’s assume for the moment there are no <code>.n4jsd</code> file available for MongoDB; we import MongoDB using |
| a <strong>dynamic import</strong> as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import * as mongodb+ from "mongodb" |
| |
| mongodb.MongoClient.connect('mongodb://localhost:27017/tasks', function (err: any+, db: any+) { |
| if (!err) { |
| // ... use data base ... |
| db.close(); |
| } |
| });</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>However, since we do have an <code>.n4jsd</code> file available, we can import types such as <code>MongoDB</code>, <code>Collection</code>, |
| or <code>ObjectID</code> provided by MongoDB using an ordinary ECMAScript2015 named import, just as if we were |
| importing from an N4JS module:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">StorageMongoDB.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Storage } from "Storage"; |
| import { Task, Appointment, Todo } from "model"; |
| import { Collection, Db, MongoClient, ObjectID } from "mongodb"; |
| |
| /** |
| * Persistence for task lists using a mongodb instance. |
| */ |
| export class StorageMongoDB implements Storage { |
| cachedDb: Db = null; |
| |
| private async getTasksCollection(): Collection { |
| if (!this.cachedDb) { |
| this.cachedDb = await MongoClient.connect('mongodb://localhost:27017/tasks'); |
| } |
| return this.cachedDb.collection('tasks'); |
| } |
| |
| public async shutdown() { |
| this.cachedDb.close(true); |
| this.cachedDb = null; |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In the above code section, we are implementing StorageMongoDB from the Storage interface and then calling |
| some of the standard MongoDB collection methods.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The next step is to retrieve the information about our Tasks and to store them in our MongoDB database. In |
| the storeTask method, we are then retrieving the inserted item id’s from MongoDB and returning them as a |
| <code>task.id</code>.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">StorageMongoDB.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export class StorageMongoDB implements Storage { |
| |
| // ... |
| |
| @Override |
| public async size(): int { |
| let coll = await this.getTasksCollection(); |
| return await coll.count({}); |
| } |
| |
| @Override |
| public async clear() { |
| let coll = await this.getTasksCollection(); |
| await coll.deleteMany({}); |
| } |
| |
| @Override |
| public async getTasks(): Array<Task> { |
| let coll = await this.getTasksCollection(); |
| let resultRaw = await coll.find({}).toArray(); |
| let result = resultRaw.map((data): Task => fromData(data)); <i class="conum" data-value="1"></i><b>(1)</b> |
| return result; |
| } |
| |
| @Override |
| public async storeTask(task: Task): string { |
| let coll = await this.getTasksCollection(); |
| let result = await coll.insertOne(toData(task)); |
| if (result.insertedCount === 1) { |
| task.id = result.insertedId.toHexString(); |
| return task.id; |
| } |
| throw new Error("insert document failed"); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>The use of the <code>=></code> arrow function, derived from ES6. Arrow functions have implicit lexical |
| binding and are less verbose than traditional function expressions.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>The above code uses two helper functions, <code>toData()</code> and <code>fromData()</code>. Those illustrate two techniques available |
| in N4JS: reflection and so-called <code>@Spec</code> constructors, respectively. Reflection is known from many |
| languages and allows for retrieving information of a type and its members at runtime. It is used in |
| <code>fromData()</code> as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">StorageMongoDB.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">function toData(task: Task): ~~Task { |
| let metaClass = N4Type.of(task), |
| data: any+ = {}; |
| // note: would have to set data._id, here, if we |
| // wanted support for updating existing tasks |
| data._type = metaClass.name; |
| let taskAsObject: Object = task; // up-cast to object to allow index access |
| for (let field of metaClass.dataFields(true,true)) { |
| data[field.name] = taskAsObject[field.name]; |
| } |
| return data; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Conversely, <code>@Spec</code> constructors are special constructors that allow us to create a new instance of a class and |
| initialize it with values provided by a plain data object in properties that correspond to the type’s fields.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">StorageMongoDB.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">function fromData(data: any+): Task { |
| let ctor = typeToCtor.get(data._type as string); |
| if (!ctor) { |
| throw new Error('Unsupported type of data model entity: ' + data._type); |
| } |
| let task = new ctor(data); |
| task.id = (data._id as ObjectID).toHexString(); |
| return task; |
| } |
| |
| const typeToCtor = new Map<string,constructor{Task}>([ |
| ['Todo', Todo] as Iterable2<string, constructor{Task}>, |
| ['Appointment', Appointment] as Iterable2<string, constructor{Task}> |
| ]);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that both functions <code>toData</code> and <code>fromData</code> should be declared outside of the <code>StorageMongoDB</code> class but in the same file <code>StorageMongoDB.n4js</code>. |
| By using the above two helper functions, we avoid sending our data model instances directly to the MongoDB |
| driver. Note that the entire implementation is intended for illustration purposes and in a real-world |
| systems many details would be handled differently, depending on the actual requirements.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1 language-n4js"> |
| <h2 id="_dependency_injection"><a class="link" href="#_dependency_injection">Dependency Injection</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>We now have two implementations of the interface Storage. For testing, the in-memory solution is adequate, |
| but for the application we want to use the MongoDB solution of course. Since we are using the Storage in our |
| TaskManager class, we would need to change the TaskManager depending on the storage solution. This is |
| inconvenient and error prone. It would be much better if we could configure which storage class to use from |
| outside the TaskManager at some central location. This is possible with dependency injection.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To learn more about how dependency injection works, we have written an |
| <a href="../features/dependency-injection.html#dependency-injection">extended feature description</a> that describes the benefits of this technique. |
| In short, N4JS provides built-in support for dependency injection using the same annotations as known from JSR-330/ |
| Google Guice. Instead of using initializers calling the constructor for certain fields, we just mark them |
| with <code>@Inject</code>. We will do that with the storage field in the TaskManager class:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">TaskManger.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export public class TaskManager { |
| |
| @Inject |
| private storage: Storage; |
| |
| // ... |
| }</code></pre> |
| </div> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| After removing the constructor, the IDE will create a warning that one of the imports is unused. You |
| can easily fix that by using the "Organize Import" feature, either from the context menu (or via |
| <span class="keyseq"><kbd>⌘</kbd>+<kbd>Shift</kbd>+<kbd>O</kbd></span> on Mac OS, <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>O</kbd></span> on Windows). |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>How does N4JS now create the instance of storage? For that, we need an injector. An injector is responsible |
| for creating all variables annotated with <code>@Inject</code>. The injector is configured with a so-called "binder". |
| The binder is more or less a translation table telling the injector which type it should use to create a |
| concrete instance when a certain type is given. In our case, we need to tell the injector whether we want an |
| instance of StorageInMemory or StorageMongoDB. We are going to adjust the test accordingly.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For that, we first add a binder to the test module "TaskManagerTest.n4js":</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">TaskMangerTest.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">@Binder |
| @Bind(Storage,StorageInMemory) |
| class InMemoryBinder {}</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The annotation <code>@Binder</code> marks the class InMemoryBinder to become a binder. For each mapping we need to add |
| an annotation <code>@Bind</code>, which takes the requested type as the first argument and the actual type as the |
| second one. We only actually need to define bindings for interfaces. If the requested type is a class and if |
| no binding is defined for it, the injector will simply create an instance of that very type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The next step is to create an injector. Fortunately, we do not have to do that manually. The dependency |
| injection framework of N4JS introduces the notion of dependency injection components (DIC). A DIC is |
| associated with an injector; this is done by using the annotation <code>@GenerateInjector</code>. Additionally we need |
| to tell the framework which configuration it should use for the injector, this is done via the annotation |
| <code>@UseBinder</code>, which expects the type name of a binder class.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">TaskMangerTest.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">@GenerateInjector @UseBinder(InMemoryBinder) |
| export public class TaskManagerTest { |
| … |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The IDE helps us in finding problems: since the TaskManager class uses injection to get the storage field, |
| it needs to be injected itself. The IDE warns us in the TaskManagerTest class:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/injectionwarning.png" alt="injectionwarning"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This is hard to find but easy to fix: We just have to replace the initalizer with an <code>@Inject</code> annotation.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">TaskMangerTest.n4js (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">… |
| export public class TaskManagerTest { |
| @Inject |
| mgr: TaskManager; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>With these little changes, we can now configure the storage solution from outside the TaskManager class. |
| Running this test will behave as before but we have removed the hard-coded dependency from TaskManager to |
| StorageInMemory.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_web_ui_module"><a class="link" href="#_web_ui_module">Web UI module</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The final step in building functionality into our model is to create a simple web user interface using |
| <a href="http://expressjs.com/">Express</a> as a dependency to create a web server. We will then pass our tasks from MongoDB into a small |
| HTML page to display the results. We will create the web server using <a href="http://expressjs.com/">Express</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In order to use Express, we need the appropriate npm module. Adding this npm and making it available in |
| N4JS is as simple as adding any project dependency, as already shown for MongoDB, above. We have to open the |
| manifest editor (of the tasks project) and add the following project dependency (along with the existing |
| dependencies):</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">manifest.n4mf (cntd.)</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4mf" data-lang="n4mf">ProjectDependencies { |
| mongodb, |
| express, |
| n4js.lang |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The dependency <code>n4js.lang</code> contains <code>N4Injector</code> which is needed later, so make sure it is declared as a dependency.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The quickfix will automatically download all required npm packages, that is, Express and all its |
| dependencies. We can now use Express in our N4JS code (for more details, esp. N4JS definition files, see |
| above description on MongoDB).</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">WebUI.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">//Creating a simple Web User Interface in HTML |
| |
| import { TaskManager } from "TaskManager" |
| import {Application, Response } from "express"; |
| import express from "express"; |
| import { Todo } from "model" |
| |
| export class WebUI { |
| |
| private app: Application; |
| |
| @Inject |
| private manager: TaskManager; |
| |
| public start() { |
| |
| this.app = express(); |
| |
| this.app.get('/', async (req, res) => { |
| let page = await this.renderHomePage(); |
| res.send(page); |
| }); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Express is a web framework that provides (among other things) HTTP helpers for web routing. In the above |
| example, we are importing the classes <code>Application</code> and <code>Response</code> from Express and creating a home page |
| that we can render some HTML to. Next we will add a method for creating new tasks:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">WebUI.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">public start() { |
| |
| // ... code shown above ... |
| |
| this.app.get("/create", async (req, res) => { |
| let values = req.query as ~Object with {type: string, label: string}; |
| if (values && values.type === 'Todo' && values.label && values.label.length > 0) { |
| await this.manager.createTodo(values.label); |
| } |
| redirect(res, '/'); |
| }); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Have Express listen on port 4000 at localhost:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">WebUI.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">public start() { |
| |
| // ... code shown above ... |
| |
| this.app.listen(4000, '0.0.0.0', 511, function() { |
| console.log("HTTP server listening on http://localhost:4000/"); |
| }); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Finally, we add a helper method for rendering a simple HTML page so we can view our Todos and edit them:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">WebUI.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">export class WebUI { |
| |
| // ... methods shown above ... |
| |
| protected async renderHomePage(): string { |
| let tasks = await this.manager.getTasks(); |
| let todos = tasks.filter((task) => task instanceof Todo); |
| return ` |
| <html> |
| <body> |
| Your to-do's: |
| <ul> |
| ${ |
| todos.length === 0 ? '<li><em>none</em></li>\n' |
| : todos.map((todo) => |
| '<li>'+todo.label+' <small>(id: '+ todo.id +')</small></li>' |
| ).join('\n') |
| } |
| </ul> |
| <hr/> |
| <form action="/create" method="get"> |
| <input type="hidden" name="type" value="Todo"> |
| Label: <input type="text" name="label"><br> |
| <input type="submit" value="Create Todo"> |
| </form> |
| <hr/> |
| <a href="/clear">[Clear All]</a> |
| </body> |
| </html> |
| `; |
| } |
| } |
| |
| function redirect(res: Response, url: string) { |
| res.header('Cache-Control', 'no-cache'); |
| res.redirect(301, url); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>At this point, we have to launch our web server. For this purpose, we create a small launch script that |
| configures the dependency injection (as shown in the section on dependency injection, above), creates an |
| instance of class <code>WebUI</code>, and invokes method <code>start()</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">launch.n4js</div> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Storage } from "Storage"; |
| import { StorageMongoDB } from "StorageMongoDB"; |
| import { WebUI } from "WebUI"; |
| import { N4Injector } from "n4js/lang/N4Injector"; |
| |
| @Binder |
| @Bind(Storage, StorageMongoDB) |
| class Binding { } |
| |
| @GenerateInjector |
| @UseBinder(Binding) |
| class Root { } |
| |
| N4Injector.of(Root).create(WebUI).start();</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You can now use the HTML page by going to <a href="http://localhost:4000/">http://localhost:4000/</a>, |
| allowing you to interact with all of the logic we have built so far in order to read Todos, create new Todos |
| and clear the storage.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All of the fundamental elements of our model are completed and we have a functioning Task Manager with a |
| simple Web UI.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1 language-n4js"> |
| <h2 id="_export_as_npm"><a class="link" href="#_export_as_npm">Export as npm</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Finally, we can export our project as an npm package to integrate it into other Node.js projects or to |
| launch from command line.</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>You can export one or multiple projects by selecting them in the Project Explorer and opening the |
| "Export …​" wizard by right-clicking on them. On the first page select "N4JS Exports / N4JS npm Export". For |
| the purpose of this example, only export project <code>n4js.example.tasks</code>.</p> |
| </li> |
| <li> |
| <p>On the second page you have to choose a target folder to export to.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="admonitionblock important"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-important" title="Important"></i> |
| </td> |
| <td class="content"> |
| Export to a folder outside your Eclipse workspace! |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>By default, the exporter exports as a directory. Optionally, you can export as a versioned tarball by |
| checking the option "Compress the contents of the file".</p> |
| </li> |
| <li> |
| <p>The last page of the wizard shows a preview of the package.json file that will be created in the |
| exported npm package, together with a comparison to an existing package.json file in your N4JS project, if |
| present. You can place such a package.json file next to your <code>manifest.n4mf</code> file (optional), in case you |
| need |
| to define more <a href="https://docs.npmjs.com/files/package.json">specifics in the package.json</a>, that |
| are not covered by the N4JS export wizard.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="images/npmexport.png" alt="npmexport"> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_run_from_command_line_with_node_js"><a class="link" href="#_run_from_command_line_with_node_js">Run from command line with Node.js</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Once you’ve exported your project, you can either publish it to |
| <a href="https://www.npmjs.com/">npmjs.com</a> or install directly from your hard disk and call the launch |
| module, for example</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-bash" data-lang="bash">$ npm install -g n4js.example.tasks |
| $ node -r n4js.example.tasks/launch |
| HTTP server listening on http://localhost:4000/</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In case you want to install dependencies and run it right away in the exported npm folder, you have to |
| manually set up the <code>NODE_PATH</code> to the folder hosting the exported npms, otherwise node cannot resolve the |
| project/npm IDs.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-bash" data-lang="bash">$ export NODE_PATH=`pwd` |
| $ pushd n4js.example.tasks; npm install; popd |
| n4js.example.tasks@0.0.1 /Users/me/prj/n4js.example.tasks |
| ├─┬ express@4.13.4 |
| ... |
| $ node n4js.example.tasks/launch.js |
| HTML server listening on http://localhost:4000/</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>So far we’ve been loading all code via node’s <code>require()</code> function. |
| In case you want to load your modules via <a href="https://github.com/systemjs/systemjs">SystemJS</a>, |
| which has more support to resolve cyclic dependencies across modules, you could use a handy starter |
| executable called <code>n4js</code>. The <code>n4js</code> starter is part of the <code>n4js-node</code> runtime environment npm (a default |
| dependency of any exported npm) and is therefore already installed:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-bash" data-lang="bash">$ export NODE_PATH=`pwd` |
| $ cd n4js.example.tasks; npm install |
| n4js.example.tasks@0.0.1 /Users/me/prj/n4js.example.tasks |
| ├─┬ express@4.13.4 |
| ... |
| $ ./node_modules/.bin/n4js n4js.example.tasks/launch |
| HTTP server listening on http://localhost:4000/</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_bibliography"><a class="link" href="#_bibliography">Bibliography</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>bibliography::[]</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div id="footer"> |
| <div id="footer-text"> |
| </div> |
| </div> |
| <div class="Grid social" style="color:#d5dfea"> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <h2>Quick Links</h2> |
| <ul> |
| <li><a href="../downloads.html">Download</a></li> |
| <li><a href="index.html">Documentation</a></li> |
| <li><a href="https://github.com/eclipse/n4js/">Source</a></li> |
| <li><a href="https://github.com/eclipse/n4js/issues">Issues</a></li> |
| </ul> |
| </div> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <br/><br/> |
| <ul> |
| <li><a href="https://www.eclipse.org/forums/index.php/f/365/">Forum</a></li> |
| <li><a href="http://n4js.blogspot.de/">Blog</a></li> |
| <li><a href="https://dev.eclipse.org/mailman/listinfo/n4js-dev">Mailing List</a></li> |
| <li><a href="https://projects.eclipse.org/projects/technology.n4js">Eclipse Project Page</a></li> |
| <li><a href="https://twitter.com/n4jsdev">Tweets by n4jsdev</a></li> |
| </ul> |
| </div> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <br/><br/> |
| <ul> |
| <li><a href="http://www.eclipse.org/">Eclipse Home</a></li> |
| <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> |
| </div> |
| <div style="clear: both; height: 0; overflow: hidden;"></div> |
| </div> |
| |
| <script> |
| // Toggle the table of contents |
| $( "button#tocbutton" ).click(function() { |
| if ($("#tocbutton").css('right') == '25px') { |
| $( "#tocbutton" ).animate({right: '215px'},"slow"); |
| $( "#toc.toc2" ).animate({right: '0'},"slow"); |
| } |
| else { |
| $( "#tocbutton" ).animate({right: '25px'},"slow"); |
| $( "#toc.toc2" ).animate({right: '-13rem'},"slow"); |
| } |
| }); |
| </script> |
| <script type="text/javascript"> |
| // Create a back to top button |
| $('body').prepend('<a href="#" class="back-to-top">Back to Top</a>'); |
| var amountScrolled = 300; |
| $(window).scroll(function() { |
| if ( $(window).scrollTop() > amountScrolled ) { |
| $('a.back-to-top').fadeIn('slow'); |
| } else { |
| $('a.back-to-top').fadeOut('slow'); |
| } |
| }); |
| $('a.back-to-top, a.simple-back-to-top').click(function() { |
| $('html, body').animate({ |
| scrollTop: 0 |
| }, 700); |
| return false; |
| }); |
| </script> |
| </body> |
| </html> |