1. Java(Script) на JVM
Дмитрий Александров
Старший эксперт-программист в T-Systems Rus
Bulgarian JUG co-lead
dmitry.aleksandrov@t-systems.ru
@bercut2000
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
1
2. Поговорим о JavaScript…
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
2
3. Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
3
4. WAT
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
4
By
Gary
Bernhardt:
h-p://www.youtube.com/watch?v=20BySC_6HyY
5. План на сегодня
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
5
6. Was ist JavaScript?
• Разработан Бренданом Ейхом за 15 дней в далеком 1995 году
• Диалект ECMAScript (да, это не синонимы)
• Мультипарадигменный: прототипный, слаботипизированный,
функциональный, императивный… скриптовый
• Ducktyped
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
6
7. Was ist Nashorn?
• Читается как Насхорн (ˈnaːsˌhɔʁn ).. Не наШорн!
• Рантайм для ECMAScript 5.1 (6.0) на JVM
• GPL
• Часть OpenJDK
• Релиз – Март 2014
• Просто напишите jjs в консоли.. И вы в игре!
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
7
8. … Зачем?
Закон Атвуда: любое приложение, которое
может быть написано на JavaScript, рано или
поздно оно будет написано на JavaScript
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
8
9. Зачем:
• Поддержка Oracle динамических языков
• Ныне часть JRE
• 100% поддержка ECMAScript 5.1
• Частичная поддержка ECMAScript 6
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
9
10. Почему не Rhino?
• Весь код компилируется в bytecode. Нет
интерпретации.. Даже в консоли!
• Самый большой потребитель InvokeDynamic
в мире!
• JSR-223 javax.script.* единое публичное API
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
10
11. Часть первая..
Java -> JavaScript
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
11
12. Самое простое
import
javax.script.ScriptEngine;
import
javax.script.ScriptEngineManager;
import
javax.script.ScriptExcepOon;
public
class
EvalScript
{
public
sta.c
void
main(String[]
args)
throws
ExcepOon
{
//
create
a
script
engine
manager
ScriptEngineManager
factory
=
new
ScriptEngineManager();
//
create
a
Nashorn
script
engine
ScriptEngine
engine
=
factory.getEngineByName("nashorn");
//
evaluate
JavaScript
statement
try
{
engine.eval("print('Hello,
World!');");
}
catch
(final
ScriptExcepOon
se)
{
se.printStackTrace();
}
}
}
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
12
13. Чуть сложнее: Multiple invoke
import
javax.script.Invocable;
import
javax.script.ScriptEngine;
import
javax.script.ScriptEngineManager;
public
class
Eval_Invocable
{
public
sta.c
void
main(String[]
args)
throws
ExcepOon
{
ScriptEngineManager
factory
=
new
ScriptEngineManager();
ScriptEngine
engine
=
factory.getEngineByName("nashorn");
engine.eval("funcOon
f(x){return
x
<
2
?
1
:
f(x-‐1)*x}
");
engine.eval("funcOon
sum(x,y){return
x+y}");
Invocable
i
=
(Invocable)
engine;
System.out.println(i.invokeFuncOon("f",5));
System.out.println(i.invokeFuncOon("f",10));
System.out.println(i.invokeFuncOon("sum",5,10));
System.out.println(i.invokeFuncOon("sum",10,15));
}
}
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
13
14. Имплементируем интерфейс
public
class
Eval_InvocableInterface
{
public
sta.c
void
main(String...
args)
throws
ExcepOon{
ScriptEngine
engine
=
new
ScriptEngineManager().getEngineByName("nashorn");
engine.eval("funcOon
sum(x,y){return
x+y}");
Invocable
i
=
(Invocable)
engine;
Adder
adder=
i.getInterface(Adder.class);
System.out.println(adder.sum(1,3));
}
}
public
interface
Adder
{
int
sum(int
a,
int
b);
}
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
14
15. Передаем переменные
public
class
Eval_Bind
{
public
sta.c
void
main(String...
args)
throws
ExcepOon
{
ScriptEngine
engine
=
new
ScriptEngineManager().getEngineByName("nashorn");
Bindings
b
=
engine.createBindings();
b.put("file",
new
File("/"));
engine.eval("list
=
file.listFiles()",
b);
System.out.println(Arrays.toString((File[])
b.get("list")));
}
}
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
15
16. Часть Вторая..
JavaScript -> Java
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
16
17. Попроще:
var
Omer
=
new
java.uOl.Timer();
Omer.schedule(
new
java.uOl.TimerTask({
run:
func.on(){
print("Tick")
}
})
,0,1000)
java.lang.Thread.sleep(5000)
Omer.cancel();
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
17
18. Или даже так:
var
Omer2=
new
java.uOl.Timer();
Omer2.schedule(func.on(){print("Tack")},0,1000)
java.lang.Thread.sleep(5000)
Omer2.cancel();
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
18
19. Конструируем Java(Script) объект
• var
linkedList
=
new
java.uOl.LinkedList()
• var
LinkedList
=
java.uOl.LinkedList
var
list
=
new
LinkedList()
• var
LinkedList
=
Java.type(“java.uOl.LinkedList”)
var
list
=
new
LinkedList()
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
19
20. Типы
var
ints
=
new
(Java.type(“int[]”))(6)
ints[0]=1
ints[1]=1.6
ints[2]=null
ints[3]=“45”
ints[4]=“str”
Ints[5]=undefined
print(ints)
print(java.uOl.Arrays.toString(ints))
На
выходе
будет:
[I@43re2sd
[1,
1,
0,
45,
0,
0]
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
20
21. Типы 2
Var
dbls
=
new
(Java.type(“double[]”))(6)
dbls
[0]=1
dbls
[1]=1.6
dbls
[2]=null
dbls
[3]=“45”
dbls
[4]=“str”
dbls
[5]=undefined
print(dbls
)
print(java.uOl.Arrays.toString(dbls
))
Output
will
be:
[D@43re2sd
[1.0,
1.6,
0.0,
45.0,
NaN,
NaN]
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
21
22. Конвертирование типов
• Сначала пытается конвертировать JavaScript
методами, и далее Java методами
• Все JS native объекты имплементируют
java.util.Map
• .. И они НЕ имплементируют java.util.List
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
22
23. И еще о конвертировании
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
23
Представим
себе:
sta.c
void
about(Object
object)
{
System.out.println(object.getClass());
}
24. И еще о конвертировании
MyJavaClass.about(123);
//
class
java.lang.Integer
MyJavaClass.about(49.99);
//
class
java.lang.Double
MyJavaClass.about(true);
//
class
java.lang.Boolean
MyJavaClass.about("hi
there")
//
class
java.lang.String
MyJavaClass.about(new
Number(23));
//
class
jdk.nashorn.internal.objects.Na.veNumber
MyJavaClass.about(new
Date());
//
class
jdk.nashorn.internal.objects.Na.veDate
MyJavaClass.about(new
RegExp());
//
class
jdk.nashorn.internal.objects.Na.veRegExp
MyJavaClass.about({foo:
'bar'});
//
class
jdk.nashorn.internal.scripts.JO4
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
24
25. Конвертирование массивов
• Сами не конвертируются!
• Существует специализированные методы:
– var javaArray = Java.toJavaArray( jsArray,type)
– var jsArray = Java.toJavaScriptArray( javaArray)
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
25
26. Доступ static
var
ps
=
java.io.File.pathSeparator
print(ps)
var
File
=
Java.type("java.io.File")
var
p
=
File.separator
print(p)
var
MapEntry
=
java.uOl.AbstractMap.SimpleEntry
print(MapEntry)
var
m
=
new
MapEntry(1,"b");
print(m)
На
выходе:
:
/
[JavaClass
java.uOl.AbstractMap$SimpleEntry]
1=b
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
26
27. Кстати, а ведь это Java 8!
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
27
28. Кстати, а ведь это Java 8!
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
28
29. … так вот
JavaScript:
var
stack
=
new
java.uOl.LinkedList();
[1,
2,
3,
4,54,87,42,32,65,4,5,8,43].forEach(func.on(item)
{
stack.push(item);
});
print(stack.getClass());
var
sorted
=
stack
.stream()
.filter(func.on(i){return
i%2==0})
.sorted()
.toArray();
print(java.uOl.Arrays.toString(sorted));
На
выходе:
[Ljava.lang.Object;@6591f517
[2,
4,
4,
8,
32,
42,
54]
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
29
30. .. и Default методы
Java:
public
interface
DefTest
{
default
void
sayHello(String
name){
System.out.println("Hello
"+name);
}
}
public
class
DefTestImpl
implements
DefTest
{
//nothing
here
}
JavaScript:
>jjs
-‐cp
.
jjs>
var
DT
=
Java.type("DefTestImpl")
jjs>
DT
[JavaClass
DefTestImpl]
jjs>
var
dt
=
new
DT()
jjs>
dt.sayHello("World")
Hello
World
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
30
32. Scripting расширения
• Возможность указывать classpath элементы
для JVM
• JavaScript Strict Mode
• Scripting mode!!!!
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
32
36. Как оно работает
• Dynalink:
Имплементация метаобъектного протокола
мультиязычного связывающего фреймворка,
основанного на invokedynamic.
Позволяет JVM классам созданными одним
языком вызывать методы и свойства классов
созданными другим языковым рантаймом в
одной инстанции JVM
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
36
37. Как оно работает
• Dynalink:
– Позволяет динамически вызывать операции на
объектах создавая MethodHandle или
– В случае генерации байткода, позволяет вызывать
методы без знания конкретной модели
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
37
39. Как оно работает
• HTML5 и CSS3 + быстрые JS движки
превратили браузер в мощную платформу
• Восход “Thin Server Architecture” (TSA) &
“Single Page Architecture”
• ..но они все общались на разных языках до
появления node.js
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
39
40. Node.js event loop
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
40
41. …И как это происходит в Avatar.js
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
41
43. Демо
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
43
44. Node модули работающие с Avatar.js
• abbrev
• ansi
• async
• block-‐stream
• chmodr
• chownr
• coffee-‐script
• colors
• commander
• connect
• debug
• engine.io
• express
• ƒsream[1]
• glob[1]
• graceful-‐fs
• inherits
• ini
• init-‐package-‐json
• grunt
• grunt-‐bower-‐task
• jade
• lodash
• mime
• mkdirp
• mocha
• moment[2]
• mongodb[3]
• mongoose[3],
[4]
• mustache
• node-‐unit
• node-‐uuid
• once
• opener
• opOmist
• osenv
• passport
• q
• read
• redis
• request
• retry
• rimraf
• ronn
• semver
• slide
• socket.io
• tar
• uglify-‐js
• uid-‐number
• underscore
• which
• winston
[1]:
with
minor
issues
related
to
symbolic
link
handling
[2]:
some
issues
with
Ancient
Greek
lang
[3]:
Replace
all
const
occurrences
with
var
[4]:
Buffer
Schema
data
type
is
not
supported
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
44
45. Avatar EE
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
45
46. Приложение Avatar EE
• … или Архив
• Простая папка содержащая avatar.properties и
WEB-INF папку
• Содержит папку Views и/или Service
• «Встроенная системная» папкаа
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
46
47. Сервисы Avatar
• Сервис Avatar наследует REST, WebSocket или
SSE абстракцию
• Относительно ленивый. Инстансцируется и
вызывается при первом вызове. Как Servlet.
• Одновременно доступны библиотеки node.js
и все библиотеки Java
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
47
48. Avatar клиент
• View
– Декларативное UI
– Bundle widgets ( jQuery-ui)
• Model
– WS, REST, SSE, local
– Autowire with services
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
48
49. Avatar клиент
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
49
50. Avatar EE
• Data providers
– JPA provider
• JavaScript API интерфейс для Java Messaging Service (JMS)
• На будущее: “native” API для другие EE технологий:
– Context and Dependency Injection (CDI)
– Enterprise Java Beans (EJB)
– ..etc
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
50
51. Демо
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
51
54. Часть последняя..
Состояние на сегодня
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
54
55. Дела на сегодня
• Начиная с 8u20 поддержка cache для уже скомпилированных скриптов
• Начиная с 8u40
– Optimistic typing (JEP196)*
– Code Persistence (JEP194)
• --class-cache-size=100 default 50
• --persistent-code-cache=true|false default false
– Class Filter (JEP202)
– Partial ECMAScript 6 support const/var (JEP203)
• --language=es5|es6 default is es5
• --lazy-compilation=true|false
• *
NashornScriptEngineManager
factory
=
new
NashornScriptEngineManager();
ScriptEngine
engine
=
factory.getEngineByName(”—opOmisOc-‐types=true");
Октябрь 16–18 2015 | Санкт-Петербург
#jokerconf
dmitryalexandrov.net | @bercut2000
55
56. let & var
// let
let a=2;
function f(x){
// a=2
if (x){
let a=42;
}
// a все еще 2
}
// var
var a=2;
function f(x){
// a = undefined
if (x){
let a=42;
}
// либо 42 либо undefined
}