-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfaq.html
531 lines (447 loc) · 19.8 KB
/
faq.html
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
---
layout: default
title: FAQ
---
<h3>
<a id="whatIsStjs">What is ST-JS</a>
</h3>
<p>ST-JS is a Java-to-JavaScript transpiler. It's goal is to let
you write true JavaScript while borrowing the syntax and type
checking of Java.</p>
<p>ST-JS lets you write your client-side code in Java, and will
generate the equivalent JavaScript that can then be executed in a
browser. It lets you write your Java source in the same way that you
would usually write the equivalent JavaScript. It lets you use all
the JavaScript libraries you have grown fond of, without ever
forcing any other library on you.</p>
<p>The JavaScript ST-JS generates is not only readable, but also
immediately recognizable. It strives to keep the generated
JavaScript code as close as possible to your Java source code, and
to make it look like you had written the JavaScript yourself by
hand.</p>
<p>ST-JS also strives to stay as lightweight and un-intrusive as
possible. This is why ST-JS does not impose or even suggest the use
of any particular framework or library, be it server-side or
client-side.</p>
<h3>
<a id="whyStjs">Why ST-JS? (aka: the genesis of ST-JS)</a>
</h3>
<p>To better explain how ST-JS is useful and how it differs from
existing tools, let me start by telling you a story. It's the
genesis of ST-JS.</p>
<p>
Alexandru and Nicolas (see: <a href="team.html">Team</a>) and their
team were working on a rather large HTML 5 web application. The
development of this application was started many months ago by
another team of developers. Both teams were composed mostly of java
developers, with limited JavaScript experience. Development was going
well at first, but soon slowed down to a crawl.
</p>
<p>When the size of the JavaScript codebase reached approximately
5'000 lines of JavaSript code, all the developers began complaining
that their progress was being hindered by JavaScript. The project
would work perfectly in one browser, and then completely fail to
start in another due to minor syntax errors. Fixing a bug in one
corner of the application mysteriously caused two new ones in
another corner. As a result development continued, but no real
progress was made on the important stuff: delivering features to
our customers.</p>
<p>One day, we improvised a small, informal retrospective. We
analyzed our problems and dug out the root causes. Here is what we
found:</p>
<ul>
<li>For a Java developer, JavaScript is full of small gotchas.
(Arrays are indexed by String? Trailing commas are bad? On an
array, for-in produces String indices? What's the difference between
undefined and null again? for-in on an object also brings
up methods? etc...) While these gotchas are fairly obvious to any
experienced JavaScript developer, they are surprising for Java
devs. As a result they often cause obscure bugs, or different
behavior on different browsers.</li>
<li>The project has involved more than 15 people across its
life, with no less than 5 or 6 active at the same time. This
obviously means that not everybody was aware of all the
implementation details of the rest of the application. As a result,
when developers changed a piece of code, they were never fully
aware of all the consequences of that change on the whole project.
For example, a dev might want to change the name of a property. How
can he know he correctly rename it everywhere in the code
where this property is used? When he sees a property that looks
like it needs to be changed, how can he be sure that this property
really belongs to the correct object? Because of all these troubles,
developers became afraid of refactoring, and the codebase slowly
became more and more difficult to work with.</li>
</ul>
<p>After exposing these causes, the solution to the problem came
to Alexandru. We could write a Java to Javascript transpiler!</p>
<p>This had multiple benefits for us:
<ul>
<li>We don't have to deal with most of the idiosyncrasies of
JavaScript. We just write Java, and the transpiler does the rest</li>
<li>It is immediately clear which variable/field is of what
type, even to developers unfamiliar with the existing code</li>
<li>We can refactor safely because all of the Java IDEs know
how to do that. And for the cases where the refactoring is more
complicated and done manually, the Java compiler instantly checks
the correctness of the code.</li>
</ul>
</p>
<p>Within about a week, all the existing JavaScript code was
converted to Java code following the ST-JS conventions. Since then,
the project was able to grow freely and healthily.</p>
<h3><a id="whyNotGwt">Why not GWT/Dart/TypeScript/CoffeeScript/etc... ?</a></h3>
<p>Before deciding to write ST-JS, we have listed our needs, and
studied the existing alternatives. Our needs were:</p>
<ul>
<li>Static type checking</li>
<li>Widespread first-class IDE support</li>
<li>Automatic refactoring tools</li>
<li>Lightweight, no large runtime dependencies</li>
<li>Un-intrusive - doesn't force us to use any particular
framework either client-side or server-side, doesn't make it
inconvenient to use our favorite client-side or server-side
libraries</li>
<li>Easy to debug in all environments (dev, test,
pre-production, production)</li>
<li>Static code analysis tools are available</li>
</ul>
<p>Out of all the existing solutions, none matches all of these
criteria. ST-JS is our answer to this problem, and it does fulfill
all of our needs.</p>
<p>There is another extra benefit that wasn't part of our
original requirements. If for some reason, in the middle of your
development process you discovered that ST-JS doesn't work for you,
you can safely dump your Java source files and continue your
development in JavaScript directly, by basing it on the generated
JavaScript.</p>
<h3><a id="howDoesItWork">How does it work?</a></h3>
ST-JS is made of multiple components that each have a specific purpose
<ul>
<li>
<strong>generator:</strong> The main tool of ST-JS. It is the program that translates your Java to JavaScript.
In order to run correctly, this generator needs both your Java source code and the corresponding
compiled .class files.
</li>
<li>
<strong>js-lib:</strong> A small Java library that contains the various classes and interfaces required to write
ST-JS code that will run your browser. The classes it contains mirror the JavaScript DOM API, as well as many
other useful JavaScript constructs (Math, XMLHttpRequest, Window, Console, etc...). This library is only used at
compile time by the Java compiler (or your IDE), to verify that all the calls to the aforementionned JS APIs use
correct argument types. It is also used by your IDE to provide you with nice, typed, autocomplete while you write
your ST-Js code.
</li>
<li>
<strong>stjs.js:</strong> A small JavaScript file that contains the objects and functions necessary to implement
some of the Java concepts in JavaScript (inheritance, enums, etc...). This file must be included in your final
HTML page, before all the generated JavaScript. This file is the only mandatory runtime dependency for ST-JS.
</li>
<li>
<strong>jquery bridge:</strong> A Java library that exposes a properly typed version of the jQuery API. It's purpose
and usage is similar to js-lib, but for jQuery. Note that jQuery is not a dependency of ST-JS, and using this bridge is
not mandatory.
</li>
<li>
<strong>Maven plugin:</strong> Helps you setup the generator to run in your Maven projects. If you use Eclipse, this
plugin also provides some level of integration with Eclipse by showing ST-JS errors as error badges in your Java
files.
</li>
<li>
<strong>JUnit runner:</strong> Allows you to write Java unit tests with ST-JS and run them as JavaScript with JUnit.
You write your unit tests in Java, those tests are translated to JavaScript by the generator, and then sent to a JS
execution environment. You can decide to run those JS unit tests in many different environments (Rhino, web browser,
phantomjs, etc...).
</li>
</ul>
<h3><a id="shouldIUseIt">Should I use it?</a></h3>
<p>As for many other tools, the answer is: "It depends".</p>
<p>The benefits of ST-JS are most useful if your project matches one or more of the following criteria</p>
<ul>
<li>Lots of JavaScript (several thousands lines)</li>
<li>Multiple developers</li>
<li>Long project history</li>
</ul>
<p>Of course, you can use ST-JS for any project, but there is a slight overhead in development due to the
fact that you have to run the ST-JS generator on your Java code everytime you change it. ST-JS comes with
a few integrated mechanisms to do it automatically, but at the time of writing it only works properly
in Eclipse.</p>
<h3><a id="whatDoesItLookLike">What does it look like?</a></h3>
<p>Here is an example of a code written in Java and the
corresponding generated JavaScript. The Java code may seem a bit
longer and possibly more complicated at a first glance, but it
provides you with all the advantages of a typed language, while
preserving as much as possible the resemblance to the JavaScript
style of programming. The visual resemblance is crucial here since
it allows for faster learning and easier transition. This visual
resemblance maintained throughout the library design</p>
<h4>Short example</h4>
<div class="grid_5 alpha">
<pre class="code prettyprint lang-java">
// Java
$("#form").submit((ev, THIS) -> {
StockData stockData =
that.updateStock($("#newStock").val());
$(that.row(stockData)).appendTo("table tbody");
that.stocks.push(stockData.stock);
});
</pre>
</div>
<div class="grid_5 omega">
<pre class="code prettyprint lang-JavaScript">
// Generated JavaScript
$("#form").submit(function(ev) {
var stockData =
that.updateStock($("#newStock").val());
$(that.row(stockData)).appendTo("table tbody");
that.stocks.push(stockData.stock);
});
</pre>
</div>
<div class="clear"></div>
<h4>Some more JavaScript constructs</h4>
<p>The problem with having JavaScript code generated from Java is
that Java is less rich than JavaScript. There are JavaScript
constructions that do not have their corresponding in Java (or they
are different) like object (map) constructors, array constructors,
inline functions. We tried to provide constructions that may look
unusual for a Java developer but somehow familiar to a JavaScript
developer.</p>
<h5>Data Objects</h5>
<p>Javascript has a very handy syntax for creating objects with
all of their properties already initialized. As you probably know,
this syntax is the basis of the JSON format.</p>
<p>ST-JS promotes the usage of a similar syntax in Java, but
using proper type declarations.</p>
<div class="grid_5 alpha">
<pre class="code prettyprint lang-java">
// Java
StockData stock = new StockData() { {
last = 10.0;
close = 2.0;
stock = "ABC";
} };</pre>
</div>
<div class="grid_5 omega">
<pre class="code prettyprint lang-JavaScript">
// Generated JavaScript
var stock = {
"last" : 10,
"close" : 2,
"stock" : "ABC"
};
</pre>
</div>
<div class="clear"></div>
<h5>Hashes / Associative arrays / Maps</h5>
<p>In JavaScript, every object can also be used as an associative
array with string keys. This allows each field of an object to be
accessed directly via its name.
<p>
<p>
ST-JS provides a bridge class that allows you to use this behavior
in your Java code, and see it the proper associative array construct
being used in the translated JavaScript. This capability is provided
via the <strong>org.stjs.JavaScript.Map</strong> class
</p>
<div class="grid_5 alpha">
<pre class="code prettyprint lang-java">
// Java
// This Map is a org.stjs.JavaScript.Map
Map<String, Object> stock = $map(
"last", 2.0,
"close", 3.5,
"symbol", "ABC"
);
Double close = map.$get("close");
stock.$set("close", 4.8);
stock.$delete("close");</pre>
</div>
<div class="grid_5 omega">
<pre class="code prettyprint lang-JavaScript">
// Generated JavaScript
var stock = {
"last" : 2.0,
"close" : 3.5,
"symbol" : "ABC";
};
var close = stock["close"];
stock["close"] = 4.8;
delete stock["close"];</pre>
</div>
<div class="clear"></div>
<h5>Arrays</h5>
<p>
JavaScript arrays behave like a mixture of a Java's lists and
arrays. ST-JS provides the <strong>org.stjs.JavaScript.Array</strong>
class to bring the JavaScript behavior in Java. This class offers
the same methods as its JavaScript counterpart. Givent that the
bracket ([]) construct can only be used in Java with a regular
array, this class provides $get/$set methods that will generate the
expected code in JavaScript
</p>
<div class="grid_5 alpha">
<pre class="code prettyprint lang-java">
// Java
Array<Integer> array = $array(1, 5, 10);
Integer value = array.$get(2);
array.$set(2, 4);
// looping by counter
for(int i = 0; i < array.$length(); i ++){
console.info(i + " : " + array.$get(i));
}
// looping with forEach
array.forEach((el, i, arr) ->
console.info(i + " : " + arr.$get(i))
);
</pre>
</div>
<div class="grid_5 omega">
<pre class="code prettyprint lang-JavaScript">
// Generated Javascript
var array = [1, 5, 10];
var value = array[2];
array[2] = 4;
// looping by counter
for(var i = 0; i < array.length; i ++){
console.info(i + " : " + array[i]);
}
// looping with forEach
array.forEach(function(el, i, arr){
console.info(i + " : " + arr[i]);
}
</pre>
</div>
<div class="clear"></div>
<h5>Inheritance</h5>
<p>Class inheritance is a fundamental concept in Class-based,
Object-Oriented languages like Java. That concept doesn't exist in
JavaScript, but its behavior can be reproduced in its native
prototype-based inheritance.</p>
<p>In order to keep the generated JavaScript code as close as
possible to the source Java code, we have decided not to enforce the
(in-)visibility of members in JavaScript. This means that when a
field is marked privat, protected or package-protected in the Java
source, it will be generated as if it was public in the generated
JavaScript. This is an acceptable compromise given that the
visibility restrictions are enforced by the Java compiler before the
JavaScript code is generated.</p>
<div class="grid_5 alpha">
<pre class="code prettyprint lang-java">
// Java
public class Child extends Parent {
public Child(String name) {
super(name);
this.name = name;
}
public static int staticField = 1;
public int instanceField = 2;
public String name = "default";
@Override
public void instanceMethod(String n) {
super.instanceMethod(n + "-");
}
public static void staticMethod() {
staticField += 1;
}
}</pre>
</div>
<div class="grid_5 omega">
<pre class="code prettyprint lang-JavaScript">
// Generated JavaScript
Child = function(name) {
this._super(null, test);
this.name = name;
}
stjs.extend(Child, Parent, [],
function(constructor, prototype){
constructor.staticField = 1;
prototype.instanceField = 2;
prototype.name = "default";
prototype.instanceMethod = function(n) {
this._super("instanceMethod", n + "-");
}
constructor.staticMethod = function() {
Child.staticField += 1;
}
});</pre>
</div>
<div class="clear"></div>
<h5>Comparison</h5>
<p>
The comparison of objects or primitives is slightly different
between Java and Javscript. For example <i>equals</i> method does
not exist in JavaScript (and there is no way to influence how
egality operators behave in JavaScript).<br /> Conversely the
triple "=" (===) does not exist in Java. And the "==" sign has a
slightly different meaning: in JavaScript it may be accompanied by a
type conversion!<br /> To have a predictable behavior of the
generated JavaScript, the <i>equals</i> method is generated as-is.
The equals method was added to all primitive types wrappers in
JavaScript. More all generated classes will have an equals method
defined in their hierarchy. The "==" sign is left untouched as there
is basically no automatic type conversion involved (because the
initial Java code wouldn't allow it).
</p>
<h3><a id="limitations">Limitations, aka: "What you cannot do in ST-JS?"</a></h3>
<p>Due to the fact that ST-JS strives to keep the generated
JavaScript code as close as possible to your source Java code, it
has to deal with the limitations of both Java and JavaScript. This
means that some of the features of the Java language cannot be used
in your ST-JS code, and will cause an error during the
Java->JavaScript transpilation.</p>
<p>Here are the main restrictions imposed by ST-JS</p>
<p>
<strong>No overloading.</strong> This means you cannot have multiple
methods with the same name (or multiple constructors) in the same
class. Method overriding however is allowed, so you can easily
change the behavior of a method in a subclass.
</p>
<p>
<strong>No separate namespace for fields and methods.</strong> As a
result, you cannot have a method and a field with the same name
within one class and all of its parent classes and interfaces!
</p>
<p>
<strong>Javascript keywords cannot be used as identifiers.</strong>
So you cannot use JavaScript keywords or reserved words (such as
"function", "prototype", "var", etc...) as field, method or class
name.
</p>
<p>
<strong>Limited support for varargs.</strong>. Varags are only
allowed if your method has a single argument, and this argument's
name is "arguments".
</p>
<p>
<strong>Instance fields can only be initialized at
declaration with literals.</strong> Therefore any instance field that is
not a primitive type, a Number, a String or null must be initialized
in the constructor.
</p>
<p>
<strong>No native Java arrays.</strong>. Native Java arrays (such as
String[]) cannot be used as they are not direclty compatible with
the JavaScript version of arrays. JavaScript arrays are much richer
than Java arrays, and provide a set of useful methods such as push,
slice, etc... On top of that, the for-in iteration in Java array is
done on values (<i>for(String s : array)</i>) while the iteration in
JavaScript is done on indexes (<i>for(var idx : array)</i>). ST-JS
provides the <strong>org.stjs.JavaScript.Array</strong> class to
reproduced the JavaScript array behavior.
</p>
<p>
<strong>No Java collections.</strong> Since JavaScript doesn't have an
equivalent to the java.util Collection interfaces and all of its various
implementations, they cannot be used in your ST-JS code. We have decided
against supporting these collections directly, because they are a very
typical Java idiosyncrasy. Using them in some JavaScript code would be
awkward and doesn't fit the philosophy of ST-JS.
</p>
<p>While some of these limitations could be worked around by
making STJS a little bit more complex, it would result in the
JavaScript code diverging too far from the original Java source.
Removing these limitations would need going against to the
philosophy of ST-JS: the generated JavaScript code is immediately
recognizable when compared with your Java source code. That's why we
prefer to produce transpilation-time errors and to ask the user to
find a suitable alternative.</p>
</p>