VertxUI: Java as a front-end language

© Shutterstock / Grumble

Why waste time on learning new language features and lots of frameworks, taking the risk that you’re learning tools that won’t ever be updated again? There is a language that can run anywhere too, except directly in a browser. What if Java could directly run in a browser? In this article, Niels Gorisse, a senior full-stack Java developer, presents the benefits of VertxUI.

Yesterday I had a job interview for a senior Java back-end job. They asked me whether I was a full-stack developer or not. Although my answer was a proud yes, I stated that I don’t really like JavaScript, but I can find my way through HTML/CSS and JavaScript code. Then I had to explain why I don’t like JavaScript.

I said I don’t like it because of many reasons. JavaScript doesn’t – or actually: didn’t – work the same on all browsers, there is a global scope with all variables in it, and besides that, there are thousands of libraries fixing missing language and API features. Even worse, it seems none of them can be considered to be ‘default.’ So, there is no chance of knowing whether you’ve picked the lasting libraries. I guess I did not get the job.

Just like most senior Java developers, I wrote my first JavaScript lines of code well before 2000. Of course, that is the reason for my grunge against it. But things have changed. Nowadays, after more than ten years of browser disaster, ECMAscript5 has become the standard: more than 97% of all browsers in use support it. Yes, JavaScript still has the ugly language features, but you can write a piece of JavaScript code that works anywhere. And JavaScript is becoming a decent language complete with classes, exceptions, lambda notation, worker thread, packaging, annotations, futures, library management, and much more.

But why waste time on learning new language features and lots of frameworks, taking the risk that you’re learning tools that won’t ever be updated again? There is another language that can run anywhere too, except directly in a browser. What if Java could directly run in a browser?

Mind you, many features which are fairly new to JavaScript have been added to Java many years earlier. In almost every case, this means they’ve become pretty stable and mature over the years:

VertxUI and Fluent

VertxUI is a 100% Java library which tries to answer what if we could run Java directly in the browser. And because pure HTML with CSS is enough to build web pages, VertxUI provides – besides low-level access to the browser – also a lightweight fluent API called Fluent, which simplifies building HTML and CSS with code only. Fluent works with method names corresponding to HTML tags. The first argument of these methods is always a CSS class. So VertxUI does not have any templates, just code. Consider a menu in bootstrap. Using HTML, we’d define a Bootstrap menu like so:

1
2
3
4
5
6
7
8
9
10
11
12
<ul class="nav navbar-hav">
  <li class="active"><a href="#home">Home</a>
  <li><a href="#about">About</a>
</ul>
Using Fluent, we can use to generate the same HTML code like so:
...
Fluent ul = body.ul("nav navbar-nav");
ul.li("active").a(null, "Home", "#home", controller::onMenuHome);
ul.li(null).a(null, "About", "#about", controller::onMenuAbout);

The variable body is a static import from the class Fluent. Similarly, you can also use the methods console, document, and window.

Actually, the Java source code generates code doing slightly more than the HTML snippet above. It also shows how to call Java code when clicking a menu entry. In our example, an instance of a controller (controller::someMethod) takes care of the event handling.

Although not displayed in the previous snippet, there is also a class Store, maintaining a list of class Model. This traditional MVC (model-view-controller) setup is not necessary, but it turns out to be useful when writing JUnit tests.

Of course, you can also use the lambda notation too. For example, let’s create a Bootstrap form. The methods .css() and .att() are also used to show you how they work. This is basically all you need to write HTML and CSS:

Desired HTML snippet:

1
2
3
4
<div class="form-group">
  <label style="font-size: 200%" for="n">Wat</label>
  <input class="cssClass" type="text" id="n">
</div>

Generating the some code using Fluent:

1
2
3
4
5
6
7
8
Fluent div = body.div("form-group");
div.label(null, "Wat")
   .style(Style.fontSize, "200%")
   .att(Att.for, "n");
div.input("cssClass", "text").id("n").
    keydown( (fluent, keyEvent) -> {
      console.log("You typed: " + fluent.domValue());
    });

How it’s done

Of course, the Java code isn’t run in the browser. It’s compiled to JavaScript before. At this point, people often get a wrong impression when they hear which compiler is used, so let’s mention first that VertXUI has been developed using TeaVM. However, TeaVM wasn’t without flaws. In particular, there were a couple of bugs concerning Lambdas. So now VertxUI uses the cross-compiler of GWT to do that, but without using the original GWT toolkit. Don’t confuse it with Vaadin or GWT itself. VertxUI is a completely different, unique approach.

View on … model

The real power of Fluent shows when you are about to change the DOM – because you don’t have to. Changes are updated as efficiently as possible, comparable to ReactJS (from Facebook) which makes sure that your Facebook list of friends does not get completely re-rendered when one online status changes.

You can create a ViewOn<Model> with the .add() method. This takes two arguments: an initial model (or reference to a model) and a method translating this model to a Fluent object. For example:

Result

1
2
3
4
5
6
7
8
9
<table>
  <tbody class="striped">
  (per subscribed person:)
  <tr>
    <td class="fat">*name*</td>
    <td>*quantity*</td>
  </tr>
  </tbody>
</table>

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public View {
  private ViewOn<List<Person>> table;
 
  public void start(Controller controller){
    List<Person> initialPersons = controller.getPersons();
 
    Fluent middle = body.div();
    ...
    table=middle.add(initialPersons, persons -> {
      if(persons == null || persons.isEmpty()) {
        return Span("big","No people yet");
      }
      Fluent result = Table().tbody("striped");
      for(Person person:persons) {
        if(person.isSubscribed()) {
          result.tr(
              Td("fat",person.getName()),
              Td(null,person.getQuantity()));
        }
      }
      return result;
    });
  }
 
  public void syncPersons() {
    table.sync();
  }
}

You probably noticed the syncPerson() method. This redraws all ViewOn objects having a link to the Person entity. As said previously, you do not need a controller, but here the controller calls that method after a change. Note that it is quite easy to write quite complex user interfaces (like wizards) because you’re just declaratively writing down what your UI should look like. You can even nest ViewOn objects.

All code is pure Java, so if you prefer streams, then that is no problem. The tbody – just like a lot of other containers like tags – takes a CSS class and a list or stream of Fluent objects.

1
2
3
4
5
6
7
8
9
10
table = middle.add(initialPersons, persons -> {
  if (persons == null || persons.isEmpty()) {
    return Span("big", "No people yet");
  }
  return Table().tbody("striped", persons
      .filter(person -> person.subscribed())
      .map(person -> Tr(
          Td("fat", person.getName()),
          Td(null, person.getQuantity()))));
});

View on … state

In the previous Bootstrap menu example, the CSS item which has the “active” class should switch to the selected one when you click on it. This is what we can call a ‘state.’ It is handy to recognize a state and to treat it as an entity which happens never to be saved into a database. You can also use ViewOn<> for a state:

1
2
3
4
5
6
7
String initState = "home"; // or something else which you have extracted from the URL
...
Fluent menu = body.add(initState, state -> {
  Fluent ul = Ul("nav navbar-nav");
  ul.li(state.equals("home") ? "active" : null).a(null, "Home", "#home", controller::onMenuHome);
  ul.li(state.equals("about") ? "active" : null).a(null, "About", "#about", controller::onMenuAbout);
});

JUnit – unit testing

Because Fluent has a virtual DOM internally, you can easily ‘abuse’ this for JUnit testing without firing up a browser. This is extremely fast because there is no compilation to JavaScript and there is no starting and stopping of a browser in the background.

In practice, the class Store is often mocked in JUnit tests to prevent network traffic, but in the next example we mock the Controller call directly:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Test {
 
  @Test
  public void test() {
    // Fake result after some network traffic
    List<Person> persons = new ArrayList<>();
    String name = "John " + Math.random();
    persons.add(new Person(name, 2000, true));
   
    // Startup sequence
    View view = new View();
    Controller controller = Mockito.spy(Controller.class);
    Mockito.when(controller.getPersons()).thenReturn(persons);
    view.start(controller);
   
    assertEquals("1 row",1,VirtualDomSearch.getElementsByTagName("TR", body));
    List<Fluent> tds = VirtualDomSearch.getElementsByTagName("TD", body);
    assertTrue("2 columns", 2, tds.length());
    assertTrue("name test", name, tds.get(0).txt());
  }
}

JUnit – integration tests
As your project grows and starts using external JavaScript libraries, integration tests get more and more important. In Fluent you can perform dual-language tests in a headless browser with a ‘register-and-run’ construction. You have slightly more control over your runtime environment than with Selenium because you can easily run and combine JavaScript assets and Java assets together in one test-run.

As an example, we take that dull first Bootstrap menu example, and we simulate a menu click by directly calling controller.onMenuAbout(). Let’s see whether the previous example, which changes the content of the ‘active’ class, actually works. The following code is really all you need. The Java-to-JavaScript compilation happens on the fly:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Test extends TestDOM {
 
  @Test
  @GwtIncompatible
  public void test() throws Exception {
    System.out.println("Java");
    runJS(100); // run slot '100'
  }
 
  @Override
  public Map<Integer, Runnable> registerJS() {
    Map<Integer, Runnable> result = new HashMap<>();
    result.put(100, () -> testWithDOM()); // register slot '100'
    return result;
  }
 
  public void testWithDOM() {
    console.log("JavaScript");
     
    View view = new View();
    Controller controller = new Controller(new StoreEmpty(), view);
    view.start(controller);
 
    // search the active menu item
    NodeList actives = document.getElementsByClassName("active");
    assertEquals("quantity test 1", actives.length(), 1);
    assertTrue("titletest 1",((Element) actives.item(0).getChildNodes().at(0))
      .getTextContent().equals("Home"));
     
    controller.onMenuAbout(null, null);
     
    // search again
    actives = document.getElementsByClassName("active");
    assertEquals("quantity 2", actives.length(), 1);
    assertTrue("titletest 2",((Element) actives.item(0).getChildNodes().at(0))
      .getTextContent().equals("About"));
  }
}

Notice that this example could have been put in a non-DOM test, which runs a lot faster.

VertX

You can run VertxUI in any back-end software, but together with VertX, it provides several facilities like FigWheely and POJO traffic. VertxUI with VertX is easier than easy: just start the main() and point your browser to http://localhost. You don’t have to install any IDE-plugin. Neither do you have to deal with a *.war or *.jar. Just start the main class, and you’re good to go!

VertX is completely asynchronously and works with callbacks, just like JavaScript. So, for example, it doesn’t block until TCP data has arrived, but instead it will continue to run the stack when something has arrived. The big difference is that because Java is a very structured language, you’ll never get a callback hell like in JavaScript. You will probably call another method in another class when something asynchronously has happened.

VertX – FigWheely

FigWheely is the runtime helper of VertxUI. It keeps a WebSocket open with the browser and receives notifications when files have changed on the server. If the files that have changed happen to be .java files, FigWheely will recompile your browser code and notify the browser too.

FigWheely works -just like VertxUI- without any IDE-plugin because the compilation to JavaScript happens when you start the (VertX) server and when the source code is found. During startup, a one-line index.html is also generated, but you can also turn this off to use an existing website. Or you can use HTML itself as HTML template when using jQuery Mobile.

VertX – POJO

VertxUI facilitates POJO traffic between server and browsers for ajax calls, WebSocket, sockJS, and the VertX event bus. This means strong-typed traffic, even though JSON is used underneath. Having the client and server in the same language has quite some nice advantages: when you want to add a table column, it might just be adding one line of code to the entity and one line for an extra ‘TD’ in the view.

Here is a client-side example of a chat application with a POJO receiver:

1
2
3
4
5
6
7
8
9
10
WebSocket socket = window.newWebSocket("ws://localhost/chatWebsocket");
socket.setOnmessage(event -> {
  // POJO: receive the a color and put it between a new <li>...</li>
  if (POJOfy.socketReceive(urlPOJO, event, POJOMapper,
    pojo -> messages.li("colored", "Received: " + pojo.getColor()))) {
    return;
  }
  // otherwise, receive the text and put it in a new <li>..</li>
  messages.li("flat", ((MessageEvent) event).getData().toString());
});

and here is the server side, which can also receive a POJO. It looks so simple that you might forget that this is an extremely powerful web server, more powerful than a regular locking multithreaded servlet environment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<String> ids = new ArrayList<>(); // all ids
vertx.createHttpServer().websocketHandler(socket -> { // entering
  String id = socket.textHandlerID();
  ids.add(id);
  socket.closeHandler(data -> { // leaving
    ids.remove(id);
  });
  socket.handler(buffer -> { // receiving
    if (POJOfy.socket(socket, View.urlPOJO,buffer, Dto.class,aService::handle)){
      return;
    }
    String message = buffer.toString();
    ids.forEach(id -> vertx.eventBus().send(id, message)); // broadcasting
  });
}).listen(80);

Wrapping it up

No matter what happens in the future with the client side and the JavaScript language, you can already create very well testable single page web applications in the very grown-up language Java backed by the well developed VertX server environment and backed by any well-developed CSS framework like Bootstrap. The test facilities of VertxUI alone should be interesting enough to try out VertUI for a new project. Let alone the POJO traffic, strong-typed code, a well developed IDE, and so forth, in other words: Java.

JavaScript and its libraries will grow up, but this will take years, and the chances are small that you can pick the right libraries now and prevent refactoring and learning new language features that get deprecated before you’re used to them.

If you’re familiar with React.js or Angular, you’re used to just changing the model to update the view. Actually, this seamless integration between the view and the model made React and Angular popular. It was a major improvement over the older approach modifying the DOM manually. Changing the DOM is error-prone. Using a framework for that makes you write clean code. VertxUI brings this idea to the Java world.

This article was originally published on Beyond Java. 

[“Source-jaxenter”]