blob: a5d5e163f2147985932687da3045c73fc98eba13 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.7.1">
<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>
</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&#8217;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>&#160;<i class="fa fa-angle-right caret"></i> <b class="submenu">New</b>&#160;<i class="fa fa-angle-right caret"></i> <b class="menuitem">N4JS Project</b></span> (Or using the
keyboard shortcuts <span class="keyseq"><kbd>&#8984;</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>&#160;<i class="fa fa-angle-right caret"></i> <b class="submenu">New</b>&#160;<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&#8217;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&#8217;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&lt;Task&gt;
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&#8217;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&lt;string,Task&gt;(); <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&lt;Task&gt; {
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&#8217;ll have to tell N4JS that our example is intended
to run as ECMAScript 2015. Before doing this in the following section, let&#8217;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&#8217;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&lt;Task&gt;
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 { &lt;pending&gt; }</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&lt;Task&gt; {
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&#8217;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&#8217;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&#8217;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&lt;Task&gt; {
let coll = await this.getTasksCollection();
let resultRaw = await coll.find({}).toArray();
let result = resultRaw.map((data): Task =&gt; 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>=&gt;</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&#8217;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&lt;string,constructor{Task}&gt;([
['Todo', Todo] as Iterable2&lt;string, constructor{Task}&gt;,
['Appointment', Appointment] as Iterable2&lt;string, constructor{Task}&gt;
]);</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>&#8984;</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) =&gt; {
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) =&gt; task instanceof Todo);
return `
&lt;html&gt;
&lt;body&gt;
Your to-do's:
&lt;ul&gt;
${
todos.length === 0 ? '&lt;li&gt;&lt;em&gt;none&lt;/em&gt;&lt;/li&gt;\n'
: todos.map((todo) =&gt;
'&lt;li&gt;'+todo.label+' &lt;small&gt;(id: '+ todo.id +')&lt;/small&gt;&lt;/li&gt;'
).join('\n')
}
&lt;/ul&gt;
&lt;hr/&gt;
&lt;form action="/create" method="get"&gt;
&lt;input type="hidden" name="type" value="Todo"&gt;
Label: &lt;input type="text" name="label"&gt;&lt;br&gt;
&lt;input type="submit" value="Create Todo"&gt;
&lt;/form&gt;
&lt;hr/&gt;
&lt;a href="/clear"&gt;[Clear All]&lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;
`;
}
}
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>
<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>