Java for web frontend developers, part 2: getting started with J2CL
Tags: j2cl, webdev, maven, java
Published: 2022-06-06 23:47:34

In the previous article I described how to create and run a simple Java application in a web browser using [j2cl-maven-plugin](https://github.com/Vertispan/j2clmavenplugin), so if you aren’t familiar with J2CL or Google Closure Compiler I’d recommend taking a look at [that article first](https://dev.to/treblereel/java-for-web-frontend-developers-part-1-generating-a-simple-project-41jp).

In this article I’m going to show you 3 scenarios of running J2CL applications:

1) Running our app as a standalone application
2) Calling methods of our application from JavaScript via a window object 
3) Exporting methods from our Java to JavaScript environment 

Before we begin: 

In the examples below, I'll be rewriting parts of the demos code. To try out complete demos you can check my [GitHub repo](https://github.com/treblereel/Beginning_J2CL/tree/main/work-with-j2cl-app-from-js) that contains all demos in one place.

If you have questions about running the demos, check my previous article.


1) [Standalone applications](https://github.com/treblereel/Beginning_J2CL/tree/main/work-with-j2cl-app-from-js/simple-xml-marshaller)

First, I created a simple POJO called `User.java` with several properties inside and a simple form with corresponding inputs that were passed to the properties of the POJO. To marshall an instance of User to XML I’ll be using the [mapper-xml](https://github.com/treblereel/mapper-xml) project. It’s an implementation of JAXB (Java Architecture for XML Binding) for GWT and J2CL. I like JAXB because it’s very flexible and allows us to process complex XML structures by annotating Java Beans. 

```java
@XMLMapper
public class User {

   private String firstName;
   private String secondName;
   private int age;

… getters and setters omitted 
```

`@XMLMapper` is necessary here to trigger a JAXB annotation processor to generate the `User_XMLMapperImpl` marshaller for this POJO. `User_XMLMapperImpl` can be used to serialize and deserialize User to XML and back.

```java
public class App {

 private AbstractObjectMapper mapper = User_XMLMapperImpl.INSTANCE;

 public void onModuleLoad() {

   HTMLDivElement xmlDivElement = (HTMLDivElement) DomGlobal.document.getElementById("xml");

   HTMLButtonElement submit = (HTMLButtonElement) DomGlobal.document.getElementById("submit");
   HTMLInputElement firstName = (HTMLInputElement) DomGlobal.document.getElementById("firstName");
   HTMLInputElement secondName =
       (HTMLInputElement) DomGlobal.document.getElementById("secondName");
   HTMLInputElement age = (HTMLInputElement) DomGlobal.document.getElementById("age");

   submit.addEventListener(
       "click",
       evt -> {
         try {
           User user = new User();
           user.setFirstName(firstName.textContent);
           user.setSecondName(secondName.textContent);

           String _age = age.textContent.trim();
           user.setAge(Integer.parseInt(age.value.trim()));

           String xml = mapper.write(user);
           xmlDivElement.textContent = xml;

           $("#exampleModal").modal("show");

         } catch (Exception e) {
           DomGlobal.alert("Exception " + e.getMessage());
         }
       });
 }
}
```

As you can see, I have added a listener to the `submit` button that collects values from the fields and sets them to the instance of the User object. When it’s done I call a mapper, which is an instance of the User’s marshaller, pass User into it and print the resulting XML on the screen. Simple and nice.


2) [Calling an XML marshaller from an existing application](https://github.com/treblereel/Beginning_J2CL/tree/main/work-with-j2cl-app-from-js/bind-to-window-xml-marshaller)

Let’s say, we already have an existing JavaScript application and we want to add an XML export feature to it. 

```java
var User = function () {
   this.firstName =  '';
   this.secondName =  '';
   this.age = -1;
}
```

The User object from the existing JavaScript application should be bound to the existing `User.java`, which is its representation in Java. To achieve that we need to do 2 steps. First, we add the `@JsType` annotation to the User (`@JsType` is part of the JsInterop API of J2CL and definitely deserves a separate article):

```java
@XMLMapper
@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "User")
public class User {

   private String firstName;
   private String secondName;
   private int age;
```

Secondly, we have to tell the Closure Compiler that a JavaScript User object exists in the global scope and it has to deal with it, so I added an extern (something like `d.ts` from TS) for it:

```java
/**
* @externs
*/

/**
* @constructor
*/
var User = function () {}

/**
* @type {string|undefined}
*/
User.prototype.firstName;

/**
* @type {string|undefined}
*/
User.prototype.secondName;

/**
* @type {number|undefined}
*/
User.prototype.age;
```

The next step is to publish our marshaller to make it discoverable from JavaScript:

```java
public class App {

 private AbstractObjectMapper mapper = User_XMLMapperImpl.INSTANCE;

 public void onModuleLoad() {
   Js.asPropertyMap(DomGlobal.window)
       .set(
           "toXml",
           (OnCall)
               user -> {
                 String xml = null;
                 try {
                   xml = mapper.write(user);
                 } catch (Exception e) {
                   DomGlobal.alert("Exception " + e.getMessage());
                 }

                 return Promise.resolve(xml);
               });
 }

 @JsFunction
 private interface OnCall {

   Promise<String> invoke(User user);
 }
}
```

As you can see, I created the `OnCall` function. It will receive a JavaScript User object, pass it to the marshaller and return a `Promise<String>` with a resulting XML. I bind this function to a window object using the property name `toXML`. So all we need is to call it from JavaScript, like this:

```java
$("#submit").on( "click", function() {

   var user = new User();
   user.firstName =  $('#firstName').val();
   user.secondName =  $('#secondName').val();
   user.age = $('#age').val();

   window.toXml(user).then(function (result) {
       $(".modal-body #xml").text(result);
       $('#exampleModal').modal('show');
       }
   );
});
```

3) [Using Google Closure Compiler to export methods to JavaScript](https://github.com/treblereel/Beginning_J2CL/tree/main/work-with-j2cl-app-from-js/js-native-xml-marshaller)

The Closure Compiler has very powerful ways to simplify interoperability with an existing JavaScript environment. To simplify its usage even further I created a project that helps with it. All we need is to add the following Maven dependencies and annotate the method we want to export with the `@GWT3Export` annotation, like I did here:

```java
<dependency>
   <groupId>org.treblereel.j2cl.processors</groupId>
   <artifactId>annotations</artifactId>
   <version>0.4.1</version>
</dependency>
<dependency>
   <groupId>org.treblereel.j2cl.processors</groupId>
   <artifactId>processors</artifactId>
   <version>0.4.1</version>
   <scope>provided</scope>
</dependency>
```


```java
public class App {

 private AbstractObjectMapper mapper = User_XMLMapperImpl.INSTANCE;

 @GWT3Export
 public Promise<String> toXml(User user) {
   String xml = null;
   try {
     xml = mapper.write(user);
   } catch (Exception e) {
     DomGlobal.alert("Exception " + e.getMessage());
   }

   return Promise.resolve(xml);
 }
}
```

The very last thing left: call it for the JavaScript:

```java
<script>

   var marshaller = new org.treblereel.j2cl.helloworld.App();

   var User = function () {
       this.firstName =  '';
       this.secondName =  '';
       this.age = -1;
   }

   $("#submit").on( "click", function() {

       var user = new User();
       user.firstName =  $('#firstName').val();
       user.secondName =  $('#secondName').val();
       user.age = $('#age').val();

       marshaller.toXml(user).then(function (result) {
           $(".modal-body #xml").text(result);
           $('#exampleModal').modal('show');
           }
       );
   });

</script>
```

In this article I have shown you a few examples of how we can deal with applications written in Java and compiled to JavaScript with the help of the J2CL Maven plugin. There are many topics I would like to touch upon in my upcoming articles from the low-level ones like writing externs and using the JsInterop API, to the high-level ones like modern UI libraries and advanced frameworks.

If you like my articles, feel free to join [GWT] (https://gitter.im/gwtproject/gwt) and [J2CL](https://gitter.im/vertispan/j2cl) channels, follow me on [Twitter](https://twitter.com/treblereel), [LinkedIn](https://www.linkedin.com/in/treblereel/) or [GitHub](https://github.com/treblereel) or even support me on [Patreon](https://www.patreon.com/treblereel) or [Stripe](https://buy.stripe.com/8wM6qO1JR9xy39S8wx).