0
# Java Integration
1
2
Comprehensive Java-JavaScript interoperability system providing seamless bidirectional communication, automatic type conversion, Java class access, and adapter objects for implementing Java interfaces with JavaScript.
3
4
## Capabilities
5
6
### Type Conversion
7
8
Automatic conversion between Java and JavaScript values with comprehensive type mapping and coercion rules.
9
10
```java { .api }
11
/**
12
* Converts Java object to JavaScript representation
13
* @param value Java object to convert
14
* @param scope JavaScript scope for object creation
15
* @return JavaScript representation of Java object
16
*/
17
public static Object javaToJS(Object value, Scriptable scope);
18
19
/**
20
* Converts Java object to JavaScript representation with explicit Context
21
* @param value Java object to convert
22
* @param scope JavaScript scope for object creation
23
* @param cx Context for the conversion
24
* @return JavaScript representation of Java object
25
*/
26
public static Object javaToJS(Object value, Scriptable scope, Context cx);
27
28
/**
29
* Converts JavaScript value to Java object of specified type
30
* @param value JavaScript value to convert
31
* @param desiredType Target Java class/interface
32
* @return Java object of desired type
33
*/
34
public static Object jsToJava(Object value, Class<?> desiredType);
35
36
/**
37
* Converts JavaScript value to boolean
38
* @param value JavaScript value
39
* @return boolean representation
40
*/
41
public static boolean toBoolean(Object value);
42
43
/**
44
* Converts JavaScript value to number
45
* @param value JavaScript value
46
* @return double representation
47
*/
48
public static double toNumber(Object value);
49
50
/**
51
* Converts JavaScript value to string
52
* @param value JavaScript value
53
* @return String representation
54
*/
55
public static String toString(Object value);
56
57
/**
58
* Converts JavaScript value to Scriptable object
59
* @param value JavaScript value
60
* @param scope Scope for object creation
61
* @return Scriptable representation
62
*/
63
public static Scriptable toObject(Object value, Scriptable scope);
64
```
65
66
**Usage Examples:**
67
68
```java
69
// Java to JavaScript conversion
70
List<String> javaList = Arrays.asList("a", "b", "c");
71
Object jsArray = Context.javaToJS(javaList, scope);
72
73
// JavaScript to Java conversion
74
String jsString = "42";
75
Object jsNumber = cx.evaluateString(scope, jsString, "test", 1, null);
76
Integer javaInt = (Integer) Context.jsToJava(jsNumber, Integer.class);
77
78
// Type coercion examples
79
Object jsValue = cx.evaluateString(scope, "true", "test", 1, null);
80
boolean javaBool = Context.toBoolean(jsValue); // true
81
double javaNum = Context.toNumber(jsValue); // 1.0
82
String javaStr = Context.toString(jsValue); // "true"
83
84
// Converting JavaScript objects
85
Object jsObj = cx.evaluateString(scope, "({name: 'test', value: 42})", "test", 1, null);
86
Map<String, Object> javaMap = (Map<String, Object>) Context.jsToJava(jsObj, Map.class);
87
```
88
89
### Java Object Wrapping
90
91
Wrapping Java objects for access from JavaScript with automatic method binding and property access.
92
93
```java { .api }
94
/**
95
* JavaScript wrapper for Java objects
96
* Provides property access and method invocation from JavaScript
97
*/
98
public class NativeJavaObject extends ScriptableObject {
99
/**
100
* Creates wrapper for Java object
101
* @param scope JavaScript scope
102
* @param javaObject Java object to wrap
103
* @param staticType Static type for method resolution
104
*/
105
public NativeJavaObject(Scriptable scope, Object javaObject, Class<?> staticType);
106
107
/**
108
* Gets the wrapped Java object
109
* @return Original Java object
110
*/
111
public Object unwrap();
112
113
/**
114
* Gets the static type used for method resolution
115
* @return Java class
116
*/
117
public Class<?> getStaticType();
118
119
/**
120
* Coerces JavaScript value to Java type
121
* @param type Target Java type
122
* @param value JavaScript value to convert
123
* @return Converted Java value
124
*/
125
public static Object coerceTypeImpl(Class<?> type, Object value);
126
}
127
128
/**
129
* JavaScript wrapper for Java classes (not instances)
130
* Allows access to static methods and constructors
131
*/
132
public class NativeJavaClass extends NativeJavaObject {
133
/**
134
* Creates wrapper for Java class
135
* @param scope JavaScript scope
136
* @param cl Java class to wrap
137
*/
138
public NativeJavaClass(Scriptable scope, Class<?> cl);
139
140
/**
141
* Gets the wrapped Java class
142
* @return Java Class object
143
*/
144
public Class<?> getClassObject();
145
}
146
147
/**
148
* JavaScript wrapper for Java methods
149
* Handles method overloading and parameter conversion
150
*/
151
public class NativeJavaMethod extends BaseFunction {
152
/**
153
* Creates wrapper for Java method(s)
154
* @param methods Array of Method objects (for overloading)
155
* @param name Method name for JavaScript
156
*/
157
public NativeJavaMethod(Method[] methods, String name);
158
}
159
160
/**
161
* JavaScript wrapper for Java constructors
162
* Enables 'new' operator usage from JavaScript
163
*/
164
public class NativeJavaConstructor extends BaseFunction {
165
/**
166
* Creates wrapper for Java constructor(s)
167
* @param constructors Array of Constructor objects
168
*/
169
public NativeJavaConstructor(Constructor<?>[] constructors);
170
}
171
```
172
173
**Usage Examples:**
174
175
```java
176
// Wrapping Java objects
177
StringBuilder sb = new StringBuilder("Hello");
178
Object wrappedSB = Context.javaToJS(sb, scope);
179
180
// Accessing from JavaScript
181
String result = (String) cx.evaluateString(scope, """
182
wrappedSB.append(' World');
183
wrappedSB.toString();
184
""", "test", 1, null);
185
System.out.println(result); // "Hello World"
186
187
// Working with Java classes
188
Class<?> stringClass = String.class;
189
Object wrappedClass = Context.javaToJS(stringClass, scope);
190
scope.put("StringClass", scope, wrappedClass);
191
192
// Using static methods from JavaScript
193
Object staticResult = cx.evaluateString(scope, """
194
StringClass.valueOf(123);
195
""", "test", 1, null);
196
```
197
198
### Java Array Integration
199
200
Special handling for Java arrays with JavaScript Array-like syntax and methods.
201
202
```java { .api }
203
/**
204
* JavaScript wrapper for Java arrays
205
* Provides Array-like access and some Array prototype methods
206
*/
207
public class NativeJavaArray extends NativeJavaObject {
208
/**
209
* Creates wrapper for Java array
210
* @param scope JavaScript scope
211
* @param array Java array to wrap
212
*/
213
public NativeJavaArray(Scriptable scope, Object array);
214
215
/**
216
* Gets array length
217
* @return Array length
218
*/
219
public int getLength();
220
221
/**
222
* Gets array element at index
223
* @param index Array index
224
* @return Array element
225
*/
226
public Object get(int index);
227
228
/**
229
* Sets array element at index
230
* @param index Array index
231
* @param value New element value
232
*/
233
public void put(int index, Object value);
234
}
235
```
236
237
**Usage Examples:**
238
239
```java
240
// Working with Java arrays
241
int[] javaArray = {1, 2, 3, 4, 5};
242
Object wrappedArray = Context.javaToJS(javaArray, scope);
243
scope.put("javaArray", scope, wrappedArray);
244
245
// Access from JavaScript with array syntax
246
Object result = cx.evaluateString(scope, """
247
javaArray[2] = 99; // Modify Java array
248
javaArray.length; // Get length
249
""", "test", 1, null);
250
251
// Java array is modified
252
System.out.println(Arrays.toString(javaArray)); // [1, 2, 99, 4, 5]
253
```
254
255
### Java Collection Integration
256
257
Enhanced integration for Java Collection framework classes with JavaScript semantics.
258
259
```java { .api }
260
/**
261
* JavaScript wrapper for Java List implementations
262
* Implements both Scriptable and List interfaces
263
*/
264
public class NativeJavaList extends NativeJavaObject implements List<Object> {
265
/**
266
* Creates wrapper for Java List
267
* @param scope JavaScript scope
268
* @param list Java List to wrap
269
*/
270
public NativeJavaList(Scriptable scope, List<?> list);
271
272
// List interface methods delegated to wrapped list
273
public int size();
274
public boolean isEmpty();
275
public boolean contains(Object o);
276
public Iterator<Object> iterator();
277
public Object[] toArray();
278
public boolean add(Object o);
279
public boolean remove(Object o);
280
public void clear();
281
public Object get(int index);
282
public Object set(int index, Object element);
283
public void add(int index, Object element);
284
public Object remove(int index);
285
}
286
287
/**
288
* JavaScript wrapper for Java Map implementations
289
* Provides Map access with JavaScript object semantics
290
*/
291
public class NativeJavaMap extends NativeJavaObject {
292
/**
293
* Creates wrapper for Java Map
294
* @scope JavaScript scope
295
* @param map Java Map to wrap
296
*/
297
public NativeJavaMap(Scriptable scope, Map<?, ?> map);
298
299
/**
300
* Gets map size
301
* @return Number of key-value pairs
302
*/
303
public int size();
304
305
/**
306
* Checks if key exists
307
* @param key Key to check
308
* @return true if key exists
309
*/
310
public boolean containsKey(Object key);
311
}
312
```
313
314
**Usage Examples:**
315
316
```java
317
// Working with Java Collections
318
List<String> javaList = new ArrayList<>();
319
javaList.addAll(Arrays.asList("a", "b", "c"));
320
Object wrappedList = Context.javaToJS(javaList, scope);
321
scope.put("javaList", scope, wrappedList);
322
323
// Use from JavaScript with array-like syntax
324
cx.evaluateString(scope, """
325
javaList[1] = 'modified'; // Set element
326
javaList.add('d'); // Call List method
327
""", "test", 1, null);
328
329
// Java List is modified
330
System.out.println(javaList); // [a, modified, c, d]
331
332
// Working with Maps
333
Map<String, Object> javaMap = new HashMap<>();
334
javaMap.put("key1", "value1");
335
Object wrappedMap = Context.javaToJS(javaMap, scope);
336
scope.put("javaMap", scope, wrappedMap);
337
338
// Access map from JavaScript
339
Object value = cx.evaluateString(scope, "javaMap.get('key1')", "test", 1, null);
340
```
341
342
### Package and Class Access
343
344
Accessing Java packages and classes from JavaScript with automatic class loading.
345
346
```java { .api }
347
/**
348
* JavaScript representation of Java packages
349
* Allows navigation of package hierarchy from JavaScript
350
*/
351
public class NativeJavaPackage extends ScriptableObject {
352
/**
353
* Creates package wrapper for given package name
354
* @param packageName Java package name (e.g., "java.util")
355
*/
356
public NativeJavaPackage(String packageName);
357
358
/**
359
* Gets package name
360
* @return Package name string
361
*/
362
public String getPackageName();
363
}
364
365
/**
366
* Top-level package objects (java, javax, org, etc.)
367
* Provides root access to Java package hierarchy
368
*/
369
public class NativeJavaTopPackage extends NativeJavaPackage {
370
/**
371
* Creates top-level package (java, javax, etc.)
372
* @param packageName Top-level package name
373
*/
374
public NativeJavaTopPackage(String packageName);
375
}
376
```
377
378
**Usage Examples:**
379
380
```java
381
// Enable Java class access (done automatically with initStandardObjects)
382
ImporterTopLevel importerScope = new ImporterTopLevel(cx);
383
384
// Access Java classes from JavaScript
385
Object result = cx.evaluateString(importerScope, """
386
var ArrayList = java.util.ArrayList;
387
var list = new ArrayList();
388
list.add('item1');
389
list.add('item2');
390
list.size();
391
""", "test", 1, null);
392
System.out.println(result); // 2.0
393
394
// Import classes for easier use
395
cx.evaluateString(importerScope, """
396
importClass(java.util.HashMap);
397
var map = new HashMap();
398
map.put('key', 'value');
399
""", "test", 1, null);
400
```
401
402
### WrapFactory
403
404
Controls how Java objects are wrapped for JavaScript access with customizable wrapping behavior.
405
406
```java { .api }
407
/**
408
* Factory for controlling Java object wrapping
409
* Customize how Java objects appear in JavaScript
410
*/
411
public class WrapFactory {
412
/**
413
* Wraps Java object for JavaScript access
414
* @param cx Current Context
415
* @param scope JavaScript scope
416
* @param obj Java object to wrap
417
* @param staticType Static type for method resolution
418
* @return Wrapped JavaScript object
419
*/
420
public Object wrap(Context cx, Scriptable scope, Object obj, Class<?> staticType);
421
422
/**
423
* Wraps Java object as NativeJavaObject
424
* @param cx Current Context
425
* @param scope JavaScript scope
426
* @param javaObject Java object to wrap
427
* @param staticType Static type
428
* @return NativeJavaObject wrapper
429
*/
430
public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class<?> staticType);
431
432
/**
433
* Wraps Java class as NativeJavaClass
434
* @param cx Current Context
435
* @param scope JavaScript scope
436
* @param javaClass Java class to wrap
437
* @return NativeJavaClass wrapper
438
*/
439
public Scriptable wrapJavaClass(Context cx, Scriptable scope, Class<?> javaClass);
440
441
/**
442
* Wraps new object (return value from constructor or method)
443
* @param cx Current Context
444
* @param scope JavaScript scope
445
* @param obj New Java object
446
* @param staticType Static type
447
* @return Wrapped object
448
*/
449
public Object wrapNewObject(Context cx, Scriptable scope, Object obj);
450
451
/**
452
* Checks if object should be wrapped
453
* @param obj Java object
454
* @param type Static type
455
* @param isStatic true if static context
456
* @return true if object should be wrapped
457
*/
458
public boolean isJavaPrimitiveWrap();
459
}
460
```
461
462
**Usage Examples:**
463
464
```java
465
// Custom WrapFactory to control wrapping behavior
466
WrapFactory customFactory = new WrapFactory() {
467
@Override
468
public Object wrap(Context cx, Scriptable scope, Object obj, Class<?> staticType) {
469
// Custom wrapping logic
470
if (obj instanceof MySpecialClass) {
471
return new MySpecialWrapper(scope, obj, staticType);
472
}
473
return super.wrap(cx, scope, obj, staticType);
474
}
475
};
476
477
// Set custom WrapFactory on Context
478
cx.setWrapFactory(customFactory);
479
480
// Now Java objects will be wrapped using custom logic
481
Object wrapped = Context.javaToJS(new MySpecialClass(), scope);
482
```
483
484
### JavaAdapter
485
486
Creates Java objects that implement interfaces using JavaScript implementations.
487
488
```java { .api }
489
/**
490
* Creates Java objects implementing interfaces with JavaScript
491
* Allows JavaScript functions to implement Java interfaces
492
*/
493
public class JavaAdapter {
494
/**
495
* Creates adapter object implementing Java interfaces
496
* @param jsObj JavaScript object with method implementations
497
* @param adapter Java interface/class to implement
498
* @return Java object implementing interface
499
*/
500
public static Object createAdapterWrapper(Scriptable jsObj, Object adapter);
501
502
/**
503
* Creates adapter class implementing interfaces
504
* @param cx Current Context
505
* @param scope JavaScript scope
506
* @param args Arguments: [interfaces..., constructor, prototype]
507
* @param writeAdapter Whether to write class file
508
* @return Constructor function for adapter class
509
*/
510
public static Scriptable createAdapterClass(Context cx, Scriptable scope, Object[] args, boolean writeAdapter);
511
}
512
```
513
514
**Usage Examples:**
515
516
```java
517
// Implementing Java interface with JavaScript
518
String jsCode = """
519
new java.lang.Runnable({
520
run: function() {
521
print('Running from JavaScript!');
522
}
523
});
524
""";
525
526
Object jsRunnable = cx.evaluateString(scope, jsCode, "adapter", 1, null);
527
Runnable runnable = (Runnable) Context.jsToJava(jsRunnable, Runnable.class);
528
runnable.run(); // Calls JavaScript function
529
530
// More complex interface implementation
531
String listenerCode = """
532
new java.awt.event.ActionListener({
533
actionPerformed: function(event) {
534
print('Action performed: ' + event.getActionCommand());
535
}
536
});
537
""";
538
539
Object jsListener = cx.evaluateString(scope, listenerCode, "listener", 1, null);
540
ActionListener listener = (ActionListener) Context.jsToJava(jsListener, ActionListener.class);
541
```
542
543
### Advanced Integration Features
544
545
#### Method Overloading Resolution
546
547
Rhino automatically resolves Java method overloads based on argument types.
548
549
```java
550
// Java class with overloaded methods
551
public class Calculator {
552
public int add(int a, int b) { return a + b; }
553
public double add(double a, double b) { return a + b; }
554
public String add(String a, String b) { return a + b; }
555
}
556
557
// From JavaScript - automatic overload resolution
558
Calculator calc = new Calculator();
559
Object wrappedCalc = Context.javaToJS(calc, scope);
560
scope.put("calc", scope, wrappedCalc);
561
562
cx.evaluateString(scope, """
563
calc.add(1, 2); // Calls int version -> 3
564
calc.add(1.5, 2.5); // Calls double version -> 4.0
565
calc.add('a', 'b'); // Calls String version -> 'ab'
566
""", "overload", 1, null);
567
```
568
569
#### Bean Property Access
570
571
Automatic property access for Java Bean getter/setter methods.
572
573
```java
574
// Java Bean class
575
public class Person {
576
private String name;
577
private int age;
578
579
public String getName() { return name; }
580
public void setName(String name) { this.name = name; }
581
public int getAge() { return age; }
582
public void setAge(int age) { this.age = age; }
583
}
584
585
// From JavaScript - property-style access
586
Person person = new Person();
587
Object wrappedPerson = Context.javaToJS(person, scope);
588
scope.put("person", scope, wrappedPerson);
589
590
cx.evaluateString(scope, """
591
person.name = 'John'; // Calls setName()
592
person.age = 30; // Calls setAge()
593
594
var name = person.name; // Calls getName()
595
var age = person.age; // Calls getAge()
596
""", "bean", 1, null);
597
```
598
599
### Java Method Binding with FunctionObject
600
601
The FunctionObject class enables direct binding of Java methods and constructors to JavaScript functions with automatic type conversion.
602
603
```java { .api }
604
/**
605
* A JavaScript function object that wraps a Java method or constructor.
606
* Enables binding Java methods to JavaScript functions with automatic
607
* type conversion and proper 'this' handling.
608
*/
609
public class FunctionObject extends BaseFunction {
610
/**
611
* Create a JavaScript function object from a Java method or constructor.
612
* @param name the name of the function
613
* @param methodOrConstructor a java.lang.reflect.Method or Constructor
614
* @param scope enclosing scope of function
615
*/
616
public FunctionObject(String name, Member methodOrConstructor, Scriptable scope);
617
618
/**
619
* Return the arity (number of parameters) of the function.
620
* @return the number of parameters
621
*/
622
public int getArity();
623
624
/**
625
* Get the name of this function.
626
* @return the function name, or empty string if none
627
*/
628
public String getFunctionName();
629
630
/**
631
* Get the underlying Java method or constructor this function represents.
632
* @return the Member (Method or Constructor)
633
*/
634
public Member getMethodOrConstructor();
635
636
/**
637
* Define this function as a JavaScript constructor.
638
* @param scope the scope to define the constructor in
639
* @param prototype the prototype object
640
*/
641
public void addAsConstructor(Scriptable scope, Scriptable prototype);
642
643
// Type conversion utilities
644
public static int getTypeTag(Class<?> type);
645
public static Object convertArg(Context cx, Scriptable scope, Object arg, int typeTag);
646
647
// Type constants for method parameter conversion
648
public static final int JAVA_UNSUPPORTED_TYPE = 0;
649
public static final int JAVA_STRING_TYPE = 1;
650
public static final int JAVA_INT_TYPE = 2;
651
public static final int JAVA_BOOLEAN_TYPE = 3;
652
public static final int JAVA_DOUBLE_TYPE = 4;
653
public static final int JAVA_SCRIPTABLE_TYPE = 5;
654
public static final int JAVA_OBJECT_TYPE = 6;
655
}
656
```
657
658
**Usage Examples:**
659
660
```java
661
// Bind static method to JavaScript function
662
public class MathUtils {
663
public static double square(double x) {
664
return x * x;
665
}
666
667
public static String format(String template, Object... args) {
668
return String.format(template, args);
669
}
670
}
671
672
// Create function binding
673
Method squareMethod = MathUtils.class.getMethod("square", double.class);
674
FunctionObject squareFunction = new FunctionObject("square", squareMethod, scope);
675
scope.put("square", scope, squareFunction);
676
677
// Use from JavaScript
678
Object result = cx.evaluateString(scope, "square(5)", "test", 1, null);
679
System.out.println(result); // 25.0
680
681
// Bind instance method to JavaScript function
682
public class Calculator {
683
private double value = 0;
684
685
public double add(double x) {
686
return value += x;
687
}
688
689
public double getValue() {
690
return value;
691
}
692
}
693
694
Calculator calc = new Calculator();
695
Method addMethod = Calculator.class.getMethod("add", double.class);
696
FunctionObject addFunction = new FunctionObject("add", addMethod, scope);
697
698
// Bind the calculator instance
699
scope.put("calc", scope, Context.javaToJS(calc, scope));
700
scope.put("addToCalc", scope, addFunction);
701
702
// Use from JavaScript - the 'this' binding is handled automatically
703
cx.evaluateString(scope, "addToCalc.call(calc, 10)", "test", 1, null);
704
System.out.println(calc.getValue()); // 10.0
705
706
// Constructor binding
707
public class Point {
708
private double x, y;
709
710
public Point(double x, double y) {
711
this.x = x;
712
this.y = y;
713
}
714
715
public double getX() { return x; }
716
public double getY() { return y; }
717
}
718
719
Constructor<Point> pointConstructor = Point.class.getConstructor(double.class, double.class);
720
FunctionObject pointFunction = new FunctionObject("Point", pointConstructor, scope);
721
722
// Add prototype for the constructor
723
Scriptable pointPrototype = cx.newObject(scope);
724
pointFunction.addAsConstructor(scope, pointPrototype);
725
726
// Use constructor from JavaScript
727
Object pointObj = cx.evaluateString(scope, "new Point(3, 4)", "test", 1, null);
728
// Creates a Point instance accessible from JavaScript
729
```
730
731
#### Exception Handling
732
733
Java exceptions are automatically converted to JavaScript errors.
734
735
```java
736
// Java method that throws exception
737
public class TestClass {
738
public void throwException() throws Exception {
739
throw new IllegalArgumentException("Test exception");
740
}
741
}
742
743
// From JavaScript - exception becomes JavaScript error
744
TestClass test = new TestClass();
745
scope.put("test", scope, Context.javaToJS(test, scope));
746
747
try {
748
cx.evaluateString(scope, """
749
try {
750
test.throwException();
751
} catch (e) {
752
print('Caught: ' + e.message); // "Test exception"
753
print('Java class: ' + e.javaException.getClass().getName());
754
}
755
""", "exception", 1, null);
756
} catch (WrappedException we) {
757
// WrappedException contains the original Java exception
758
Throwable original = we.getWrappedException();
759
}
760
```