js4j 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,684 @@
1
+ # js4j
2
+
3
+ A Node.js implementation of [py4j](https://www.py4j.org/) — a bridge between JavaScript and Java using the py4j gateway protocol. js4j clients are wire-compatible with py4j's `GatewayServer`, so any existing Java side that works with py4j works with js4j too.
4
+
5
+ - Zero runtime dependencies
6
+ - Full TypeScript type definitions included
7
+ - Supports bidirectional communication (Java → JS callbacks)
8
+ - Mirrors the py4j API surface for easy migration
9
+
10
+ ---
11
+
12
+ ## Table of Contents
13
+
14
+ - [Prerequisites](#prerequisites)
15
+ - [Installation](#installation)
16
+ - [Quick Start](#quick-start)
17
+ - [API Reference](#api-reference)
18
+ - [JavaGateway](#javagateway)
19
+ - [GatewayParameters](#gatewayparameters)
20
+ - [CallbackServerParameters](#callbackserverparameters)
21
+ - [ClientServer](#clientserver)
22
+ - [JVMView](#jvmview)
23
+ - [Java Object Types](#java-object-types)
24
+ - [JavaObject](#javaobject)
25
+ - [JavaClass](#javaclass)
26
+ - [JavaPackage](#javapackage)
27
+ - [JavaList](#javalist)
28
+ - [JavaSet](#javaset)
29
+ - [JavaMap](#javamap)
30
+ - [JavaArray](#javaarray)
31
+ - [JavaIterator](#javaiterator)
32
+ - [Callbacks](#callbacks)
33
+ - [createJavaProxy](#createjavaproxy)
34
+ - [CallbackServer](#callbackserver)
35
+ - [ProxyPool](#proxypool)
36
+ - [Errors](#errors)
37
+ - [TypeScript](#typescript)
38
+ - [Credits](#credits)
39
+
40
+ ---
41
+
42
+ ## Prerequisites
43
+
44
+ The Java side must be running a py4j `GatewayServer`. Add py4j to your Java project and start a server:
45
+
46
+ ```java
47
+ import py4j.GatewayServer;
48
+
49
+ public class MyEntryPoint {
50
+ public int add(int a, int b) { return a + b; }
51
+
52
+ public static void main(String[] args) {
53
+ GatewayServer server = new GatewayServer(new MyEntryPoint());
54
+ server.start();
55
+ System.out.println("Gateway server started on port 25333");
56
+ }
57
+ }
58
+ ```
59
+
60
+ The py4j JAR is available on [Maven Central](https://search.maven.org/artifact/net.sf.py4j/py4j) or bundled with a py4j Python installation at `$site-packages/py4j/java/py4j.jar`.
61
+
62
+ ---
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ npm install js4j
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Quick Start
73
+
74
+ ```js
75
+ const { JavaGateway } = require('js4j');
76
+
77
+ async function main() {
78
+ const gateway = new JavaGateway({ port: 25333 });
79
+ await gateway.connect();
80
+
81
+ // Call methods on the entry point object
82
+ const result = await gateway.entry_point.add(3, 4); // 7
83
+
84
+ // Traverse the JVM namespace to construct objects and call static methods
85
+ const sb = await gateway.jvm.java.lang.StringBuilder('Hello');
86
+ await sb.append(', World!');
87
+ console.log(await sb.toString()); // "Hello, World!"
88
+
89
+ const pi = await gateway.getField(gateway.jvm.java.lang.Math, 'PI'); // 3.14159…
90
+
91
+ await gateway.close();
92
+ }
93
+
94
+ main();
95
+ ```
96
+
97
+ ---
98
+
99
+ ## API Reference
100
+
101
+ ### JavaGateway
102
+
103
+ The main entry point. Connects to a Java `GatewayServer` and provides access to the JVM.
104
+
105
+ ```js
106
+ const { JavaGateway } = require('js4j');
107
+ const gateway = new JavaGateway(gatewayParameters?, callbackServerParameters?);
108
+ ```
109
+
110
+ Both arguments accept either a parameter object instance or a plain options object (see [GatewayParameters](#gatewayparameters) and [CallbackServerParameters](#callbackserverparameters)).
111
+
112
+ #### Properties
113
+
114
+ | Property | Type | Description |
115
+ |---|---|---|
116
+ | `jvm` | `JVMView` | Root of the JVM namespace. Available after `connect()`. |
117
+ | `entry_point` | `JavaObject` | The entry point object registered with the `GatewayServer`. Available after `connect()`. |
118
+ | `connected` | `boolean` | Whether the gateway is currently connected. |
119
+ | `gatewayParameters` | `GatewayParameters` | The resolved connection parameters. |
120
+ | `callbackServerParameters` | `CallbackServerParameters` | The resolved callback server parameters. |
121
+
122
+ #### Methods
123
+
124
+ **`connect() → Promise<this>`**
125
+
126
+ Open the connection pool to the Java gateway. Must be called before any other operations.
127
+
128
+ ```js
129
+ await gateway.connect();
130
+ ```
131
+
132
+ **`close() → Promise<void>`**
133
+
134
+ Close all connections and stop the callback server (if running). Does not shut down the Java GatewayServer.
135
+
136
+ **`shutdown() → Promise<void>`**
137
+
138
+ Send a shutdown command to the Java GatewayServer, then close all connections.
139
+
140
+ **`startCallbackServer() → Promise<CallbackServer>`**
141
+
142
+ Start a TCP server that accepts Java → JS callback connections. Required if you pass JS proxy objects to Java.
143
+
144
+ ```js
145
+ await gateway.startCallbackServer();
146
+ ```
147
+
148
+ **`shutdownCallbackServer() → Promise<void>`**
149
+
150
+ Stop the callback server.
151
+
152
+ **`getField(target, fieldName) → Promise<any>`**
153
+
154
+ Read a field on a Java object or class (including static fields).
155
+
156
+ ```js
157
+ const pi = await gateway.getField(gateway.jvm.java.lang.Math, 'PI');
158
+ const name = await gateway.getField(myObj, 'name');
159
+ ```
160
+
161
+ **`setField(target, fieldName, value) → Promise<void>`**
162
+
163
+ Write a field on a Java object.
164
+
165
+ ```js
166
+ await gateway.setField(myObj, 'value', 42);
167
+ ```
168
+
169
+ **`newArray(javaClass, ...dimensions) → Promise<JavaArray>`**
170
+
171
+ Create a new Java array of the given type and dimensions.
172
+
173
+ ```js
174
+ const arr = await gateway.newArray(gateway.jvm.java.lang.Integer, 5);
175
+ await arr.set(0, 100);
176
+ ```
177
+
178
+ Multi-dimensional arrays use multiple dimension arguments:
179
+
180
+ ```js
181
+ const matrix = await gateway.newArray(gateway.jvm.java.lang.Double, 3, 3);
182
+ ```
183
+
184
+ **`javaImport(classFqn) → Promise<void>`**
185
+
186
+ Import a Java class into the `jvm` namespace so it can be accessed by simple name.
187
+
188
+ ```js
189
+ await gateway.javaImport('java.util.ArrayList');
190
+ const list = await gateway.jvm.ArrayList();
191
+ ```
192
+
193
+ **`newJvmView(name?) → Promise<JVMView>`**
194
+
195
+ Create an additional JVMView with its own import namespace.
196
+
197
+ **`getMethods(javaObject) → Promise<string[]>`**
198
+
199
+ List the public methods of a Java object.
200
+
201
+ **`getFields(javaObject) → Promise<string[]>`**
202
+
203
+ List the public fields of a Java object.
204
+
205
+ **`getStaticMembers(javaClass) → Promise<string[]>`**
206
+
207
+ List the public static members of a Java class.
208
+
209
+ **`help(target) → Promise<string>`**
210
+
211
+ Get documentation for a Java object, class, or class FQN string.
212
+
213
+ **`releaseObject(javaObject) → Promise<void>`**
214
+ **`detach(javaObject) → Promise<void>`**
215
+
216
+ Notify the JVM that a Java object reference is no longer needed (allows garbage collection). Both names are equivalent.
217
+
218
+ ---
219
+
220
+ ### GatewayParameters
221
+
222
+ Configuration for connecting to the Java GatewayServer.
223
+
224
+ ```js
225
+ const { GatewayParameters } = require('js4j');
226
+ const params = new GatewayParameters(options?);
227
+ ```
228
+
229
+ | Option | Type | Default | Description |
230
+ |---|---|---|---|
231
+ | `host` | `string` | `'127.0.0.1'` | Hostname of the GatewayServer. |
232
+ | `port` | `number` | `25333` | Port of the GatewayServer. |
233
+ | `authToken` | `string \| null` | `null` | Authentication token (if the server requires one). |
234
+ | `autoField` | `boolean` | `false` | Automatically read fields on property access (not yet implemented). |
235
+ | `autoConvert` | `boolean` | `false` | Automatically convert Java collections to JS types (not yet implemented). |
236
+ | `enableMemoryManagement` | `boolean` | `false` | Auto-release Java objects when they are garbage collected. |
237
+ | `poolSize` | `number` | `4` | Number of TCP connections to maintain in the connection pool. |
238
+
239
+ A plain object can be passed anywhere `GatewayParameters` is expected:
240
+
241
+ ```js
242
+ const gateway = new JavaGateway({ host: 'localhost', port: 25333 });
243
+ ```
244
+
245
+ ---
246
+
247
+ ### CallbackServerParameters
248
+
249
+ Configuration for the callback server (JS-side TCP server that accepts Java → JS calls).
250
+
251
+ ```js
252
+ const { CallbackServerParameters } = require('js4j');
253
+ const params = new CallbackServerParameters(options?);
254
+ ```
255
+
256
+ | Option | Type | Default | Description |
257
+ |---|---|---|---|
258
+ | `host` | `string` | `'127.0.0.1'` | Address to bind the callback server on. |
259
+ | `port` | `number` | `25334` | Port to listen on. |
260
+ | `daemonize` | `boolean` | `true` | Allow Node.js to exit even if the server is still listening. |
261
+ | `propagateException` | `boolean` | `false` | Re-throw exceptions from callback methods. |
262
+
263
+ ---
264
+
265
+ ### ClientServer
266
+
267
+ A convenience wrapper that combines `JavaGateway` and `CallbackServer` and starts both automatically. Mirrors py4j's `ClientServer`.
268
+
269
+ ```js
270
+ const { ClientServer } = require('js4j');
271
+
272
+ const cs = new ClientServer(
273
+ { port: 25333 }, // gateway parameters
274
+ { port: 25334 } // callback server parameters
275
+ );
276
+ await cs.connect();
277
+ ```
278
+
279
+ `ClientServer` exposes the same convenience methods as `JavaGateway` and additionally starts the callback server during `connect()`.
280
+
281
+ #### Properties
282
+
283
+ | Property | Type | Description |
284
+ |---|---|---|
285
+ | `jvm` | `JVMView` | Delegated from the underlying gateway. |
286
+ | `entry_point` | `JavaObject` | Delegated from the underlying gateway. |
287
+ | `gateway` | `JavaGateway` | The underlying gateway instance. |
288
+ | `callbackServer` | `CallbackServer \| null` | The callback server instance, once started. |
289
+
290
+ #### Methods
291
+
292
+ `connect()`, `shutdown()`, `getField()`, `setField()`, `newArray()`, `newJvmView()`, `getMethods()`, `getFields()`, `getStaticMembers()`, `javaImport()`, `help()`, `releaseObject()`, `detach()` — all delegate to the underlying `JavaGateway`.
293
+
294
+ ---
295
+
296
+ ### JVMView
297
+
298
+ The root of the `gateway.jvm` namespace. Accessed as `gateway.jvm` after `connect()`.
299
+
300
+ #### Traversal
301
+
302
+ Property access on a `JVMView` returns `JavaPackage` or `JavaClass` objects by following the Java package hierarchy. A segment starting with an uppercase letter is treated as a class name.
303
+
304
+ ```js
305
+ const jvm = gateway.jvm;
306
+
307
+ // Package traversal
308
+ const pkg = jvm.java.util; // JavaPackage for java.util
309
+ const cls = jvm.java.util.ArrayList; // JavaClass for java.util.ArrayList
310
+
311
+ // Constructor call — returns Promise<JavaObject>
312
+ const list = await jvm.java.util.ArrayList();
313
+
314
+ // Static method call
315
+ const abs = await jvm.java.lang.Math.abs(-42); // 42
316
+ ```
317
+
318
+ #### Methods
319
+
320
+ **`javaImport(fqn) → Promise<void>`**
321
+
322
+ Register a class FQN as a shortcut so it can be accessed by simple name on this view.
323
+
324
+ ```js
325
+ await gateway.jvm.javaImport('java.util.LinkedList');
326
+ const ll = await gateway.jvm.LinkedList(); // works now
327
+ ```
328
+
329
+ **`removeImport(fqn) → Promise<void>`**
330
+
331
+ Remove a previously registered shortcut.
332
+
333
+ **`getClass(classFqn) → JavaClass`**
334
+
335
+ Get a `JavaClass` directly by FQN without traversal.
336
+
337
+ ```js
338
+ const ArrayList = jvm.getClass('java.util.ArrayList');
339
+ ```
340
+
341
+ **`help(classFqn) → Promise<string>`**
342
+
343
+ Get documentation for a Java class by FQN.
344
+
345
+ ---
346
+
347
+ ### Java Object Types
348
+
349
+ #### JavaObject
350
+
351
+ A reference to a Java object instance. Property access returns async functions that invoke Java methods.
352
+
353
+ ```js
354
+ const sb = await gateway.jvm.java.lang.StringBuilder('Hello');
355
+ await sb.append(' World'); // calls StringBuilder.append
356
+ const s = await sb.toString(); // 'Hello World'
357
+ const len = await sb.length(); // 11
358
+ ```
359
+
360
+ The object has two reserved properties used internally:
361
+
362
+ | Property | Type | Description |
363
+ |---|---|---|
364
+ | `_targetId` | `string` | Internal object ID used in the py4j protocol. |
365
+ | `_gatewayClient` | `GatewayClient` | The client that owns this reference. |
366
+
367
+ Any other property access returns a function that invokes the corresponding Java method.
368
+
369
+ #### JavaClass
370
+
371
+ A reference to a Java class, used for constructors and static members. Obtained by traversing `gateway.jvm`.
372
+
373
+ ```js
374
+ const Math = gateway.jvm.java.lang.Math;
375
+
376
+ // Static method call
377
+ const abs = await Math.abs(-5); // 5
378
+
379
+ // Constructor call (same as await jvm.java.lang.String('hello'))
380
+ const str = await gateway.jvm.java.lang.String('hello');
381
+
382
+ // Static field access
383
+ const pi = await gateway.getField(Math, 'PI');
384
+ ```
385
+
386
+ | Property | Type | Description |
387
+ |---|---|---|
388
+ | `_fqn` | `string` | Fully-qualified class name. |
389
+ | `_targetId` | `string` | Protocol target ID (`z:<fqn>` for static dispatch). |
390
+ | `_isJavaClass` | `true` | Marker property. |
391
+
392
+ #### JavaPackage
393
+
394
+ An intermediate namespace object returned during package traversal. Not directly callable.
395
+
396
+ | Property | Type | Description |
397
+ |---|---|---|
398
+ | `_fqn` | `string` | The partial package name accumulated so far. |
399
+ | `_isJavaPackage` | `true` | Marker property. |
400
+
401
+ #### JavaList
402
+
403
+ Returned automatically when a Java method returns a `java.util.List`. Wraps standard `List` methods and adds JS conveniences.
404
+
405
+ ```js
406
+ const list = await gateway.entry_point.getList(); // JavaList
407
+
408
+ await list.size(); // number
409
+ await list.get(0); // element at index
410
+ await list.add('item'); // append
411
+ await list.addAt(1, 'item'); // insert at index
412
+ await list.set(0, 'replaced'); // replace element
413
+ await list.remove(0); // remove by index (or by value if non-integer)
414
+ await list.contains('item'); // boolean
415
+ await list.indexOf('item'); // number
416
+ await list.subList(1, 3); // JavaList slice
417
+ await list.sort(); // in-place sort (natural ordering)
418
+ await list.reverse(); // in-place reverse
419
+ await list.count('item'); // occurrences of value
420
+ await list.toArray(); // Promise<any[]> — all elements as a JS array
421
+
422
+ // Async iteration
423
+ for await (const item of list) {
424
+ console.log(item);
425
+ }
426
+
427
+ // Access any other List method not listed above
428
+ await list.isEmpty();
429
+ await list.lastIndexOf('item');
430
+ ```
431
+
432
+ #### JavaSet
433
+
434
+ Returned automatically when a Java method returns a `java.util.Set`.
435
+
436
+ ```js
437
+ const set = await gateway.entry_point.getSet(); // JavaSet
438
+
439
+ await set.size();
440
+ await set.add('item');
441
+ await set.remove('item');
442
+ await set.contains('item');
443
+ await set.clear();
444
+ await set.toArray(); // Promise<any[]>
445
+ await set.toSet(); // Promise<Set<any>> — native JS Set
446
+
447
+ for await (const item of set) { … }
448
+ ```
449
+
450
+ #### JavaMap
451
+
452
+ Returned automatically when a Java method returns a `java.util.Map`.
453
+
454
+ ```js
455
+ const map = await gateway.entry_point.getMap(); // JavaMap
456
+
457
+ await map.size();
458
+ await map.get('key');
459
+ await map.put('key', 'value');
460
+ await map.remove('key');
461
+ await map.containsKey('key');
462
+ await map.containsValue('value');
463
+ await map.clear();
464
+ await map.keySet(); // JavaSet of keys
465
+ await map.values(); // JavaObject (Collection)
466
+ await map.entrySet(); // JavaSet of Map.Entry objects
467
+ await map.toMap(); // Promise<Map<any,any>> — native JS Map
468
+ await map.toObject(); // Promise<Record<string,any>> — plain JS object
469
+ ```
470
+
471
+ #### JavaArray
472
+
473
+ Returned automatically when a Java method returns a Java array, or created via `gateway.newArray()`.
474
+
475
+ ```js
476
+ const arr = await gateway.newArray(gateway.jvm.java.lang.Integer, 3);
477
+
478
+ await arr.length(); // 3
479
+ await arr.get(0); // element at index
480
+ await arr.set(0, 42); // set element
481
+ await arr.slice(1, 3); // JavaArray (sub-array)
482
+ await arr.toArray(); // Promise<any[]>
483
+
484
+ for await (const item of arr) { … }
485
+ ```
486
+
487
+ #### JavaIterator
488
+
489
+ Returned automatically when a Java method returns a `java.util.Iterator`.
490
+
491
+ ```js
492
+ const iter = await someJavaObject.iterator();
493
+
494
+ await iter.hasNext(); // boolean
495
+ await iter.next(); // next element
496
+ await iter.remove(); // remove last returned element
497
+ await iter.toArray(); // Promise<any[]>
498
+
499
+ for await (const item of iter) { … }
500
+ ```
501
+
502
+ ---
503
+
504
+ ### Callbacks
505
+
506
+ Callbacks allow Java code to call back into JavaScript. This requires a `CallbackServer` to be running and JS objects to be registered with a `ProxyPool`.
507
+
508
+ #### createJavaProxy
509
+
510
+ Wrap a plain JS object so that it can be passed to Java as an implementation of one or more Java interfaces.
511
+
512
+ ```js
513
+ const { createJavaProxy } = require('js4j');
514
+
515
+ const proxy = createJavaProxy(interfaces, impl);
516
+ ```
517
+
518
+ | Parameter | Type | Description |
519
+ |---|---|---|
520
+ | `interfaces` | `string[]` | Fully-qualified names of the Java interfaces this object implements. |
521
+ | `impl` | `object` | An object whose methods will be called by Java. |
522
+
523
+ The returned object has two additional properties: `_js4jProxy: true` and `_interfaces: string[]`.
524
+
525
+ ```js
526
+ // Implement java.lang.Runnable
527
+ const runnable = createJavaProxy(['java.lang.Runnable'], {
528
+ run() {
529
+ console.log('Java called run!');
530
+ return null;
531
+ },
532
+ });
533
+
534
+ const thread = await gateway.jvm.java.lang.Thread(runnable);
535
+ await thread.start();
536
+ await thread.join();
537
+ ```
538
+
539
+ ```js
540
+ // Implement java.util.Comparator
541
+ const byLength = createJavaProxy(['java.util.Comparator'], {
542
+ compare(a, b) {
543
+ return String(a).length - String(b).length;
544
+ },
545
+ });
546
+
547
+ const list = await gateway.jvm.java.util.ArrayList();
548
+ await list.add('banana'); await list.add('fig'); await list.add('apple');
549
+ await gateway.jvm.java.util.Collections.sort(list, byLength);
550
+ ```
551
+
552
+ ```js
553
+ // Implement java.util.concurrent.Callable (returns a value)
554
+ const callable = createJavaProxy(['java.util.concurrent.Callable'], {
555
+ call() {
556
+ return 'hello from JS';
557
+ },
558
+ });
559
+
560
+ const future = await gateway.jvm.java.util.concurrent.FutureTask(callable);
561
+ await future.run();
562
+ const result = await future.get(); // 'hello from JS'
563
+ ```
564
+
565
+ > **Note:** Callback proxies require a `CallbackServer` to be running. Use `ClientServer` (which starts one automatically) or call `gateway.startCallbackServer()` before passing proxies to Java.
566
+
567
+ #### CallbackServer
568
+
569
+ Manages the TCP server that accepts incoming Java → JS calls.
570
+
571
+ ```js
572
+ const { CallbackServer } = require('js4j');
573
+
574
+ const server = new CallbackServer({
575
+ host: '127.0.0.1',
576
+ port: 25334,
577
+ proxyPool, // ProxyPool instance
578
+ gatewayClient, // GatewayClient instance (for decoding Java object args)
579
+ });
580
+
581
+ await server.start();
582
+ // …
583
+ await server.stop();
584
+ ```
585
+
586
+ | Property | Type | Description |
587
+ |---|---|---|
588
+ | `host` | `string` | Bound address. |
589
+ | `port` | `number` | Listening port (updated to actual port after `start()` if `port: 0` was given). |
590
+ | `listening` | `boolean` | Whether the server is currently listening. |
591
+ | `proxyPool` | `ProxyPool` | The pool of registered JS proxy objects. |
592
+
593
+ #### ProxyPool
594
+
595
+ Maintains a registry of JS objects that Java can invoke callbacks on.
596
+
597
+ ```js
598
+ const { ProxyPool } = require('js4j');
599
+ const pool = new ProxyPool();
600
+
601
+ const id = pool.register(myObj); // returns an id string
602
+ pool.get(id); // returns the object or null
603
+ pool.has(id); // boolean
604
+ pool.remove(id); // deregisters the object
605
+ ```
606
+
607
+ You do not normally need to interact with `ProxyPool` directly — it is managed internally by `JavaGateway` and `CallbackServer`.
608
+
609
+ ---
610
+
611
+ ### Errors
612
+
613
+ All errors extend `Js4JError`.
614
+
615
+ | Class | Description |
616
+ |---|---|
617
+ | `Js4JError` | Base error class for all js4j errors. |
618
+ | `Js4JJavaError` | A Java-side exception occurred. Contains `javaExceptionMessage` (raw protocol payload) and `javaException` (a `JavaObject` wrapping the `Throwable`). |
619
+ | `Js4JNetworkError` | A network or connection error occurred. |
620
+ | `Js4JAuthenticationError` | Authentication with the GatewayServer failed. |
621
+
622
+ ```js
623
+ const { Js4JJavaError, Js4JNetworkError } = require('js4j');
624
+
625
+ try {
626
+ await gateway.entry_point.riskyMethod();
627
+ } catch (err) {
628
+ if (err instanceof Js4JJavaError) {
629
+ console.error('Java threw:', err.message);
630
+ // Optionally inspect the Java Throwable
631
+ if (err.javaException) {
632
+ const msg = await err.javaException.getMessage();
633
+ console.error('Java message:', msg);
634
+ }
635
+ } else if (err instanceof Js4JNetworkError) {
636
+ console.error('Connection problem:', err.message);
637
+ } else {
638
+ throw err;
639
+ }
640
+ }
641
+ ```
642
+
643
+ ---
644
+
645
+ ## TypeScript
646
+
647
+ Full type definitions are included. No `@types/` package is needed.
648
+
649
+ ```ts
650
+ import {
651
+ JavaGateway,
652
+ ClientServer,
653
+ GatewayParameters,
654
+ CallbackServerParameters,
655
+ JavaObject,
656
+ JavaList,
657
+ JavaMap,
658
+ createJavaProxy,
659
+ Js4JJavaError,
660
+ } from 'js4j';
661
+
662
+ const gateway = new JavaGateway({ port: 25333 });
663
+ await gateway.connect();
664
+
665
+ const list: JavaList = await gateway.entry_point.getList();
666
+ const items: any[] = await list.toArray();
667
+ ```
668
+
669
+ ---
670
+
671
+ ## Running Tests
672
+
673
+ ```bash
674
+ npm test # unit + integration tests (requires Java gateway)
675
+ npm run test:unit # unit tests only (no Java required)
676
+ ```
677
+
678
+ ## Credits
679
+
680
+ Obviously, this module is a port of the project py4j (https://www.py4j.org/). Thank you to them for an awesome package.
681
+
682
+ There is, additionally, another NPM package called node4j (https://www.npmjs.com/package/node4j) which I had been using, but seems to have some errors and limitations, which is why I had this one built.
683
+
684
+ Finally, I did not build this, it was largely build by Claude Code. I did some debugging, but I do want to make my laziness largely known.