⬆️ ⬇️

TeaVM - a tool to create a web frontend for Java, Kotlin and Scala

Quite a long time ago I published an article on Habré, where I told about my project, TeaVM . Since then, a lot of things happened to him, including one important thing, about which we will discuss below and for which I decided to write again on Habr. But first, let me briefly remind you what the project is about.



So TeaVM is a Java bytecode compiler in javascript. The idea of ​​creating TeaVM came to me while I was a full-stack Java developer and used GWT to write a frontend. In those days (and this was about 5 years ago), tools like node.js, webpack, babel, TypeScript were not widely distributed; Angular was in the first version, and there were no alternatives like React and vue.js at all. Then, quite seriously, people were testing sites in IE7 (and some who were not lucky with customers, even IE6). In general, the JavaScript ecosystem was much less mature than it is now, and it was impossible to write JavaScript without pain.



I liked the GWT because, against the background of all this, it seemed to be an adequate solution, although not without its flaws. The main problems are listed under the cat:





It didn’t seem to me that the idea of ​​writing web applications in Java is bad in itself. All the flaws of GWT were from the fact that Google, I think, simply did not invest sufficient resources in its development. I preferred to put up with the shortcomings of GWT, just not to switch to JavaScript.



And then I thought - why not use Java bytecode as input? The bytecode saves a lot of information about the source program, so much so that decompilers manage to restore the sources almost exactly. Javaas does all the most difficult work on generating bytecode, so it takes very little time to generate JavaScript. Plus we get support for other languages ​​for JVM and almost free support for new versions of Java (bytecode is much more conservative than Java language).



What interesting happened to the project



I have already said that a lot of interesting things happened to the project. Here are the most important points that I would like to talk about:





Web framework



The TeaVM web framework is called Flavour and is entirely written in Java. Recently I published the first version (numbered 0.1.0) on Maven Central. Ideologically, it resembles modern Angular 2/4 and Vue.js, but is built entirely on idioms that are close to a Java developer. For example, all Flavor components are represented by regular Java classes, annotated with annotations, there are no separate props and state, or any special objects that should encapsulate the changing properties. The HTML template language is completely statically typed, any access to the object property or a call to the event handler is checked at compile time and, for example, typos in the name of the properties simply will not allow the project to be compiled.



To communicate with the server, Flavor suggests using interfaces marked up with JAX-RS annotations, and the data is transmitted using DTO, which in turn are marked up with Jackson annotations. This should be convenient for Java developers, who very likely already know and use these APIs in their projects.



A natural question arises: why create a framework if there are existing ones: React, Angular, Vue.js? You can just use JavaScript interop and not invent anything. Of course, I thought about it. But no, everything turns out to be much worse than it seems at first glance. These frameworks are built around the idioms of dynamically typed JavaScript, and you can create an object with the right set of properties out of thin air, and hope that the "class" of the object has a magic method with the right name. In general, in the JavaScript world, framework creators are not used to thinking about typing. This can be overcome by writing all sorts of adapters, wrappers, preprocessors, generators. But in the end, the system will be more complicated than the original frameworks, so it was decided to write your own.



Few examples



Project creation



Of course, all those interested can read the documentation on the site . But in order to make it easier and faster to taste the flavor of Flavour, I will show a small example here.



So, you can create a project using Maven:



  mvn archetype:generate \ -DarchetypeGroupId=org.teavm.flavour \ -DarchetypeArtifactId=teavm-flavour-application \ -DarchetypeVersion=0.1.0 


The generated project is collected, as expected, with the mvn package command.



Template engine



The page is described by two files - a class code that describes its behavior (provides data for display, contains event handlers) and an HTML template. In the created project there is already an example of a page, but I still give one more example. You can replace the example generated from the archetype or simply add two more files to the existing ones. This is how the page class code looks like:



 @BindTemplate("templates/fibonacci.html") public class Fibonacci { private List<Integer> values = new ArrayList<>(); public Fibonacci() { values.add(0); values.add(1); } public List<Integer> getValues() { return values; } public void next() { values.add(values.get(values.size() - 2) + values.get(values.size() - 1)); } } 


And so - its template:



 <ul> <!-- values -    this.getValues() --> <std:foreach var="fib" in="values"> <li> <html:text value="fib"/> </li> </std:foreach> <li> <!--   , event:click    -  ,         ,       --> <button type="button" event:click="next()">Show next</button> </li> </ul> 


std:foreach , html:text and event:click are the Flavor components. The user can describe his components (interested in how exactly they can read about it in the documentation ), while they can either manually draw their DOM, or do it through a template. There is nothing special about these components, they are not implemented by compiler magic. If you wish, you can write your analogs. For an illustration you can familiarize yourself with the html: text code.



Finally, here’s what the main method code should look like:



 public static void main(String[] args) { Templates.bind(new Fibonacci(), "application-content"); } 


All the main magic starts right here. The framework does not create an instance of the page class, and does not manage it in any way. Instead, you create it yourself and manage it yourself as you like, and Flavour simply generates a DOM, inserts it in the right place, tracks changes in the state of the object and redraws the DOM according to these changes. By the way, Flavor does not redraw the entire DOM, but changes only the necessary part of it.



I want to note once again that templates are statically typed. If you make a mistake and write event:click="nxt()" , then the compiler will write an error message. This approach also allows you to generate faster code - Flavor does not waste time after loading the page to parse directives and initialize the baydings; it does all this at compile time.



REST client



Now I would like to show how Flavor can be useful to a fullstack developer. Suppose you use some CXF in conjunction with JAX-RS. You wrote about this interface:



 @Path("math") public interface MathService { @GET @Path("integers/sum") int sum(@QueryParam("a") int a, @QueryParam("b") int b); } 


and implemented it (for example, in the MathServiceImpl class), registered the implementation in CXF. You have a small REST service. Now, to make a request for it, from the client’s side, you can write the following code:



 MathService math = RESTClient.factory(MathService.class).createResource("api"); System.out.println(math.sum(2, 3)); 


(it can be seen in devtools that this code will send a GET request to the address /api/math/integers/sum?a=2&b=3 ).



In general, it is not necessary to somehow explain to the web client how to properly make a REST request to the desired endpoint. You have already done this in the same way for the server and for the client. You can further increase and refactor the REST service, without having to synchronize it from the server side and from the client side - there is a synchronization point in the form of the MathService interface.



GWT has a similar mechanism, GWT-RPC, but it forces to generate an additional async interface and use callbacks, while TeaVM can convert synchronous code to asynchronous. And GWT-RPC uses its own incompatible protocol, so by creating an endpoint for GWT-RPC, you cannot reuse it, for example, for an iOS client.



What else is interesting?



Of course, in a small review article I can not tell everything at all. Therefore, I’ll just mention that there is such an interesting thing in TeaVM and Flavor, which makes them quite suitable for creating high-quality web applications.





Why is Java on the web?



Recently, the JavaScript ecosystem has become quite mature. It’s easier for a developer not to use all sorts of heavyweight monsters like GWT, but to learn how to customize tools that have become de facto standards, and write in a modern language with a lot of advanced features or even in a modern statically typed language (TypeScript).



The problem is that all this needs to be studied. Studying is not just the language syntax (an experienced developer will spend a few days on this), learn a lot of things - libraries, idioms, developer tools. I am sure that yesterday’s experienced Java developer will take and deal with all this in a couple of weeks, but the question is, how well will he have time to figure it out? Can he write really good code? Even if you understand and can, there are still problems. First, the developer will have to switch the context between Java and JavaScript. Secondly, the developer will have to spend more time setting up the tools.



Well, I have a question for the Java community. For some reason, is there such a persistent movement towards the backend from the side of JavaScript? I suspect that exactly one of the considerations that I cited above. Why not be the same movement in the opposite direction? Here is the JavaScript frontend developer community that has cooperated and spawned the backend ecosystem around node.js. How are we, the Java community, worse? There is a myth that supposedly JavaScript is smart and lightweight, and Java is big and heavy, and is not suitable for creating frontend. In fact, with my project I try to prove that it is precisely that myth, and that properly prepared Java can also be small and quick. An example of this is the implementation of TodoMVC, which takes 125kb (try writing TodoMVC on React or Angular 4 and see how big you get the bundle).



Finally



If you're interested in Flavor, here's some more study material:





I would love to get feedback. Are you interested in my project, would you like to try it for writing a small application? Do I still need to publish articles, and if so, what exactly would you like to read about it? I can publish tutorials on Flavor, I can tell how it is arranged inside, how TeaVM works. What is more interesting for you?



')

Source: https://habr.com/ru/post/339998/



All Articles