Software Development

JsInterop, Web Components, Polymer: A beginner’s guide

JsInterop

Back when GWT was released, there wasn’t that much of Javascript libraries, so having a two way interoperability between Java and JS was not that attractive. GWT offered a way to write Javascript inside Java classes using JSNI. But now with the changing landscape of the Javascript ecosystem, GWT developers need something more elaborate than JSNI. From version 2.7, JsInterop was introduced in GWT as an experimental feature to replace JSNI. As its name suggests, JsInterop is a way of interoperating Java (GWT) with Javascript. it offers a better way of communication between the two using annotations instead of having to write JavaScript in your classes. JSInterop is defined by the following interfaces: @JsType, @JsProperty, @JSMethod, @JSConstructor, @JSFunction, @JsExport.

The first utility of JsInterop is to expose your java classes to a javascript script. For example:

package com.jsinterop;

@JsType
public class myClasse {

public String name;

public myClass(String name){
this.name = name;
}
public void sayHello(){
return 'Hello' + this.name;
}
}

From a browser, we can do something like:

//the package name serves as JS namespace
var aClass = new com.jsinterop.myClasse('developpez.com');

console.log(aClass.sayHello());

// result: 'Hello developpez.com'

The second utility of JsInterop is the ability to import existing Javascript libraries into GWT without having to re-write any line of code. This is where things get interesting. Imagine that you can make use of all the major frameworks that exist in javascript ecosystem (Angular, Polymer, React …) from your Java code.
For example, suppose we want to use Leaflet, which is a JS library to manipulate the maps from our GWT project. All we need to do is wrap the methods using JsInterop annotations:

@JsType(isNative=true, namespace=JsPackage.GLOBAL)
public class L {


public static native Map map(String id);

}

@JsType(isNative=true)
public class Map {


@JsMethod
public native L setView(double[] center, int zoom);

}

Please note that we used the same variable names as those in the source code of the Leaflet library. Class names, in our example L and Map, and method names are very important in JsInterop because from the moment when we specify isNative = true, GWT will automatically set the variables types as the types in the browser environment.

Now we can initialize a Leafet map in our GWT application without handling any javascript code:

public class Leafletwrapper implements EntryPoint {

double[] positions = {51.505, -0.09};

public void onModuleLoad() {

//ça marche
L.map("map").setView(positions, 13);
}
}

The full example is available at : https://github.com/zak905/jsinterop-leaflet

Currently there is no tool for automatically converting a Js library into JsInterop-like classes. While waiting for a tool to do so (something like the gwt-api-generator which is used for Polymer elements only), the developer must know how to walk through the Javascript library (methods, arguments, fields, namespaces,. ..etc) and do the mapping manually. There is no doubt that manual mapping is not error prone, but this is the only way for now. Another disadvantage of manual mapping is when a Js library gets updated. Again, the developper must incorporate the changes manually for the continuity of the interoperability.

Here is another interesting example that can help you understand JsIntrop. It implements interoperability between AngularJs and GWT: https://github.com/bitwerk/AngularGwtExample

Polymer and Web Components: the big picture

With the emergence of the new generation of web applications, web developers are now required to handle a great deal of HTML, CSS, and Javascript. Working with the three at once is not simple sometimes, so developers and the web community felt the need to have something more standard to better manage complex HTML, CSS and Js. The idea of ​​Web Components is born from this need. The purpose behind the creation of WCs is reusability. Reusability was one of the main goals of object-oriented languages ​​such as Java, but has not been really considered for the front end. There are obviously lots of patterns that repeat themselve, so the question is why not port them and reuse them. Imagine you have created a menu bar for an application: you spent time on things such as html, style, animations, events, etc … While developing a new application, you realize that you need the same menu, so you return to your previous project and start picking up pieces of HTML, Js, CSS and try adapt it to your new application. This process gets tedious over time and is more prone to errors. Web Components provide an answer to the question. WCs provide a way to carry and reuse HTML, CSS and JS, all encapsulated in a HTML tag. WCs are defined by 4 specifications that are now part of the W3C HTML specification:

– Custom Elements: allowing to create your own components <my-element> </ my-element>
– HTML imports: import these items in any DOM
– Templates: defining custom html templates that can be manipulated by JS
– Shadow Dom: hiding the complexity of Components by hiding the underlying html.

WCs are raw specifications. There are several frameworks that are built on the top of these specifications and allow the user to take advantage of their features. Polymer is among these frameworks. Polymer is a project built and maintained by Google. It’s a framework for building optimized applications, with high performance and a stylish look. Polymer also provides the ability to extend its functionality and create your own reusable components.

To illustrate the use of the Web Components, we will create a Polymer component with a green background that displays a pop up with each click. we’ll call this cool-div element. To do this, we need to create an element definition in a file named cool-div.html:

<dom-module id="cool-div">
<template>
<style>
:host {
display: block;
}
#mydiv{
background-color: green;
max-width: 100px;
color: white;
}

</style>
<div id="mydiv">
<content></content>
</div>
</template>

<script>
Polymer({

is: 'cool-div',

properties: {
prop1: {
type: String,
value: 'cool-div',
},
},

listeners :{
click:'divClicked'
},

divClicked: function(){
alert('cool div clicked');
}

});
</script>
</dom-module>

Now we can use this element simply by importing the definition from the head section in our HTML page:

<link rel="import" href="cool-div.html">

and then we can do something like:

<cool-div>my first Polymer element</cool-div>

Full example: https://github.com/zak905/cool-div

The intersection between GWT and Polymer

Vaadin team has done some interesting things with GWT. One of them was the adaptation of Polymer elements to GWT. gwt-polymer-elements brings not only a new potential to GWT, but can also be a replacement for Widgets which are to be removed from the version 3.0 of GWT. To adapt Polymer Elements to GWT, Vaadin chose the JsInterop approach instead of rewriting everything from scratch. In this way, the adapatation of Polymer was done in a very smooth way and without errors. Vaadin created a generator named gwt-api-generator which automatically wraps the library as an API. The generator can also be used to generate Java APIs for your own Polymer elements.

Building your first Polymer application in GWT

It’s not complicated to create a Polymer application in GWT. All you need to do is to import gwt-polymer-elements and use the -generateJsInteropExports flag. Some knowledge of Polymer components and their use is necessary, don’t worry, it comes with practice. There is a great series of podcasts that explains the basics of Polymer on Youtube called Polycasts presented by Rob Dodson (Polymer team). The documentation of Polymer Elements is also well developed and provides all the necessary information. There are also some projects in Github that can help you get some inspiration, and overcome the blank page syndrome:

https://github.com/manolo/gwt-polymer-todo-list
https://github.com/gwidgets/gwt-polymer-starter-kit
https://github.com/cdigiano/polymergwt

Important: gwt-polymer-elements works only with the 2.8.0-SNAPSHOT (RC1 as of now) version of GWT.

Wrap-up

JsInterop brings infinite possibilities to GWT. it opens a new world to GWT developers, and this is only the experimental phase. We’ll have to wait until the stable version of GWT 2.8 is launched to be able use JsIntrop production.

French version of this post is sponsored by Developpez.com and is available at: http://zakariaamine.developpez.com/tutoriels/java/gwt/utiliser-webcomponents-polymer-jsinterop/?utm_source=twitterfeed&utm_medium=twitter

Zakaria Amine

Zakaria is a freelance software engineer who enjoys working with Java web frameworks, and microservice architectures. During his free time, Zakaria works on hobby projects, and blogs about his favorite topics like GWT and Spring.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button