File: userguide.rst

package info (click to toggle)
python-jpype 1.6.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,308 kB
  • sloc: python: 19,275; cpp: 18,053; java: 8,638; xml: 1,454; makefile: 155; sh: 37
file content (6472 lines) | stat: -rw-r--r-- 242,143 bytes parent folder | download
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
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
##################
JPype User Guide
##################

.. toctree::
   :maxdepth: 2

.. _introduction:

Introduction
************

.. _introduction_jpype_the_python_to_java_bridge:

JPype the Python to Java bridge
===============================
JPype is a Python module that provides seamless
access to Java libraries from Python. Unlike Jython, which reimplements Python
on the Java Virtual Machine (JVM), JPype bridges Python and Java at the native
level using the Java Native Interface (JNI). This native approach implements CPython
classes for each Java type and Java support for type management while communicating
at the process level.  This approach enables:

- Direct interaction between Python and Java objects.

- Access to the full range of Java libraries and APIs.

- No need to serialize objects when communicating between language.

- Unified primitive types.

- High speed transfers through shared memory between Python and Java 
  for large primitive array types.

JPype is intended for Python developers who need to leverage Java libraries or
Java developers who want to use Python for scripting, debugging, or
visualization.

.. _introduction_why_use_jpype?:

Why Use JPype?
--------------
JPype makes it easy to integrate Python and Java, enabling developers to:

1. Access Java libraries directly from Python code.
2. Debug Java data structures interactively using Python tools.
3. Use Python's flexibility for scientific computing while leveraging Java's
   robustness for enterprise applications.

.. _introduction_prerequisites:

Prerequisites
-------------
Before using JPype, ensure the following:

1. **Python**: JPype requires Python 3.8 or later. Check your Python version by
   running::

       python --version

2. **Java**: JPype requires a Java Runtime Environment (JRE) or Java Development
   Kit (JDK) version 11 or later. Check your Java version by running::

       java -version

3. **Architecture Compatibility**: Ensure the Python interpreter and JVM have
   matching architectures (e.g., both 64-bit or both 32-bit).

.. _introduction_installation:

Installation
------------
JPype can be installed using either `pip` or `conda`.

.. _introduction_using_pip:

Using pip
~~~~~~~~~
To install JPype via `pip`, run::

    pip install JPype1


.. _introduction_using_conda:

Using conda
~~~~~~~~~~~
To install JPype via `conda`, use::

    conda install -c conda-forge jpype1


.. _introduction_verifying_installation:

Verifying Installation
~~~~~~~~~~~~~~~~~~~~~~
After installation, verify that JPype is installed correctly by running::

    import jpype
    print("JPype installed successfully!")


.. _introduction_your_first_jpype_program:

Your First JPype Program
------------------------
Follow these steps to write and run your first JPype program:


.. _introduction_step_1_start_the_jvm:

Step 1: Start the JVM
~~~~~~~~~~~~~~~~~~~~~
JPype requires the JVM to be started before interacting with Java. All calls
to the Java prior to the start of the JVM will fail. Use the
`jpype.startJVM()` function to start the JVM::

    import jpype

    # Start the JVM
    jpype.startJVM(classpath=[])

.. _introduction_step_2_access_java_classes:

Step 2: Access Java Classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~
JPype allows you to import and use Java classes directly. For example, import
Java's `java.lang.String` class::

    from java.lang import String

.. _introduction_step_3_use_java_objects:

Step 3: Use Java Objects
~~~~~~~~~~~~~~~~~~~~~~~~
Create and manipulate Java objects just like Python objects::

    java_string = String("Hello from Java!")
    print(java_string.toUpperCase())  # Output: HELLO FROM JAVA!

.. _introduction_step_4_shut_down_the_jvm:

Step 4: Shut Down the JVM
~~~~~~~~~~~~~~~~~~~~~~~~~
Once the program is complete the JVM will exit when Python does.  All termination
code is handled automatically.


.. _introduction_complete_example:

Complete Example
~~~~~~~~~~~~~~~~
Save the following code in a file named `hello_jpype.py`:

.. code-block:: python

    import jpype
    import jpype.imports

    # Start the JVM
    jpype.startJVM(classpath=["../jar/*","../classes","com.amce-1.0.jar"])

    # Import Java classes
    from java.lang import String

    # Use the Java String class
    java_string = String("Hello from Java!")
    print(java_string.toUpperCase())  # Output: HELLO FROM JAVA!


Run the script using Python::

    python hello_jpype.py

You should see the output::

    HELLO FROM JAVA!


.. _introduction_next_steps:

Next Steps
----------
Once you've successfully set up JPype, explore the following topics:

1. **Accessing Java Libraries**: Learn how to use JPype to interact with third-
   party Java libraries.
2. **Working with Java Collections**: Discover how JPype integrates Java
   collections with Python's `collections` module.
3. **Implementing Java Interfaces in Python**: Use JPype's proxy functionality
   to implement Java interfaces in Python.
4. **Debugging Java Code**: Use JPype as an interactive shell for debugging
   Java programs.


.. _introduction_summary_of_jpype:

Summary of JPype
----------------
JPype bridges Python and Java, enabling seamless integration between the two
languages. With JPype, you can access Java libraries, implement Java
interfaces, and debug Java code—all from the comfort of Python. Happy coding!



.. _introduction_jpype_use_cases:

JPype Use Cases
===============

Here are three typical reasons to use JPype.

- Access to a Java library from a Python program (Python oriented)
- Visualization of Java data structures via Matplotlib (Java oriented)
- Interactive Java and Python development including scientific and mathematical
  programming using Python as a Java shell with Spyder or Jupyter notebooks.

Let's explore each of these options.


.. _introduction_case_1_access_to_a_java_library:

Case 1: Access to a Java library
--------------------------------

Suppose you are a hard core Python programmer.  You can easily use lambdas,
threading, dictionary hacking, monkey patching, been there, done that.  You are
hard at work on your latest project but you just need to pip in the database
driver for your customers database and you can call it a night.  Unfortunately,
it appears that your customers database will not connect to the Python database
API.  The whole thing is custom and the customer isn't going to supply you with
a Python version.  They did send you a Java driver for the database but fat
lot of good that will do for you.

Stumbling through the internet you find a module that says it can natively
load Java packages as Python modules.  Well, it's worth a shot...

So first thing the guide says is that you need to install Java and set up
a ``JAVA_HOME`` environment variable pointing to the JRE.  Then start the
JVM with classpath pointed to customers jar file. The customer sent over
an example in Java so you just have to port it into Python.

.. code-block:: java

  package com.paying.customer;

  import com.paying.customer.DataBase

  public class MyExample {
     public void main(String[] args) {
       Database db = new Database("our_records");
       try (DatabaseConnection c = db.connect())
       {
          c.runQuery();
          while (c.hasRecords())
          {
            Record record = db.nextRecord();
            ...
          }
       }
    }
  }


It does not look too horrible to translate.  You just need to look past all
those pointless type declarations and meaningless braces.  Once you do, you
can glue this into Python and get back to what you really love, like performing
dictionary comprehensions on multiple keys.

You glance over the JPype quick start guide.  It has a few useful patterns...
set the class path, start the JVM, remove all the type declarations, and you are done.

.. code-block:: python

   # Boiler plate stuff to start the module
   import jpype
   import jpype.imports
   from jpype.types import *

   # Launch the JVM
   jpype.startJVM(classpath=['jars/database.jar'])

   # import the Java modules
   from com.paying.customer import DataBase

   # Copy in the patterns from the guide to replace the example code
   db = Database("our_records")
   with db.connect() as c:
       c.runQuery()
       while c.hasRecords():
           record = db.nextRecord()
           ...

Launch it in the interactive window.  You can get back to programming in Python
once you get a good night sleep.




.. _introduction_case_2_visualization_of_java_structures:

Case 2: Visualization of Java structures
----------------------------------------

Suppose you are a hard core Java programmer.  Weakly typed languages are for
wimps, if it isn't garbage collected it is garbage.  Unfortunately your latest
project has suffered a nasty data structure problem in one of the threads.  You
managed to capture the data structure in a serialized form but if you could just
make graph and call a few functions this would be so much easier.  But  the
interactive Java shell that you are using doesn't really have much in the way of
visualization and you don't have time to write a whole graphing applet just to
display this dataset.

So poking around on the internet you find that Python has exactly the
visualization that you need for the problem, but it only runs in CPython.  So
in order to visualize the structure, you need to get it into Python, extract
the data structures and, send it to the plotting routine.

You install conda, follow the install instructions to connect to conda-forge,
pull JPype1, and launch the first Python interactive environment that appear to
produce a plot.

You get the shell open and paste in the boilerplate start commands, and load
in your serialized object.

.. code-block:: python

   import jpype
   import jpype.imports

   jpype.startJVM(classpath = ['jars/*', 'test/classes'])

   from java.nio.file import Files, Paths
   from java.io import ObjectInputStream

   with Files.newInputStream(Paths.get("myobject.ser")) as stream:
       ois = ObjectInputStream(stream)
       obj = ois.readObject()

   print(obj)  # prints org.bigstuff.MyObject@7382f612

It appears that the structure is loaded.  The problematic structure requires you
call the getData method with the correct index.

.. code-block:: python

   d = obj.getData(1)

   > TypeError: No matching overloads found for org.bigstuff.MyObject.getData(int),
   > options are:
          public double[] org.bigstuff.MyObject.getData(double)
          public double[] org.bigstuff.MyObject.getData(int)

Looks like you are going to have to pick the right overload as it can't
figure out which overload to use.  Darn weakly typed language, how to get
the right type in so that you can plot the right data.  It says that
you can use the casting operators.

.. code-block:: python

   from jpype.types import *
   d = obj.getData(JInt(1))
   print(type(d))  # prints double[]

Great. Now you just need to figure out how to convert from a Java array into
something our visualization code can deal with.  As nothing indicates that
you need to convert the array, you just copy out of the visualization tool
example and watch what happens.

.. code-block:: python

   import matplotlib.pyplot as plt
   plt.plot(d)
   plt.show()

A graph appears on the screen.  Meaning that NumPy has not issue dealing with
Java arrays.  It looks like ever 4th element in the array is zero.
It must be the PR the new guy put in.  And off you go back to the wonderful
world of Java back to the safety of curly braces and semicolons.


.. _introduction_case_3_interactive_java:

Case 3: Interactive Java
------------------------

Suppose you are a laboratory intern running experiments at Hawkins National
Laboratory.  (For the purpose of this exercise we will ignore the fact that
Hawkins was shut down in 1984 and Java was created in 1995).  You have the test
subject strapped in and you just need to start the experiment.  So you pull up
Jupyter notebook your boss gave you and run through the cells.  You need to
add some heart wave monitor to the list of graphed results.

The relevant section of the API for the Experiment appears to be

.. code-block:: java

  package gov.hnl.experiment;

  public interface Monitor {
     public void onMeasurement(Measurement measurement);
  }

  public interface Measurement {
     public double getTime();
     public double getHeartRate();
     public double getBrainActivity();
     public double getDrugFlowRate();
     public boolean isNoseBleeding();
  }

  public class Experiment {
     public void addCondition(Instant t, Condition c);
     public void addMoniter(Monitor m);
     public void run();
  }

The notebook already has all the test conditions for the experiment set up
and the JVM is started, so you just need to implement the monitor.

Based on the previous examples, you start by defining a monitor class

.. code-block:: python

  from jpype import JImplements, JOverride
  from gov.hnl.experiment import Monitor

  @JImplements(Monitor)
  class HeartMonitor:
      def __init__(self):
          self.readings = []
      @JOverride
      def onMeasurement(self, measurement):
          self.readings.append([measurement.getTime(), measurement.getHeartRate()])
      def getResults(self):
          return np.array(self.readings)

There is a bit to unpack here.  You have implemented a Java class from within Python.
The Java implementation is simply an ordinary Python class which has be
decorated with ``@JImplements`` and ``@JOverride``.  When you forgot to place
the ``@JOverride``, it gave you the response::

  NotImplementedError: Interface 'gov.hnl.experiment.Monitor' requires
  method 'onMeasurement' to be implemented.

But once you added the ``@JOverride``, it worked properly.  The subject appears
to be getting impatient so you hurry up and set up a short run to make sure it
is working.

.. code-block:: python

  hm = HeartMonitor()
  experiment.addMonitor(hm)
  experiment.run()
  readings = hm.getResults()
  plt.plot(readings[:,0], readings[:,1)
  plt.show()

To your surprise, it says unable to find method addMonitor with an error message::

  AttributeError: 'gov.hnl.experiment.Experiment' object has no attribute 'addMonitor'


You open the cell and type ``experiment.add<TAB>``.  The line completes with
``experiment.addMoniter``.  Whoops, looks like there is typo in the interface.
You make a quick correction and see a nice plot of the last 30 seconds pop up
in a window.  Job well done, so you set the runtime back to one hour.  Looks
like you still have time to make the intern woodlands hike and forest picnic.
Though you wonder if maybe next year you should sign up for another laboratory.
Maybe next year, you will try to sign up for those orbital lasers the President
was talking about back in March.  That sounds like real fun.

(This advanced demonstration utilized the concept of Proxies_ and
`Code completion`_)


.. _introduction_the_jpype_philosophy:

The JPype Philosophy
=====================

JPype is designed to provide seamless integration between Python and Java,
allowing developers to use Java libraries and features as naturally as possible
within Python. To achieve this, JPype adheres to several core design
principles:

1. **Make Java appear Pythonic**:

   - JPype strives to make Java concepts feel familiar to Python programmers.
     This involves adapting Java syntax and behaviors to align with Python's
     conventions wherever possible.
   - For example, Java methods are mapped to Python methods, and Java
     collections are customized to behave like Python collections.

2. **Make Python appear like Java**:

   - JPype ensures that Java developers can work with Python without a steep
     learning curve. This includes presenting Python constructs in a way that
     resembles Java syntax and behavior.
   - For instance, Python classes can implement Java interfaces, and Java
     objects can be manipulated using Python's object-oriented features.

3. **Expose all of Java to Python**:

   - JPype aims to provide access to the entirety of the Java ecosystem,
     including libraries, packages, and features. The goal is to act as a
     bridge, enabling unrestricted interaction between the two languages.
   - Whether it's Java threading, reflection, or advanced APIs, JPype ensures
     that Python developers can leverage Java's full capabilities.

4. **Keep the design simple**:

   - Mixing two languages is inherently complex, so JPype minimizes additional
     complexity by maintaining a simple and consistent design.
   - For example, all Java array types originate from the `JArray` factory,
     ensuring a unified approach to handling arrays.

5. **Favor clarity over performance**:

   - While JPype optimizes critical paths for performance, clarity is
     prioritized to ensure long-term maintainability and usability.
   - For example, JPype avoids premature optimization that could complicate the
     codebase or introduce unnecessary constraints.

6. **Introduce familiar methods**:

   - When new methods are added, JPype ensures they align with established
     conventions in both Python and Java.
   - For example, Python's ``memoryview`` is used to access Java-backed memory,
     while Java's ``Stream.of`` inspired the ``JArray.of`` method for converting
     NumPy arrays to Java arrays.

7. **Provide obvious solutions for both Python and Java programmers**:

   - JPype recognizes that "obviousness" varies between Python and Java
     developers. Therefore, it provides solutions that feel natural to both
     audiences.

   - For example, Python programmers can use list comprehensions with Java
     collections, while Java programmers can use familiar methods like
     ``contains`` or ``hashCode``.


**Balancing Two Worlds**

JPype bridges two distinct programming paradigms: Python's dynamic and flexible
nature versus Java's strongly-typed and structured approach. This balance
requires careful mapping of concepts between the two languages:

- **Types**:

  - Python's weak typing allows variables to change types dynamically, while
    Java's strong typing enforces strict type declarations. JPype accommodates
    this difference by providing type factories (``JClass``, ``JArray``) and casting
    operators (``@``).

- **Inheritance**:

  - Java supports single inheritance with interfaces, while Python allows
    multiple inheritance. JPype maps Java interfaces to Python classes using
    decorators (``@JImplements``) to ensure compatibility.

- **Collections**:

  - Java collections (``List``, ``Map``, ``Set``) are customized to behave like
    Python collections, enabling intuitive interaction for Python developers.

- **Error Handling**:

  - Java exceptions are mapped to Python exceptions, allowing developers to
    handle errors seamlessly across both languages.


**Philosophy in Practice**

JPype's design philosophy ensures a small footprint while offering high levels
of integration between Python and Java. Developers can use JPype to:

- Access Java libraries for tasks that Python lacks native support for (e.g.,
  advanced threading, enterprise APIs).
- Use Python's interactive and visualization capabilities to debug or analyze
  Java data structures.
- Combine Python's flexibility with Java's robustness for scientific computing,
  machine learning, and enterprise applications.

By adhering to these principles, JPype provides a powerful yet accessible tool
for bridging the Python and Java ecosystems.


.. _introduction_languages_other_than_java:

Languages Other Than Java
=========================

Although JPype is primarily designed to bridge Python with Java, its
capabilities extend to other JVM-based languages such as Kotlin, Scala, Groovy,
and Clojure. These languages share the same underlying Java Virtual Machine
(JVM) infrastructure, allowing JPype to interact with them seamlessly. However,
each language introduces unique features and paradigms that may require
additional considerations when integrating with Python.


.. _introduction_supported_jvmbased_languages:

Supported JVM-Based Languages
-----------------------------

1. **Kotlin**:

   - Kotlin is a modern JVM-based language that emphasizes conciseness and
     safety. JPype can interact with Kotlin libraries and classes just as it
     does with Java.

   - Kotlin's null safety and extension functions are fully compatible with
     JPype, though developers may need to handle Kotlin's nullable types
     explicitly when working in Python.

   - Example: Using Kotlin's ``List`` class in Python via JPype.

.. code-block:: python

      from kotlin.collections import List
      my_list = List.of("apple", "orange", "banana")
      print(my_list.size())  # Access Kotlin methods


2. **Scala**:

   - Scala combines object-oriented and functional programming paradigms,
     making it a popular choice for big data and distributed systems.

   - JPype can interact with Scala libraries, including those built on
     frameworks like Akka or Spark.

   - Scala's collections and functional constructs (e.g., `map`, `flatMap`) can
     be accessed directly from Python, though some functional idioms may
     require adaptation.

.. code-block:: python

      from scala.collection.mutable import ArrayBuffer
      buffer = ArrayBuffer()
      buffer.append(1)
      buffer.append(2)
      print(buffer.mkString(", "))  # Outputs: "1, 2"


3. **Groovy**:

   - Groovy is a dynamic language for the JVM, often used for scripting and
     lightweight application development.

   - JPype can interact with Groovy scripts and libraries, enabling Python
     developers to leverage Groovy's concise syntax and dynamic capabilities.

   - Groovy's dynamic typing aligns well with Python, but accessing from
     within JPype may cause difficulties.

.. code-block:: python

      from groovy.util import Eval
      result = Eval.me("3 + 5")
      print(result)  # Outputs: 8


4. **Clojure**:

   - Clojure is a functional programming language that runs on the JVM. Its
     emphasis on immutability and concurrency makes it ideal for certain types
     of applications.

   - JPype can interact with Clojure libraries, though developers may need to
     adapt to Clojure's Lisp-like syntax and functional paradigms.

.. code-block:: python

      from clojure.lang import PersistentVector
      vector = PersistentVector.create([1, 2, 3])
      print(vector.nth(1))  # Access elements using Clojure methods


.. _introduction_using_jpype_with_other_jvm_languages:

Using JPype with Other JVM Languages
------------------------------------

JPype can be used with JVM-based languages, but the following considerations
apply:

1. **Language-Specific Features**:

   - Each language introduces unique features (e.g., Kotlin's null safety,
     Scala's functional constructs, Groovy's dynamic typing). These may require
     adaptation when working with Python.

2. **Interoperability**:

   - JPype relies on the JVM's native interoperability mechanisms, ensuring
     seamless interaction with JVM-based languages. However, developers should
     be aware of differences in naming conventions, type systems, and runtime
     behavior.

3. **Testing and Integration**:

   - To fully support a JVM-based language, developers should set up a test
     bench to exercise its features, write language-specific quick-start
     guides, and ensure compatibility with JPype's existing API.


.. _introduction_expanding_jpype_for_other_jvm_languages:

Expanding JPype for Other JVM Languages
---------------------------------------

If you wish to extend JPype's capabilities for a specific JVM-based language,
the following steps are recommended:

1. **Create a Test Bench**:

   - Set up a test environment for your language under JPype's test directory.
     Use Ivy or Maven to pull in the required JAR files and exercise the
     language's unique features.

2. **Write a Language-Specific Guide**:

   - Document how your language interacts with JPype, highlighting differences
     from Java and providing examples for common use cases.

3. **Set Up a Test Harness**:

   - Build a test harness to verify compatibility for each language feature.
     Place the setup script (e.g., `test_kotlin`, `test_scala`) alongside
     JPype's existing tests.

.. _introduction_conclusion_on_languages:

Conclusion on Languages
-----------------------

JPype's ability to interact with JVM-based languages opens up exciting
possibilities for Python developers. Whether you're working with Kotlin's
modern syntax, Scala's functional paradigms, Groovy's dynamic scripting, or
Clojure's immutability, JPype provides a powerful bridge to leverage the
strengths of these languages within Python. By following the steps outlined
above, you can ensure smooth integration and expand JPype's capabilities for
your specific needs.


.. _introduction_alternatives:

Alternatives
============
JPype is not the only Python module of its kind that acts as a bridge to Java.
Depending on your programming requirements, one of the alternatives may be a
better fit. Specifically, JPype is designed for clarity and high levels of
integration between the Python and Java virtual machines. As such, it makes use
of JNI and inherits all the benefits and limitations that JNI imposes. With
JPype, both virtual machines run in the same process, sharing the same memory
space and threads. JPype can intermingle Python and Java threads and exchange
memory quickly. However, the JVM cannot be restarted within the same process,
and if Python crashes, Java will also terminate since they share the same
process.

Below is a comparison of JPype with other Python-to-Java bridging technologies.
These alternatives may suit different use cases depending on the level of
integration, performance requirements, or ease of use.

.. _introduction_py4j:

Py4J
---------------------------
`Py4J <https://py4j.org/>`_ is a Python library that enables communication
with a JVM through a remote tunnel. Unlike JPype, which embeds the JVM directly
into the Python process using JNI, Py4J operates the JVM as a separate process,
allowing Python and Java to run independently. This separation introduces
several unique advantages:

1. **Cross-Architecture Compatibility**: Py4J allows Python and Java to run on
different architectures or platforms. For example, you can run Python on a
64-bit architecture while connecting to a 32-bit JVM, or even run Python and
Java on entirely different machines. This flexibility is particularly useful
for distributed systems or environments where the Python and Java components
have different hardware or software requirements.

2. **Restartable Java Sessions**: Because Py4J operates the JVM as a separate
process, it is possible to stop and restart the JVM without restarting the
Python process. This is a feature frequently requested by JPype users but is
not feasible with JPype due to its use of JNI, which tightly couples the Python
and Java memory spaces. Py4J's ability to restart the JVM makes it suitable for
applications requiring dynamic lifecycle management of the Java environment.

3. **Memory Isolation**: Since Python and Java run in separate processes, Py4J
provides complete memory isolation between the two environments. This ensures
that a crash in the JVM does not affect the Python process and vice versa. Such
isolation can be critical for applications requiring high reliability and fault
tolerance.

4. **RPC-Style Communication**: Py4J operates more like a remote procedure call
(RPC) framework, where Python sends commands to the JVM and receives responses.
While this approach is less integrated than JPype's direct JNI-based
interaction, it is intended for applications where tight coupling between
Python and Java is not required.

Despite these advantages, Py4J has some limitations compared to JPype:

- **Performance**: The remote communication introduces a transfer penalty when
  moving data between Python and Java, making Py4J less suitable for
  applications requiring high-performance data exchange.

- **Integration**: Py4J does not provide the seamless integration of Java
  objects into Python syntax that JPype offers. For example, Java collections
  and arrays do not behave like native Python objects.

Py4J is a good choice for applications requiring cross-architecture
compatibility, restartable JVM sessions, or memory isolation between Python and
Java. However, for applications needing tight integration and high-performance
data exchange, JPype may be a better fit.


.. _introduction_jep:

Jep
-------
`Jep <https://github.com/ninia/jep>`_ stands for Java embedded Python. It is
designed to allow Java to access Python as a sub-interpreter. The syntax for
accessing Java resources from within the embedded Python is similar to JPype,
with support for imports.  However, Jep has limitations due to Python's
sub-interpreter model, which restricts the use of many Python modules.
Additionally, Jep's documentation is sparse, making it difficult to assess its
full capabilities without experimentation. Jep is best suited for applications
where Java needs to embed Python for scripting purposes.

.. _introduction_pyjnius:

PyJnius
-------
PyJnius <https://github.com/kivy/pyjnius>_ is another Python-to-Java bridge.
Its syntax is somewhat similar to JPype, allowing classes to be loaded and
accessed with Java-native syntax. PyJnius supports customization of Java
classes to make them appear more Pythonic. However, PyJnius lacks support for
primitive arrays, requiring Python lists to be converted manually whenever an
array is passed as an argument or return value. This limitation makes PyJnius
less suitable for scientific computing or applications requiring efficient
array manipulation. PyJnius is actively developed and is particularly focused
on Android development, making it a strong choice for mobile applications
requiring Python-Java integration.

.. _introduction_jython:

Jython
------
Jython <https://www.jython.org/>_ is a reimplementation of Python in Java. It
allows Python code to run directly on the JVM, providing seamless access to
Java libraries. Jython, while limited to Python 2, played a significant role in
bridging Python and Java in earlier development eras. It may still be useful for
legacy systems or environments where Python 2 compatibility is required. Its
development has largely stalled, and it lacks support for popular Python
libraries like NumPy and pandas, making it unsuitable for modern applications.

.. _introduction_javabridge:

Javabridge
-----------
`Javabridge <https://github.com/CellProfiler/python-javabridge/>`_  provides
direct low-level JNI control from Python. Its integration
level is low, offering only the JNI API to Python rather than attempting to
wrap Java in a Python-friendly interface. While Javabridge can be useful for
advanced users familiar with JNI, it requires significant expertise to use
effectively. Javabridge is best suited for applications needing fine-grained
control over JNI interactions.

.. _introduction_jcc:

JCC
---
`JCC <https://lucene.apache.org/pylucene/jcc/>`_ is a C++ code generator that
produces a C++ object interface wrapping a Java library via JNI. JCC also
generates C++ wrappers conforming to Python's C type system, making instances
of Java classes directly available to a Python interpreter. JCC is actively
maintained as part of PyLucene and is useful for exposing specific Java
libraries to Python rather than providing general Java access. It is best
suited for applications requiring tight integration with libraries like Apache
Lucene.  It is best suited for applications requiring tight integration with
specific Java libraries.

.. _introduction_about_this_guide:

About this Guide
================

The JPype User Guide is designed for two primary audiences:

1. **Python Programmers**: Those who are proficient in Python and wish to
leverage Java libraries or integrate Java functionality into their Python
projects.

2. **Java Programmers**: Those who are experienced in Java and want
to use Python as a development tool for Java, particularly for tasks like
visualization, debugging, or scripting.


This guide aims to bridge the gap between these two languages by comparing and
contrasting their differences, providing examples that illustrate how to
translate concepts from one language to the other. It assumes that readers are
proficient in at least one of the two languages. If you lack a strong
background in either Python or Java, you may need to consult tutorials or
introductory materials for the respective language before proceeding.

Key Features of the Guide
-------------------------

- **No JNI Knowledge Required**: JPype abstracts away the complexities of the
  Java Native Interface (JNI). Users do not need to understand JNI concepts or
  its naming conventions to use JPype effectively. In fact, relying on JNI
  knowledge may lead to incorrect assumptions about the JPype API. Where JNI
  imposes limitations, the guide explains the consequences in practical
  programming terms.

- **Python 3 Compatibility**: JPype supports only Python 3. All examples in
  this guide use Python 3 syntax and assume familiarity with Python's new-style
  object model. If you're using an older version of Python, you will need to
  upgrade to Python 3 to use JPype.

- **Java Naming Conventions**: JPype adheres to Java's naming conventions for
  methods and fields to ensure consistency and avoid potential name collisions.
  While this may differ from Python's conventions, it is a deliberate choice to
  maintain compatibility with Java libraries and APIs.

By following this guide, you’ll learn how to use JPype to seamlessly integrate
Python and Java, unlocking the strengths of both languages in your projects.


.. _introduction_getting_jpype_started:

Getting JPype started
---------------------

This document holds numerous JPype examples.  For the purposes of clarity
the module is assumed to have been started with the following command

.. code-block:: python

  # Import the module
  import jpype

  # Allow Java modules to be imported
  import jpype.imports

  # Import all standard Java types into the global scope
  from jpype.types import *

  # Import each of the decorators into the global scope
  from jpype import JImplements, JOverride, JImplementationFor

  # Start JVM with Java types on return
  jpype.startJVM()

  # Import default Java packages
  import java.lang
  import java.util

This is not the only style used by JPype users.  Some people feel it is
best to limit the number for symbols in the global scope and instead
start with a minimalistic approach.

.. code-block:: python

  import jpype as jp                 # Import the module
  jp.startJVM()                      # Start the module

Either style is usable and we do not wish to force any particular style on the
user.  But as the extra ``jp.`` tends to just clutter up the space and implies
that JPype should always be used as a namespace due to namespace conflicts, we
have favored the global import style.  JPype only exposes 40 symbols total
including a few deprecated functions and classes. The 13 most commonly used
Java types are wrapped in a special module ``jpype.types`` which can be used to
import all for the needed factories and types with a single command without
worrying about importing potentially problematic symbols.

We will detail the starting process more later in the guide.  See
`Starting the JVM`_.


.. _introduction_jpype_concepts:

JPype Concepts
==============

At its heart, JPype is about providing a bridge to use Java within Python.
Depending on your perspective, this can either be a means of accessing Java
libraries from within Python or a way to use Java with Python syntax for
interactivity and visualization. JPype aims to provide access to the entirety
of the Java language from Python, mapping Java concepts to their closest Python
equivalents wherever possible.

Python and Java share many common concepts, such as types, classes, objects,
functions, methods, and members. However, there are significant differences
between the two languages. For example, Python lacks features like casting,
type declarations, and method overloading, which are central to Java's strongly
typed paradigm. JPype introduces these concepts into Python syntax while
striving to maintain Pythonic usability.

This section breaks down JPype's core concepts into nine distinct categories.
These categories define how Java elements are mapped into Python and how they
can be used effectively.


.. _introduction_core_concepts:

Core Concepts
-------------

1. **Type Factories**:

   - Type factories allow you to declare specific Java types in Python. These
     factories produce wrapper classes for Java types.

   - Examples include `JClass` for Java classes and `JArray` for Java arrays.

   - Factories also exist for implementing Java classes from within Python
     using proxies (e.g., `JProxy`).

2. **Meta Classes**:

   - Meta classes describe properties of Java classes, such as whether a class
     is an interface.

   - Example: `JInterface` can be used to check if a Java class is an interface.

3. **Base Classes**:

   - JPype provides base classes for common Java types, such as `Object`,
     `String`, and `Exception`.

   - These classes can be used for convenience, such as catching all Java
     exceptions with `JException`.

   - Example: `java.lang.Throwable` can be caught using `JException`.

4. **Wrapper Classes**:

   - Wrapper classes correspond to individual Java classes and are dynamically
     created by JPype. These wrappers encapsulate Java objects and provide a Pythonic
     interface for interacting with them. Depending on the context, a wrapper may 
     contain a Java reference, such as a class instance, primitive array, or boxed type
     or a Java proxy which implements dynamically implements a Java interface.

   - Wrappers are designed to make Java objects behave like native Python objects, 
     enabling seamless integration between Python and Java. These wrappers provide
     a Pythonic interface to Java objects, making them behave like native Python
     objects while retaining their Java functionality.

   - They allow access to static variables, static methods, constructors, and
     casting.

   - Example: `java.lang.Object`, `java.lang.String`.

5. **Object Instances**:

   - These are Java objects created or accessed within Python. They behave like
     Python objects, with Java fields mapped to Python attributes and Java
     methods mapped to Python methods.

   - Example: A Java `String` object can be accessed and manipulated like a
     Python string.

6. **Primitive Types**:

   - JPype maps Java's primitive types (e.g., `boolean`, `int`, `float`) into
     Python classes.

   - Example: `JInt`, `JFloat`, `JBoolean`.

7. **Decorators**:

   - JPype provides decorators to augment Python classes and methods with
     Java-specific functionality.

   - Examples include `@JImplements` for implementing Java interfaces and
     `@JOverride` for overriding Java methods.

8. **Mapping Java Syntax to Python**:

   - JPype maps Java syntax to Python wherever possible. For example:

     - Java's `try`, `throw`, and `catch` are mapped to Python's `try`, `raise`,
       and `except`.

     - Java's `synchronized` keyword is mapped to Python's `with` statement
       using `jpype.synchronized`.

9. **JVM Control Functions**:

   - JPype provides functions for controlling the JVM, such as starting and
     shutting it down.

   - Examples: `jpype.startJVM()` and `jpype.shutdownJVM()`.


.. _introduction_additional_details:

Additional Details
------------------

- **Name Mangling**:

  - JPype handles naming conflicts between Java and Python by appending an
    underscore (`_`) to conflicting names.

  - Example: A Java method named `with` will appear as `with_` in Python.

  - For details see `Name Mangling`_.

- **Lifetime Management**:

  - Java objects remain alive as long as their corresponding Python handles
    exist. Once the Python handle is disposed, the Java object is eligible for
    garbage collection.

By understanding these core concepts, you can effectively use JPype to
integrate Python and Java, leveraging the strengths of both languages.


.. _introduction_best_practices:

Best Practices on JVM Startup
-----------------------------

Starting the Java Virtual Machine (JVM) correctly is critical for ensuring the
smooth operation of JPype-based applications. A well-configured JVM startup
process minimizes runtime issues, optimizes performance, and ensures
compatibility with the required Java libraries. This section provides a
detailed explanation of best practices to guide developers in setting up the
JVM effectively.

1. Start the JVM Early
   The JVM should always be started early in the application lifecycle. By
   initializing the JVM at the beginning of your program, you can avoid issues
   related to delayed imports or incomplete initialization. This approach
   ensures that all Java classes and libraries required by your application
   are properly loaded and accessible throughout the program's execution.

2. Configure the Classpath Explicitly
   Classpath configuration is another essential consideration. The
   ``classpath`` specifies the location of Java classes and JAR files that the
   JVM needs to load. For optimal results, explicitly define the ``classpath``
   when starting the JVM. This can be done using the ``classpath`` argument in
   the ``startJVM()`` function or dynamically through the ``addClassPath()``
   method prior to JVM startup. Explicit configuration prevents errors caused
   by missing dependencies and ensures that the correct versions of libraries
   are loaded.

3. Disable Automatic String Conversion
   When dealing with large-scale data transfers or computationally intensive
   operations, it is advisable to disable automatic string conversion by
   setting the ``convertStrings`` argument to ``False``. This prevents
   unnecessary overhead caused by automatic conversion of Java strings to
   Python strings, allowing developers to retain control over string handling
   and improve performance. While enabling automatic string conversion may
   seem convenient, it is considered a legacy option and should be avoided in
   modern applications.

4. Avoid Restarting the JVM
   It is important to note that the JVM cannot be restarted once it has been
   shut down. Therefore, design your application to start the JVM once and
   keep it running for the program's lifetime. Attempting to restart the JVM
   will result in errors due to lingering references and resource conflicts.
   This limitation underscores the importance of careful planning when
   initializing the JVM.

.. _optimize_data_transfers:

5. Optimize Data Transfers
   When Python and Java need to exchange large amounts of data, such as arrays
   or complex structures, the efficiency of these transfers can significantly
   impact application performance. Without optimization, frequent back-and-
   forth calls between Python and Java can create bottlenecks, especially in
   computationally intensive applications like scientific computing or machine
   learning.

   To ensure smooth data exchange, consider the following strategies:

   1. **Use NumPy Arrays**: NumPy arrays integrate seamlessly with JPype and
      allow fast, memory-efficient data transfers to Java. For example, a
      NumPy array can be mapped directly to a Java primitive array, enabling
      high-speed operations without unnecessary copying.

   2. **Leverage Java Buffers**: Java's `nio` buffers provide a mechanism for
      shared memory between Python and Java. These buffers are particularly
      useful for large datasets or memory-mapped files, as they eliminate the
      overhead of repeated conversions and allow both languages to operate on
      the same memory space.

   3. **Cache Java Objects**: If a Java object is used repeatedly in Python,
      consider caching it to reduce the frequency of cross-language calls.
      This avoids redundant conversions and improves overall runtime
      efficiency.

   4. **Validate Data Structures**: Ensure that arrays or collections being
      transferred are rectangular and compatible with the expected Java types.
      For example, jagged arrays or incompatible data types can lead to errors
      or performance degradation.

   By implementing these strategies, you can optimize the interaction between
   Python and Java, ensuring that your application performs efficiently even
   when handling large-scale data or computationally intensive tasks.

6. Handle Exceptions Properly
   Exception handling is another key aspect of JVM startup. Always catch Java
   exceptions using ``jpype.JException`` or specific Java exception classes to
   ensure robust error handling. When debugging issues, the ``stacktrace()``
   method can provide detailed information about Java exceptions, helping
   developers identify and resolve problems effectively.

7. Document Your Setup
   Finally, document the JVM startup process and configuration settings
   clearly within your codebase. This practice not only aids in debugging but
   also ensures that other developers working on the project can understand
   and replicate the setup. By adhering to these best practices, you can
   maximize the reliability, performance, and maintainability of your
   JPype-based applications.

By adhering to these best practices, you can maximize the performance,
reliability, and maintainability of your JPype-based applications.


.. _jpype_types:

JPype Types
***********

Both Java and Python have a concept of a type.  Every variable refers to an
object which has a defined type.  A type defines the data that the variable is
currently holding and how that variable can be used.  In this chapter we will
learn how Java and Python types relate to one another, how to create import
types from Java, and how to use types to create Java objects.


.. _jpype_types_stay_strong_in_a_weak_language:

Stay strong in a weak language
==============================

Before we get into the details of the types that JPype provides, we first need
to contrast some of the fundamental language differences between Java and
Python.  Python is inherently a weakly typed language.  Any variable can take
any type and the type of a particular variable can change over the
lifetime of a program.  Types themselves can be mutable as you can patch an
existing type to add new behaviors.  Python methods can in principle take any
type of object as an argument, however if the interface is limited it will produce
a TypeError to indicate a particular argument requires a specific type.  Python
objects and classes are open.  Each class and object is basically a dictionary
storing a set of key-value pairs.  Types implemented in native C are often more
closed and thus can't have their method dictionaries or data members altered
arbitrarily.  But subject to a few restrictions based implementation, it is
pretty much the wild west.

In contrast, Java is a strongly typed language.  Each variable can only take
a value of the specified class or a class that derives from the specified
class.  Each Java method takes only a specific number and type of arguments.
The type and number are all checked at compile type to ensure there is
little possibility of error.  As each method requires a specific number and type
of arguments, a method can be overloaded by having two different
implementations which take a different list of types sharing the same method
name. A primitive variable can never hold an object and it can only be converted
to or from other primitive types unless it is specifically cast to that type.
Java objects and classes are completely closed.  The methods and fields for a
particular class and object are defined entirely at compile time.  Though it is
possible create classes with a dictionary allowing expansion, this is not the
Java norm and no standard mechanism exists.

Thus we need to introduce a few Java terms to the Python vocabulary.  These are
"conversion" and "cast".


.. _jpype_types_java_conversions:

Java conversions
----------------

A conversion is a permitted change from an object of one type to another.
Conversions have three different degrees.  These are: exact, derived, implicit,
and explicit.

Exact conversions are those in which the type of an object is identical.  In
Java each class has only one definition thus there is no need for an exact
conversion.  But when dealing with Python we have objects that are effectively
identical for which exact conversion rules apply.  For example, a Java string
and a Python string both bind equally well to a method which requires a string,
thus this is an exact conversion for the purposes of bind types.

The next level of conversion is derived.  A derived class is one which is a
descends from a required type.  It is better that implicit but worse than
exact.  If all of the types in a method match are exact or derived then it will
override a method in which one argument is implicit.

The next level of conversion is implicit.  An implicit conversion is one that
Java would perform automatically.  Java defines a number of other conversions
such as converting a primitive to a boxed type or from a boxed type back to a
primitive as implicit conversions.  Python conversions defined by the user are
also considered to be implicit.

Of course not every cast is safe to perform.  For example, converting an object
whose type is currently viewed as a base type to a derived type is not
performed automatically nor is converting from one boxed type to another.  For
those operations the conversion must be explicitly requested, hence these are
explicit conversions.   In Java, a cast is requested by placing the type name
in parentheses in front of the object to be cast.  Python does not directly
support Java casting syntax. To request an explicit conversion an object must
be "cast" using a cast operator @.   Overloaded methods with an explicit
argument will not be matched.  After applying an explicit cast, the match
quality can improve to exact or derived depending on the cast type.

Not every conversion is possible between Java types.  Types that cannot be
converted are considerer to be conversion type "none".

Details on how method overloads are resolved are given in `Method Resolution`_.
Details on the standard conversions provided by JPype are given in the section
`Type Matching`_.

.. _cast:

Java casting
------------

To access a casting operation we use the casting ``JObject`` wrapper.
For example, ``JObject(object, Type)`` would produce a copy with specificed type.
The first argument is the object to convert and
the second is the type to cast to.  The second argument should always be a Java
type specified using a class wrapper, a Java class instance, or a string.
Casting will also add a hidden class argument to the resulting object such that
it is treated as the cast type for the duration of that variable lifespan.
Therefore, a variable create by casting is stuck as that type and cannot revert
back to its original for the purposes of method resolution.

The object construction and casting are sometimes a bit blurry.  For example,
when one casts a sequence to a Java list, we will end up constructing a new
Java list that contains the elements of the original Python sequence.  In
general JPype constructors only provide access the Java constructor methods
that are defined in the Java documentation.  Casting on the other hand is
entirely the domain of whatever JPype has defined including user defined casts.

As ``JObject`` syntax is long and does not look much like Java syntax, the
Python matmul operator is overloaded on JPype types such that one can use the
``@`` operator to cast to a specific Java type.   In Java, one would write
``(Type)object`` to cast the variable ``object`` to ``Type``.  In Python, this
would be written as ``Type@object``.   This can also be applied to array types
``JLong[:]@[1,2,3]``, collection types ``Iterable@[1,2,3]`` or Java functors
``DoubleUnaryOperator@(lambda x:x*2)``.  The result of the casting operator
will be a Java object with the desired type or raise a ``TypeError`` if the
cast or conversion is not possible.   For Python objects, the Java object will
generally be a copy as it is not possible to reflect changes in an array back
to Python.  If one needs to retrieve the resulting changes keep a copy of the
converted array before passing it.  For an existing Java object, casting
changes the resolution type for the object.  This can be very useful when
trying to call a specific method overload.   For example, if we have a Java
``a=String("hello")`` and there were an overload of the method ``foo`` between
``String`` and ``Object`` we would need to select the overload with
``foo(java.lang.Object@a)``.

.. _JObject:

Casting is performed through the Python class ``JObject``.  JObject is called
with two arguments which are the object to be cast and the type to cast too.
The cast first consults the conversion table to decide if the cast it permitted
and produces a ``TypeError`` if the conversion is not possible.

``JObject`` also serves as a abstract base class for testing if an object
instance belongs to Java.  All objects that belong to Java will return
true when tested with ``isinstance``.  Like Python's sequence, JObject is an
abstract base class.  No classes actual derive from ``JObject``.

.. _null:

Of particular interest is the concept of Java ``null``.  In Java, null is a
typeless entity which can be placed wherever an object is taken to
indicate that the object is not available.  The equivalent concept in Python is
``None``.  Thus all methods that accept any object type that permit a null will
accept None as an augment with implicit conversion.  However, sometime it is
necessary to pass an explicit type to the method resolution.  To achieve this
in JPype use ``Type@None`` which will create a null pointer with the
desired type.  To test if something is null we have to compare the handle to
None.  This unfortunately trips up some code quality checkers.  The idiom in
Python is ``obj is None``, but as this only matches things that Python
considers identical, we must instead use ``obj==None``.

Casting ``None`` is use to specify types when calling between overloads
with variadic arguments such as ``foo(Object a)`` and ``foo(Object... many)``.
If we want to call ``foo(None)`` is is ambiguous whether we intend to call the
first with a null object or the second with a null array.  We can resolve the
ambiguity with ``foo(java.lang.Object@None)`` or
``foo(java.lang.Object[:]@None)``

Type enforcement appears in three different places within JPype.  These are
whenever a Java method is called, whenever a Java field is set, and whenever
Python returns a value back to Java.


Primitive Types
===============

Unlike Python, Java makes a distinction between objects and primitive data types.
Primitives represent the minimum data that can be manipulated by a computer. These
stand in contrast to objects, which have the ability to contain any combination of
data types and objects within themselves, and can be inherited from.

Java primitives come in three categories:

- **Logical**: `boolean` (true/false values).
- **Textual**: `char` (single Unicode character).
- **Numerical**: Fixed-point or floating-point numbers of varying sizes.

JPype maps Java primitives to Python classes. To avoid naming conflicts with
Python, JPype prefixes each primitive type with `J` (e.g., `JBoolean`, `JInt`).

.. _jpype_types_primitive_types_jboolean:

JBoolean
--------

Represents a logical value (`True` or `False`). In JPype, `True` and `False` are
exact matches for `JBoolean`. Methods returning a `JBoolean` will always return a
Python `bool`.

.. code-block:: python

   # Example usage
   java_boolean = JBoolean(True)
   print(java_boolean)  # Output: True

.. _jpype_types_primitive_types_jchar:

JChar
-----

Represents a single character. Java `char` types are 16-bit Unicode characters,
but some Unicode characters require more than 16 bits. JPype maps `JChar` to
Python strings of length 1. While `JChar` supports numerical operations, modifying
characters numerically can corrupt their encoding.

.. code-block:: python

   # Example usage
   java_char = JChar('A')
   print(java_char)  # Output: 'A'

.. _jpype_types_primitive_types_jbyte,_jshort,_jint,_jlong:

JByte, JShort, JInt, JLong
--------------------------

These types represent signed integers of varying sizes:

- **JByte**: 8 bits
- **JShort**: 16 bits
- **JInt**: 32 bits
- **JLong**: 64 bits

JPype maps these types to Python's `int`. Methods returning integer primitives will
return Python `int` values. Methods accepting integer primitives will accept Python
integers or any object that can be converted into the appropriate range.

.. code-block:: python

   # Example usage
   java_int = JInt(42)
   print(java_int)  # Output: 42


.. _jpype_types_jfloat_jdouble:

JFloat, JDouble
---------------

These types represent floating-point numbers:

- **JFloat**: 32-bit precision
- **JDouble**: 64-bit precision

JPype maps these types to Python's `float`. Numbers exceeding the range of `JFloat`
or `JDouble` will result in positive or negative infinity. Range checks are
performed when converting Python types, and an `OverflowError` will be raised if
the value is out of bounds.

.. code-block:: python

   # Example usage
   java_double = JDouble(3.14)
   print(java_double)  # Output: 3.14


.. _jpype_types_objects__classes:

Objects & Classes
=================

In contrast to primitive data type, objects can hold any combination of
primitives or objects.  Thus they represent structured data.  Objects can also
hold methods which operate on that data.  Objects can inherit from one another.

However unlike Python, Java objects must have a fixed structure which defines
its type.  These are referred to the object's class.  Here is a point of
confusion.  Java has two different class concepts: the class definition and the
class instance.  When you import a class or refer to a method using the class
name you are accessing the class definition.  When you call ``getClass`` on an
object it returns a class instance.  The class instance is a object whose
structure can be used to access the data and methods that define the class
through reflection.  The class instance cannot directly access the fields or
method within a class but instead provides its own interface for querying the
class.  For the purposes of this document a "class" will refer to the class
definition which corresponds to the Python concept of a class. Wherever the
Java reflection class is being referred to we will use the term "class
instance".  The term "type" is synonymous with a "class" in Java, though often
the term "type" is only used when inclusively discussing the type of primitives
and objects, while the term "class" generally refers to just the types
associated with objects.

All objects in Java inherit from the same base class ``java.lang.Object``, but
Java does not support multiple inheritance.  Thus each class can only inherit
from a single parent.  Multiple inheritance, mix-ins, and diamond pattern are
not possible in Java.  Instead Java uses the concept of an interface.  Any Java
class can inherit as many interfaces as it wants, but these interfaces may not
contain any data elements.  As they do not contain data elements there can
be no ambiguity as to what data a particular lookup.

.. _JInterface:

The meta class ``JInterface`` is used to check if a class type is an interface
using ``isinstance``.  Classes that are pure interfaces cannot be instantiated,
thus, there is not such thing as an abstract instance.  Therefore, every
Java object should have Objects cannot actual be pure interfaces.  To
represent this in Python every interface inherits ``java.lang.Object`` methods
even through it does not have ``java.lang.Object`` as a parent.  This ensures
that anonymous classes and lambdas have full object behavior.

.. _jpype_types_classes:

Classes
-------

In JPype, Java classes are instances of the Python ``type`` and function like
any ordinary Python class.  However unlike Python types, Java classes are
closed and cannot be extended.  To enforce extension restrictions, all Java
classes are created from a special private meta class called
``_jpype._JClass``.  This gatekeeper ensures that the attributes of classes
cannot be changed accidentally nor extended.  The type tree of Java is fixed
and closed.

All Java classes have the following functionality.

Class constructor
  The class constructor is accessed by using the Python call syntax ``()``.
  This special method invokes a dispatch whenever the class is called
  as a function.  If an matching constructor is found a new Java instance
  is created and a Python handle to that instance is returned.  In the case
  of primitive types, the constructor creates a Java value with the exact
  type requested.

Get attribute
  The Python ``.`` operator gets an attribute from a class with a specified
  name.  If no method or field exists a ``AttributeError`` will be raised.
  For public static methods, the getattr will produce a Python descriptor which
  can be called to invoke the static method.  For public static fields, a Python
  descriptor will be produced that allows the field to be get or set depending
  on whether the field is final or not.  Public instance methods and instance
  fields will produce a function that can be applied to a Java object to
  execute that method or access the field.  Function accessors are
  non-virtual and thus they can provide access to behaviors that have been
  hidden by a derived class.

Set attribute
  In general, JPype only allows the setting of public non-final fields.  If you
  attempt to set any attribute on an object that does not correspond to a
  settable field it will produce an ``AttributeError``.  There is one exception
  to this rule.  Sometime it is necessary to attach addition private meta data to
  classes and objects.  Attributes that begin with an underbar are consider to be
  Python private attributes.  Private attributes handled by the default Python
  attribute handler allowing these attributes to be attached to to attach data to
  the Python handle.  This data is invisible to Java and it is retained only on
  the Python instance.  If an object with Python meta data is passed to Java
  and Java returns the object, the new Python handle will not contain any of the
  attached data as this data was lost when the object was passed to Java.

``class_`` Attribute
  For Java classes there is a special attribute called ``class``.  This
  is a keyword in Python so `name mangling`_ applies.  This is a class instance
  of type ``java.lang.Class``.  It can be used to access fields and methods.

Inner classes
  For methods and fields, public inner classes appear as attributes of
  the class.  These are regular types that can be used to construct objects,
  create array, or cast.

String
  The Java method ``toString`` is mapped into the Python function ``str(obj)``.

Equality
  The Java method ``equals()`` has been mapped to Python ``==`` with special
  augmentations for null pointers.  Java ``==`` is not exposed directly
  as it would lead to numerous errors.  In principle, Java ``==`` should map
  to the Python concept of ``is`` but it is not currently possible to overload
  Python in such a way to achieve the desired effect.

Hash
  The Java method ``hashCode`` is mapped to Python ``hash(obj)`` function.
  There are special augmentations for strings and nulls.  Strings will return
  the same hash code as returned by Python so that Java strings and Python
  strings produce the same dictionary lookups.  Null pointers produce the
  same hash value as None.

  Java defines ``hashCode`` on many objects including mutable ones.  Often
  the ``hashCode`` for a mutable object changes when the object is changed.
  Only use immutable Java object (String, Instant, Boxed types) as
  dictionary keys or risk undefined behavior.

Java objects are instances of Java classes and have all of the methods defined
in the Java class including static members.  However, the get attribute method
converts public instance members and fields into descriptors which act on
the object.

Now that we have defined the basics of Java objects and classes, we will
define a few special classes that operate a bit differently.

.. _jpype_types_array_classes:

Array Classes
-------------

In Java, all arrays are objects, but they cannot define any methods beyond a
limited set of Java array operations. These operations have been mapped into
Python to their closest Python equivalent.

`JArray` is an abstract base class for all Java array classes. Thus, you can
test if something is an array class using ``issubclass``, and check if a Java
object is an array using ``isinstance``.

Creating Array Types
~~~~~~~~~~~~~~~~~~~~

In principle, you can create an array class using ``JClass``, but the signature
required would need to use the proper name as required for the Java method
``java.lang.Class.forName``. Instead, JPype provides two specialized methods to
create array types: arrays may be produced through the factory ``JArray`` or
through the index operator ``[]`` on any `JClass` instance.

.. _JArray:

The signature for `JArray` is ``JArray(type, [dims=1])``. The `type` argument
accepts any Java type, including primitives, and constructs a new array class.
This class can be used to create new instances, cast, or serve as the input to
the array factory. The resulting object has a constructor method that takes
either:

- A number, which specifies the desired size of the array.
- A sequence, which provides the elements of the array. If the members of the
  initializer sequence are not Java objects, each will be converted. If any
  element cannot be converted, a ``TypeError`` will be raised.

As a shortcut, the ``[]`` operator can be used to specify an array type or
create a new instance of an array with a specified length. You can also create
multidimensional arrays or arrays with unspecified dimensions after a specific
point. This applies to both primitive and object types. Because of the number
of options, we will walk through each use case.

To create a one-dimensional array type, append ``[:]`` to any Java class or
primitive type. For example:

- ``JInt[:]`` creates a Java array type for integers.
- ``java.lang.Object[:]`` creates a Java array type for objects.
- ``java.util.List[:]`` creates a Java array type for lists.

Once the array type is created, you can use it to construct arrays, cast Python
sequences to Java arrays, or define multidimensional arrays.

.. code-block:: python

   # Example: Creating array types
   int_array_type = JInt[:]
   object_array_type = java.lang.Object[:]

   # Creating arrays
   int_array = int_array_type([1, 2, 3])
   object_array = object_array_type([None, "Hello", 42])

   print(int_array)  # Output: [1, 2, 3]
   print(object_array)  # Output: [null, Hello, 42]

Multidimensional Arrays
~~~~~~~~~~~~~~~~~~~~~~~

JPype supports the creation of multi-dimensional arrays by appending additional
dimensions using ``[:]``. For example:

- ``JInt[:,:]`` creates a two-dimensional array type for integers.
- ``java.lang.Object[:,:]`` creates a two-dimensional array type for objects.
- ``JDouble[:,:,:]`` creates a three-dimensional array type for double-precision
  floating-point numbers.

When creating multi-dimensional arrays, you can initialize them using nested
Python lists. JPype automatically converts nested lists into the appropriate
Java array structure.

.. code-block:: python

   # Example: Creating multidimensional arrays
   int_2d_array_type = JInt[:, :]
   int_2d_array = int_2d_array_type([[1, 2], [3, 4]])

   print(int_2d_array[0][1])  # Output: 2

   # Creating a 3D array
   double_3d_array_type = JDouble[:, :, :]
   double_3d_array = double_3d_array_type([[[1.1, 2.2], [3.3, 4.4]], [[5.5, 6.6], [7.7, 8.8]]])

   print(double_3d_array[1][0][1])  # Output: 6.6

Jagged Arrays
~~~~~~~~~~~~~

Java supports jagged arrays, which are arrays of arrays with varying lengths.
To create jagged arrays in JPype, replace the final dimension with `[:]`. For
example:

- `JInt[5, :]` creates a jagged array of integers with 5 rows.
- `java.lang.Object[3, :]` creates a jagged array of objects with 3 rows.

Jagged arrays can be initialized using nested Python lists with varying lengths.

.. code-block:: python

   # Example: Creating jagged arrays
   jagged_int_array_type = JInt[3, :]
   jagged_int_array = jagged_int_array_type([[1, 2], [3, 4, 5], [6]])

   print(jagged_int_array[1][2])  # Output: 5

Use of Java Arrays
~~~~~~~~~~~~~~~~~~

Java arrays provide several Python methods:

- **Get Item**:
  Arrays are collections of elements. Array elements can be accessed using the
  Python ``[]`` operator. For multidimensional arrays, JPype uses Java-style
  access with a series of index operations, such as ``jarray[4][2]``.

- **Get Slice**:
  Arrays can be accessed using slices, like Python lists. The slice operator is
  ``[start:stop:step]``. Note that array slices are views of the original array,
  so any alteration to the slice will affect the original array. Use the `clone`
  method to create a copy of the slice if needed.

- **Set Item**:
  Array items can be set using the Python ``[]=`` operator.

- **Set Slice**:
  Multiple array items can be set using a slice assigned with a sequence. The
  sequence must have the same length as the slice. If the items being transferred
  are a buffer, a faster buffer transfer assignment will be used.

- **Buffer Transfer**:
  Buffer transfers from Java arrays work for primitive types. Use Python's
  ``memoryview(jarray)`` function to create a buffer for transferring data.
  Memory views of Java arrays are not writable.

- **Iteration (For Each)**:
  Java arrays can be used in Python `for` loops and lopp comprehensions.

- **Clone**:
  Java arrays can be duplicated using the `clone()` method.

- **Length**:
  Arrays in Java have a defined, immutable length. Use Python's ``len(array)``
  function to get the array length.

Character specialization
~~~~~~~~~~~~~~~~~~~~~~~~

- The Java class `JChar[]` has additional customizations to work better with
  string types.
- Java arrays do not support additional mathematical operations at this time.
- Creating a Java array is required for pass-by-reference syntax when using Java
  methods that modify array contents.

.. code-block:: python

   orig = [1, 2, 3]
   obj = jpype.JInt[:](orig)
   a.modifies(obj)   # Modifies the array by multiplying all elements by 2
   orig[:] = obj     # Copies all the values back from Java to Python


.. _jpype_types_buffer_classes:

Buffer classes
--------------

In addition to array types, JPype also supports Java ``nio`` buffer types.
Buffers in Java come in two flavors.  Array backed buffers have no special
access.  Direct buffers are can converted to Python buffers with both
read and write capabilities.

Each primitive type in Java has its own buffer type named based on the
primitive type.  ``java.nio.ByteBuffer`` has the greatest control allowing
any type to be read and written to it.  Buffers in Java function are like
memory mapped files and have a concept of a read and write pointer which
is used to traverse the array.  They also have direct index access to their
specified primitive type.

Java buffer provide an additional Python method:

Buffer transfer
  Buffer transfers from a Java buffer works for a direct buffer.  Array backed
  buffers will raise a ``BufferError``.  Use the Python ``memoryview(jarray)``
  function to create a buffer that can be used to transfer any portion of a Java
  buffer out.  Memory views of Java buffers are readable and writable.

Buffers do not currently support element-wise access.


.. _jpype_types_boxed_classes:

Boxed Classes
-------------

Often one wants to be able to place a Java primitive into a method of
fields that only takes an object.  The process of creating an object from a
primitive is referred to as creating a "boxed" object.  The resulting object is
an immutable object which stores just that one primitive.

Java boxed types in JPype are wrapped with classes that inherit from Python
``int`` and ``float`` types as both are immutable in Python.  This means that
a boxed type regardless of whether produced as a return or created explicitly
are treated as Python types. They will obey all the conversion rules
corresponding to a Python type as implicit matches.

In addition, they produce an exact match with their corresponding Java
type. The type conversion for this is somewhat looser than Java.  While Java
provides automatic unboxing of a Integer to a double primitive, JPype can
implicitly convert Integer to a Double boxed.

To box a primitive into a specific type such as to place it into a
``java.util.List`` use ``JObject`` on the desired boxed type or call
the constructor for the desired boxed type directly.  For example:

.. code-block:: python

     lst = java.util.ArrayList()
     lst.add(JObject(JInt(1)))      # Create a Java integer and box it
     lst.add(java.lang.Integer(1))  # Explicitly create the desired boxed object

JPype boxed classes have some additional functionality.  As they inherit from
a mathematical type in Python they can be used in mathematical operations.
But unlike Python numerical types they can take an addition state corresponding
to being equal to a null pointer.  The Python methods are not aware of this
new state and will treat the boxed type as a zero if the value is a null.

To test for null, cast the boxed type to a Python type explicitly and the
result will be checked.  Casting null pointer will raise a ``TypeError``.

.. code-block:: python

     b = JObject(None, java.lang.Integer)
     a = b+0      # This succeeds and a gets the value of zero
     a = int(b)+0 # This fails and raises a TypeError

Boxed objects have the following additional functionality over a normal object.

Convert to index
  Integer boxed types can be used as Python indices for arrays and other
  indexing tasks. This method checks that the value of the boxed
  type is not null.

Convert to int
  Integer and floating point boxed types can be cast into a Python integer
  using the ``int()`` method.  The resulting object is always of type ``int``.
  Casting a null pointer will raise a ``TypeError``.

Convert to float
  Integer and floating point boxed types can be cast into a Python float
  using the ``float()`` method.  The resulting object is always of type
  ``float``.  Casting a null pointer will raise a ``TypeError``.

Comparison
  Integer and floating point types implement the Python rich comparison API.
  Comparisons for null pointers only succeed for ``==`` and ``!=`` operations.
  Non-null boxed types act like ordinary numbers for the purposes of
  comparison.


.. _jpype_types_number_class:

Number Class
------------

The Java class ``java.lang.Number`` is a special type in Java. All numerical
Java primitives and Python number types can convert implicitly into a
Java Number.

========================== ========================
Input                      Result
========================== ========================
None                       java.lang.Number(null)
Python int, float          java.lang.Number
Java byte,   NumPy int8    java.lang.Byte
Java short,  NumPy int16   java.lang.Short
Java int,    NumPy int32   java.lang.Integer
Java long,   NumPy int64   java.lang.Long
Java float,  NumPy float32 java.lang.Float
Java double, NumPy float64 java.lang.Double
========================== ========================

Additional user defined conversion are also applied.  The primitive types
boolean and char and their corresponding boxed types are not considered to
numbers in Java.

.. _java.lang.Object:

Object Class
------------

Although all classes inherit from Object, the object class itself has special
properties that are not inherited.  All Java primitives will implicitly convert
to their box type when placed in an Object.  In addition, a number of Python
types implicitly convert to a Java object.  To convert to a different object
type, explicitly cast the Python object prior to placing in a Java object.

Here a table of the conversions:

================ =======================
Input            Result
================ =======================
None             java.lang.Object(null)
Python str       java.lang.String
Python bool      java.lang.Boolean
Python int       java.lang.Number
Python float     java.lang.Number
================ =======================

In addition it inherits the conversions from ``java.lang.Number``.
Additional user defined conversion are also applied.

.. _java.lang.String:

String Class
------------

The String class in Java is a special representation often pointing either to
a dynamically created string or to a constant pool item defined in the class.
All Java strings are immutable just like Python strings and thus these are
considered to be equivalent classes.

Because Java strings are in fact just pointers to blob of bytes they are
actually slightly less than a full object in some JVM implementation.  This is
a violation of the Object Orients (OO) principle, never take something away by
inheritance.  Unfortunately, Java is a frequent violator of that rule, so
this is just one of those exceptions you have to trip over.  Therefore, certain
operations such as using a string as a threading control with ``notify`` or ``wait``
may lead to unexpected results.  If you are thinking about using a Java string
in synchronized statement then remember it is not a real object.

Java strings have a number of additional functions beyond a normal
object.

Length
  Java strings have a length measured in the number of characters required
  to represent the string.  Extended Unicode characters
  count for double for the purpose of counting characters.  The string length
  can be determined using the Python ``len(str)`` function.

Indexing
  Java strings can be used as a sequence of characters in Python and thus
  each character can be accessed as using the Python indexing operator ``[]``.

Hash
  Java strings use a special hash function which matches the Python hash code.
  This ensures that they will always match the same dictionary keys as
  the corresponding string in Python.  The Python hash can be determined using
  the Python ``hash(str)`` function.  Null pointers are not currently handled.
  To get the actually Java hash, use ``s.hashCode()``

Contains
  Java strings implement the concept of ``in`` when using the Java method
  ``contains``.  The Java implementation is sufficiently similar that it will
  work fairly well on strings.
  For example, ``"I" in java.lang.String("team")`` would be equal to False.

  Testing other types using the ``in`` operator
  will likely raise a ``TypeError`` if Java is unable to convert the other item
  into something that can be compared with a string.

Concatenation
  Java strings can be appended to create a new string which contains the
  concatenation of the two strings.  This is mapped to the Python operator
  ``+``.

Comparison
  Java strings are compared using the Java method ``compareTo``.  This
  method does not currently handle null and will raise an exception.

For each
  Java strings are treated as sequences of characters and can be used with a
  for-loop construct and with list comprehension.  To iterate through all of the
  characters, use the Python construct ``for c in str:``.

Unfortunately, Java strings do not yet implement the complete list of
requirements to act as Python sequences for the purposes of
``collections.abc.Sequence``.

.. _JString:

The somewhat outdated JString factory is a Python class that pretends to be a
Java string type.  It has the marginal advantage that it can be imported before
the JVM is actually started.  Once the JVM is started, its class representation
is pointed to ``java.lang.String`` and can be used to construct a new string
object or to test if an object is actually a Java string using ``isinstance``.
It does not implement any of the other string methods and just serves as
convenience class.  The more capable ``java.lang.String`` can be imported
in place of JString, but only after the JVM is started.

String objects may optionally convert to Python strings when returned
from Java methods, though this option is a performance issue and can lead to
other difficulties.  This setting is selected when the JVM is started.
See `String Conversions`_ for details.

Java strings will cache the Python conversion so we only pay the conversion
cost once per string.


.. _jpype_types_exception_classes:

Exception Classes
-----------------

Both Python and Java treat exception classes differently from other objects.
Only these types may be caught as part of a try block.  Therefore, the
exceptions have a special wrapper.  Most of the mechanics of exceptions happen
under the surface.  The one difference between Python and Java is the behavior
when the argument is queried.  Java arguments can either be the string value, the exception
itself, or the internal construction key depending on how the exception came
into existence.  Therefore, the arguments to a Java exception should never be
used as their values are not guaranteed.

Java exception can report their stacktrace to Python in two different ways.  If
printed through the Python stack trace routine, Java exceptions are split
between the Python code that raised and a phantom Java ``cause`` which contains the
Java exception in Python order.  If the debugging information for the Java
source is enabled, Python may even print the Java source code lines
where the error occurred.  If you prefer Java style stack traces then print the
result from the ``stacktrace()`` method.  Unhandled exception that terminate
the program will print the Python style stack trace information.

.. _JException:

The base class ``JException`` is a special type located in ``jpype.types`` that
can be imported prior to the start of the JVM.  This serves as the equivalent
of ``java.lang.Throwable`` and contains no additional methods.  It is currently
being phased out in favor of catching the Java type directly.

Using ``jpype.JException`` with a class name as a string was supported in
previous JPype versions but is currently deprecated.  For further information
on dealing with exception, see the `Exception Handling`_ section.  To create a
Java exception use JClass or any of the other importing methods.


.. _jpype_types_anonymous_classes:

Anonymous Classes
-----------------

Sometimes Java will produce an anonymous class which does to have any actual
class representation.  These classes are generated when a method implements
a class directly as part of its body and they serve as a closure with access
to some of the variables that were used to create it.

For the purpose of JPype these classes are treated as their parents.  But this
is somewhat problematic when the parent is simply an interface and not an actual
object type.


.. _jpype_types_lambdas:

Lambdas
-------

The companion of anonymous classes are lambda classes.  These are generated
dynamically and their parent is always an interface.  Lambdas are always
Single Abstract Method (SAM) type interfaces.  They can implement additional
methods in the form of default methods but those are generally not accessible
within JPype.

.. _jpype_types_inner_classes:

Inner Classes
-------------

For the most part, inner classes can be used like normal classes, with the
following differences:

- Inner classes in Java natively use $ to separate the outer class from the
  inner class. For example, inner class Foo defined inside class Bar is called
  Bar.Foo in Java, but its real native name is Bar$Foo.
- Inner classes appear as member of the containing class. Thus to access them
  import the outer class and call them as members.
- Non-static inner classes cannot be instantiated from Python code.  Instances
  received from Java code can be used without problem.

.. _jpype_types_buffer_transfers:

Buffer Transfers
----------------
Java arrays provide efficient buffer transfers for primitive types using Python's
`memoryview`. This allows seamless integration with libraries like NumPy for
numerical operations. For strategies to optimize data exchange, 
see :ref:`Optimize Data Transfers <optimize_data_transfers>`.

.. code-block:: python

   # Example: Buffer transfer
   import numpy as np

   int_array = JInt[:](5)
   int_array[:] = [1, 2, 3, 4, 5]  # Transfer data to Java array

   buffer = memoryview(int_array)
   np_array = np.array(buffer)     # Convert to NumPy array

   print(np_array)  # Output: [1, 2, 3, 4, 5]


.. _import:

Importing Java classes
======================

As Java classes are remote from Python and can neither be created nor extended within
Python, they must be imported.  JPype provides three different methods for
creating classes.

The highest level API is the use of the import system.
To import a Java class, one must first import the optional module
``jpype.imports`` which has the effect of binding the Java package system
to the Python module lookup.  Once this is completed package or class can
be imported using the standard Python import system.  The import system
offers a very rich error reporting system.  All failed imports produce
an ``ImportError`` with diagnostics as to what went wrong.  Errors include
unable to find the class, unable to find a required dependency, and incorrect
Java version.

One important caveat when dealing with importing Java modules.  Python always
imports local directories as modules before calling the Java importer.  So any
directory named ``java``, ``com``, or ``org`` will hide corresponding Java
package.  We recommend against naming directories as ``java`` or top level
domain.

.. _JPackage:

The older method of importing a class is with the ``JPackage`` factory.
This factory automatically loads classes as attributes as requested.
If a class cannot be found it will produce an ``AttributeError``.  The
symbols ``java`` and ``javax`` in the ``jpype`` module are both ``JPackage``
instances.  Only public classes appear on ``JPackage`` but protected and even
private classes can be accessed by name.  Though most private classes
don't have any methods or fields that can be accessed.

.. _JClass:

The last mechanism for looking up a class is through the use of the ``JClass``
factory.  This is a low level API allowing the loading of any class available
using the forName mechanism in Java.  The JClass method can take up to three
arguments corresponding to arguments of the forName method and can be used
with alternative class loaders.  The majority of the JPype test bench uses
JClass so that the tests are only evaluating the desired functionality and not
the import system.  But this does not imply that JClass is the preferred
mechanic for importing classes.  The first argument can be a string or
a Java class instance.  There are two keyword arguments ``loader`` and
``initialize``.  The loader can point to an alternative ClassLoader which
is handy when loading custom classes through mechanisms such as over the
web.  A False ``initialize`` argument loads a class without
loading dependencies nor populating static fields.  This option is likely
not useful for ordinary users.  It was provided when calling forName was problematic
due to `caller sensitive`_ issues.


.. _name_mangling:

Name mangling
=============

When providing Java package, classes, methods, and fields to Python,
there are occasionally naming conflicts.  For example, if one has a method
called ``with`` then it would conflict with the Python keyword ``with``.
Wherever this occurs, JPype renames the offending symbol with a trailing
under bar.  Java symbols with a leading or trailing under bars are consider to
be privates and may not appear in the JPype wrapper entirely with the exception
of package names.

The following Python words will trigger name mangling of a Java name:

=========== =========== ============= =========== ==========
``False``   ``None``    ``True``      ``and``     ``as``
``async``   ``await``   ``def``       ``del``     ``elif``
``except``  ``exec``    ``from``      ``global``  ``in``
``is``      ``lambda``  ``nonlocal``  ``not``     ``or``
``pass``    ``print``   ``raise``     ``with``    ``yield``
=========== =========== ============= =========== ==========


.. _methods:
.. _jpype_types_method_resolution:


Method Resolution
=================

Because Java supports method overloading and Python does not, JPype wraps Java
methods as a "method dispatch". The dispatch is a collection of all of the
methods from the class and all of its parents which share the same name. The
job of the dispatch is to choose the method to call. Enforcement of the strong
typing of Java must be performed at runtime within Python. Each time a method
is invoked, JPype must match against the list of all possible methods that the
class implements and choose the best possible overload. For this reason, the
methods that appear in a JPype class will not be the actual Java methods, but
rather a "dispatch" whose job is deciding which method should be called based
on the type of the provided arguments. If no method is found that matches the
provided arguments, the method dispatch will produce a ``TypeError``. This is
the exact same outcome that Python uses when enforcing type safety within a
function. If a type doesn't match, a ``TypeError`` will be produced.

Dispatch Example
----------------

When JPype is unable to decide which overload of a method to call, the user
must resolve the ambiguity. This is where casting comes in. Take for example
the ``java.io.PrintStream`` class. This class has a variant of the print and
println methods! So for the following code:

.. code-block:: python

   java.lang.System.out.println(1)

JPype will automatically choose the ``println(long)`` method, because the
Python ``int`` matches exactly with the Java ``long``, while all the other
numerical types are only "implicit" matches. However, if that is not the
version you wanted to call, you must cast it. In this case, we will use a
primitive type to construct the correct type. Changing the line thus:

.. code-block:: python

   java.lang.System.out.println(JByte(1))  # <--- wrap the 1 in a JByte

This tells JPype to choose the byte version. When dealing with Java types,
JPype follows the standard Java matching rules. Types can implicitly grow to
larger types but will not shrink without an explicit cast.

Caching Optimization for Method Resolution
------------------------------------------

JPype optimizes method resolution by caching the results of previous matches.
If the same method is called repeatedly with the same argument types (e.g.,
inside a loop or list comprehension), JPype reuses the cached resolution,
avoiding the overhead of re-evaluating all overloads. This greatly improves
performance for repetitive calls.

For example, consider the following code:

.. code-block:: python

   fruits = ["apple", "orange", "banana"]
   jlist = java.util.ArrayList()
   [jlist.add(fruit) for fruit in fruits]  # Cached resolution for each iteration

In this case, JPype caches the resolution for ``add(str)`` to ``add(String)``
method after the first call, and subsequent calls reuse the cached result. This
optimization is particularly beneficial in loops and list comprehensions.  A
call to ``add(int)`` would trigger a new resolution.  The next call to ``add(str)``
will once again trigger a resolution request.

**Note**: For an in-depth discussion on how this caching mechanism improves
loop performance, particularly in list comprehensions, see the
:ref:`Performance <miscellaneous_topics_performance>` section.

Interactions of Custom Converters and Caching
---------------------------------------------

It is unwise to define very broad conversions as it can interact poorly with 
caching. Suppose that one defined a convertion from all Python strings to the
Java class for date under some condition. Or perhaps an even broader convserion
was defined such as all Python classes that inherit from object.

If such overly broad conversions are applied to a function
for which both date and string were acceptable it were prefer the date
conversion when method resolution starts.  As the type for the cache was string
it would attempt the out of order resolution of date first.  If the 
condition yield a fail it will fall back to normal method resolution, but
an overly broad conversion specialization may end up being dispatched to the 
previously defined conversion.

Under normal operation of JPype the type conversions are narrowly defined such
that the cache will always yield the proper resolution.  But user defined
conversions may cause unexpected results.  In such a case, a cast operation to
the Java type would be required to resolve the ambiguity.



.. _jpype_types_type_matching:

Type Matching
=============

This section provides tables documenting the JPype conversion rules.
JPype defines different levels of "match" between Python objects and Java
types. These levels are:

- **none**, There is no way to convert.
- **explicit (E)**, JPype can convert the desired type, but only
  explicitly via casting.  Explicit conversions are only execute automatically
  in the case of a return from a proxy.
- **implicit (I)**, JPype will convert as needed.
- **exact (X)**, Like implicit, but when deciding with method overload
  to use, one where all the parameters match "exact" will take precedence
  over "implicit" matches.

See the previous section on `Java Conversions`_ for details.

There are special conversion rules for ``java.lang.Object`` and ``java.lang.Number``.
(`Object Class`_ and `Number Class`_)

============== ========== ========= =========== ========= ========== ========== =========== ========= ========== =========== ========= ================== =================
Python\\Java    byte      short       int       long       float     double     boolean     char      String      Array       Object    java.lang.Object   java.lang.Class
============== ========== ========= =========== ========= ========== ========== =========== ========= ========== =========== ========= ================== =================
    int         I [1]_     I [1]_       X          I        I [3]_     I [3]_     X [8]_                                                       I [11]_
   long         I [1]_     I [1]_     I [1]_       X        I [3]_     I [3]_                                                                  I [11]_
   float                                                    I [1]_       X                                                                     I [11]_
 sequence
dictionary
  string                                                                                     I [2]_       X                                    I
  unicode                                                                                    I [2]_       X                                    I
   JByte          X                                                                                                                            I [9]_
  JShort                     X                                                                                                                 I [9]_
   JInt                                 X                                                                                                      I [9]_
   JLong                                           X                                                                                           I [9]_
  JFloat                                                      X                                                                                I [9]_
  JDouble                                                                X                                                                     I [9]_
 JBoolean                                                                           X                                                          I [9]_
   JChar                                                                                       X                                               I [9]_
  JString                                                                                                 X                                    I
  JArray                                                                                                          I/X [4]_                     I
  JObject                                                                                                         I/X [6]_    I/X [7]_         I/X [7]_
  JClass                                                                                                                                       I                  X
 "Boxed"[10]_     I          I          I          I          I          I          I                                                          I
============== ========== ========= =========== ========= ========== ========== =========== ========= ========== =========== ========= ================== =================

.. [1] Conversion will occur if the Python value fits in the Java
       native type.

.. [2] Conversion occurs if the Python string or unicode is of
       length 1.

.. [3] Java defines conversions from integer types to floating point
       types as implicit conversion. Java's conversion rules are based
       on the range and can be lossy.
       See (http://stackoverflow.com/questions/11908429/java-allows-implicit-conversion-of-int-to-float-why)

.. [4] Number of dimensions must match and the types must be
       compatible.

.. [6] Only if the specified type is a compatible array class.

.. [7] The object class is an exact match, otherwise
       implicit.

.. [8] Only the values `True` and `False` are implicitly converted to
       booleans.

.. [9] Primitives are boxed as per Java rules.

.. [10] Java boxed types are mapped to Python primitives, but will
        produce an implicit conversion even if the Python type is an exact
        match. This is to allow for resolution between methods
        that take both a Java primitve and a Java boxed type.

.. [11] Boxed to ``java.lang.Number``


Exception Handling
==================

Error handling is an important part of any non-trivial program. All Java
exceptions occurring within Java code raise a `jpype.JException`, which derives
from Python's `Exception`. These can be caught either using a specific Java
exception or generically as a `jpype.JException` or `java.lang.Throwable`. You
can then use the `stacktrace()`, `str()`, and `args` to access extended
information.

.. _jpype_types_catching_a_specific_java_exception:

Catching a Specific Java Exception
----------------------------------

The following example demonstrates catching a specific Java exception:

.. code-block:: python

    try:
        # Code that throws a java.lang.RuntimeException
    except java.lang.RuntimeException as ex:
        print("Caught the runtime exception:", str(ex))
        print(ex.stacktrace())

.. _jpype_types_catching_multiple_java_exceptions:

Catching Multiple Java Exceptions
---------------------------------

Multiple Java exceptions can be caught together or separately:

.. code-block:: python

    try:
        # Code that may throw various exceptions
    except (java.lang.ClassCastException, java.lang.NullPointerException) as ex:
        print("Caught multiple exceptions:", str(ex))
        print(ex.stacktrace())
    except java.lang.RuntimeException as ex:
        print("Caught runtime exception:", str(ex))
        print(ex.stacktrace())
    except jpype.JException as ex:
        print("Caught base exception:", str(ex))
        print(ex.stacktrace())
    except Exception as ex:
        print("Caught Python exception:", str(ex))

.. _jpype_types_raising_exceptions_from_python_to_java:

Raising Exceptions from Python to Java
--------------------------------------

Exceptions can be raised in proxies to throw an exception back to Java.
Exceptions within the JPype core are issued with the most appropriate Python
exception type, such as `TypeError`, `ValueError`, `AttributeError`, or
`OSError`.

.. _jpype_types_raising_exceptions_in_proxies:

Raising Exceptions in Proxies
-----------------------------

JPype allows Python proxies to raise exceptions that are propagated back to
Java. This is particularly useful when implementing Java interfaces in Python
and handling invalid inputs or unexpected conditions.

When an exception is raised in Python, it is wrapped in a `RuntimeException` in
Java. If the exception propagates back to Python, it is unpacked to return the
original Python exception.

.. _jpype_types_example:

Example
~~~~~~~

The following example demonstrates raising a Python exception from a proxy:

.. code-block:: python

    import jpype
    import jpype.imports

    jpype.startJVM()

    from java.util.function import Function

    @jpype.JImplements(Function)
    class MyFunction:
        @jpype.JOverride
        def apply(self, value):
            if value is None:
                raise ValueError("Invalid input: None is not allowed")
            return value.upper()

    try:
        func = MyFunction()
        result = func.apply(None)  # This will raise a ValueError
    except ValueError as ex:
        print("Caught Python exception:", str(ex))


.. _jpype_types_exception_aliasing:

Exception Aliasing
------------------

Certain exceptions in Java have a direct correspondence with existing Python
exceptions. Rather than forcing JPype to translate these exceptions or
requiring the user to handle Java exception types throughout the code, these
exceptions are "derived" from their Python counterparts. This allows the user
to catch them using standard Python exception types.

+---------------------------------------+------------------+
| Java Exception                        | Python Exception |
+---------------------------------------+------------------+
| `java.lang.IndexOutOfBoundsException` | `IndexError`     |
| `java.lang.NullPointerException`      | `ValueError`     |
+---------------------------------------+------------------+


.. _jpype_types_aliasing_example:

Aliasing Example
~~~~~~~~~~~~~~~~

The following example demonstrates catching an aliased exception:

.. code-block:: python

    try:
        # Code that throws a java.lang.IndexOutOfBoundsException
    except IndexError as ex:
        print("Caught IndexError:", str(ex))

By deriving these exceptions from Python, the user is free to catch the
exception either as a Java exception or as the more general Python exception.
Remember that Python exceptions are evaluated in order from most specific to
least.


.. _controlling_the_jvm:

Controlling the JVM
*******************

In this chapter, we will discuss how to control the JVM from within Python.
For the most part, the JVM is invisible to Python.  The only user controls
needed are to start up and shutdown the JVM.

.. _startJVM:

Starting the JVM
================

JPype requires the Java Virtual Machine (JVM) to be started before interacting
with Java. This section explains how to start the JVM, configure its options,
and troubleshoot common issues.

.. _controlling_the_jvm_key_requirements:

Key Requirements
----------------
Before starting the JVM, ensure the following prerequisites are met:

1. **Java Installation**: A Java Runtime Environment (JRE) or Java Development
   Kit (JDK) must be installed. JPype supports Java versions 11 and later.

2. **Architecture Match**: The architecture of the Python interpreter (e.g.,
   64-bit or 32-bit) must match the architecture of the installed JVM.

3. **Classpath Configuration**: Specify the paths to Java classes or JAR files
   required by your application.

4. **Environment Variable**: Ensure the `JAVA_HOME` environment variable is set
   to the directory containing the Java installation.


How to Start the JVM
--------------------
To start the JVM, use the ``jpype.startJVM()`` function. This function
initializes the JVM with the specified options. The key arguments are:

- **``classpath``**: A list of paths to JAR files or directories containing
  Java classes.
- **``convertStrings``**: A boolean flag controlling whether Java strings are
  automatically converted to Python strings.
- **``ignoreUnrecognized``**: A flag that suppresses errors for unrecognized
  JVM options.
- **Additional JVM options**: Any valid JVM arguments (e.g., ``-Xmx`` for
  memory allocation).


Example: Starting the JVM
~~~~~~~~~~~~~~~~~~~~~~~~~
Here is a typical example of starting the JVM:

.. code-block:: python

    import jpype

    # Start the JVM with classpath and options
    jpype.startJVM(
        classpath=['lib/*', 'classes'],
        jvmOptions=["-ea"]  # Enable assertions
    )



Classpath Configuration
-----------------------
JPype supports two methods for specifying the classpath:

1. **``classpath`` Argument**: Pass a list of paths directly to the
   ``startJVM()`` function. Wildcards (``*``) are supported for JAR files in a
   directory.

.. code-block:: python

    jpype.startJVM(classpath=['lib/*', 'classes'])

2. **``addClassPath()`` Function**: Use ``jpype.addClassPath()`` to add paths
   dynamically before starting the JVM.

.. code-block:: python

    jpype.addClassPath('lib/*')
    jpype.addClassPath('classes')
    jpype.startJVM()

To debug classpath issues, print the effective classpath after starting the
JVM:

.. code-block:: python

    print(java.lang.System.getProperty('java.class.path'))

.. _controlling_the_jvm_handling_jar_files_compiled_for_newer_java_versions:

Handling JAR Files Compiled for Newer Java Versions
---------------------------------------------------
If a JAR file is compiled for a newer version of Java than the JVM being used,
JPype will fail to load the classes from the JAR file, and the JVM will throw
an ``UnsupportedClassVersionError``. This occurs because the JVM cannot
interpret class files compiled for a newer version.


.. _controlling_the_jvm_behavior:

Behavior
~~~~~~~~
When attempting to load a JAR file compiled for a newer version of Java, the
JVM will throw an error similar to the following::

    java.lang.UnsupportedClassVersionError: <class_name> has been compiled by a
    more recent version of the Java Runtime (class file version X), this
    version of the Java Runtime only recognizes class file versions up to Y.

For example:

- Java 11 corresponds to class file version 55.
- Java 17 corresponds to class file version 61.

If the JAR file contains class files compiled with a newer version than the
JVM supports, the JVM cannot interpret them.

.. _controlling_the_jvm_starting_the_jvm_handling_jar_files_compiled_for_newer_java_versions_steps_to_resolve:

Steps to Resolve
~~~~~~~~~~~~~~~~
1. **Upgrade the JVM**:
   Ensure the JVM version matches or exceeds the version used to compile the
   JAR file. Use the following command to check the JVM version::

       java -version

2. **Recompile the JAR**:
   If you have access to the source code, recompile the JAR with an older
   version of Java using the ``--release`` flag. For example::

       javac --release 11 -d output_directory source_files

   This ensures compatibility with Java 11.

3. **Check the Class File Version**:
   Use the ``javap`` command to verify the class file version of the JAR::

       javap -verbose <class_name>

   Look for the ``major version`` field in the output.


.. _controlling_the_jvm_best_practices:

Best Practices
~~~~~~~~~~~~~~
- Always ensure the JVM version matches the requirements of the JAR files
  being loaded.
- If possible, use JAR files compiled for long-term support (LTS) versions of
  Java, such as Java 11 or Java 17, to maximize compatibility.

.. _controlling_the_jvm_automatic_jvm_path_detection:

Automatic JVM Path Detection
----------------------------
JPype automatically detects the path to the JVM shared library using the
``JAVA_HOME`` environment variable. If ``JAVA_HOME`` is not set, JPype searches
common directories based on the platform. You can retrieve the detected path
using:

.. code-block:: python

    print(jpype.getDefaultJVMPath())

If the automatic detection fails, specify the JVM path manually as the first
argument to ``startJVM()``:

.. code-block:: python

    jpype.startJVM('/path/to/libjvm.so', classpath=['lib/*'])


.. _controlling_the_jvm_handling_nonascii_characters_in_the_jvm_path:

Handling Non-ASCII Characters in the JVM Path
----------------------------------------------
JPype has been revised to handle JVM paths containing non-ASCII characters. Due
to restrictions in Java, JPype must make a copy of the JVM shared library when
the path includes non-ASCII characters. This ensures compatibility with the
Java Virtual Machine.

**Windows-Specific Behavior**:
On Windows, the copied JVM shared library cannot be deleted after use due to
file locking restrictions imposed by the operating system. As a result, the
temporary file will remain on disk after the JVM is shut down.

**Implications**:

- The copied JVM shared library will occupy disk space until manually removed.

- This behavior is specific to Windows and does not affect Linux or macOS.

**Best Practices**:

- Avoid using non-ASCII characters in the JVM path when running JPype on
  Windows to prevent unnecessary file duplication.

- If non-ASCII characters are unavoidable, ensure sufficient disk space is
  available for temporary files.

**Troubleshooting**:
To locate the copied JVM shared library, check the directory where the JVM path
is specified. The copied file will have the same name as the original shared
library but may include additional identifiers.

**Example**:
If the original JVM path is:
C:\Program Files\Java\jdk-11.0.7\bin\server\jvm.dll

And it contains non-ASCII characters, JPype will create a copy in a temporary directory.

This behavior is necessary to ensure compatibility with Java's handling of
non-ASCII paths.


.. _controlling_the_jvm_additional_flags_for_startjvm:

Additional Flags for `startJVM()`
---------------------------------
JPype provides several optional flags for `startJVM()` to customize the JVM
startup process:

1. **`jvmOptions`**: A list of JVM options for memory, debugging, or garbage
   collection tuning.
   Example: ``jpype.startJVM(jvmOptions=["-Xmx512m", "-XX:+UseG1GC"])``

2. **`ignoreUnrecognized`**: Suppresses errors for unrecognized JVM options.
   Example: ``jpype.startJVM(ignoreUnrecognized=True)``

3. **`convertStrings`**: Controls automatic conversion of Java strings to
   Python strings.
   Example: ``jpype.startJVM(convertStrings=False)``

4. **`classpath`**: Specifies paths to JAR files and Java classes.
   Example: ``jpype.startJVM(classpath=["lib/*", "classes"])``

5. **`jvmPath`**: Specifies the path to the JVM shared library.
   Example: ``jpype.startJVM(jvmPath="/path/to/libjvm.so")``

6. **`attachThread`**: Automatically attaches Python threads to the JVM.
   Example: ``jpype.startJVM(attachThread=True)``

7. **`disableGC`**: Disables JPype's garbage collection hooks.
   Example: ``jpype.startJVM(disableGC=True)``

8. **`stackTrace`**: Enables detailed stack traces for Java exceptions.
   Example: ``jpype.startJVM(stackTrace=True)``

9. **`initializers`**: A list of Python functions executed during JVM startup.
   Example: ``jpype.startJVM(initializers=[setup])``

10. **`modulePath`**: Specifies the module path for Java modular applications.
    Example: ``jpype.startJVM(modulePath=["modules/*"])``

.. _string_conversions:

String Conversions
------------------
The ``convertStrings`` argument controls whether Java strings are automatically
converted to Python strings. By default, this behavior is disabled
(``convertStrings=False``) to preserve Java string methods and avoid
unnecessary conversions.


If enabled (``convertStrings=True``), Java strings are returned as Python
strings, but this can impact performance and chaining of Java string methods.
This option is consisted a legacy option as it will result in unncessary
calls to ``str()`` every time a String is passed from Java.

Best practice: Set ``convertStrings=False`` unless your application explicitly
requires automatic conversion.


.. _controlling_the_jvm_checking_jvm_state:

Checking JVM State
------------------
Use the following functions to check the status of the JVM:

- **``jpype.isJVMStarted()``**: Returns ``True`` if the JVM is running.
- **``jpype.getJVMVersion()``**: Retrieves the version of the running JVM.

Example:

.. code-block:: python

    if not jpype.isJVMStarted():
        print("JVM is not running!")
    else:
        print("JVM version:", jpype.getJVMVersion())

.. _controlling_the_jvm_common_issues_and_troubleshooting:

Common Issues and Troubleshooting
---------------------------------
1. **Classpath Errors**: Ensure that all required JAR files and directories are
   included in the classpath. Use ``java.lang.System.getProperty('java.class.path')``
   to verify the effective classpath.

2. **Architecture Mismatch**: Ensure the Python interpreter and JVM have
   matching architectures (e.g., both 64-bit or both 32-bit). Running a 64-bit
   Python interpreter with a 32-bit JVM will cause startup failures.

3. **Environment Variable Issues**: Verify that the ``JAVA_HOME`` environment
   variable is set correctly. If necessary, set it manually:
   - **Windows**: ``set JAVA_HOME=C:\Program Files\Java\jdk-<version>``
   - **Linux/Mac**: ``export JAVA_HOME=/usr/lib/jvm/java-<version>``

4. **Unrecognized JVM Options**: If you encounter errors for unrecognized JVM
   options, use the ``ignoreUnrecognized=True`` flag to suppress them.

5. **Memory Allocation Errors**: Ensure sufficient memory is allocated to the
   JVM using the ``-Xmx`` option.

6. **Debugging Startup Failures**: Enable stack traces for additional
   diagnostics:

.. code-block:: python

    import _jpype
    _jpype.enableStacktraces(True)


.. _controlling_the_jvm_best_practices_for_jvm_starting:

Best Practices for JVM starting
-------------------------------
- **Start Early**: Start the JVM at the beginning of your program to avoid
  issues with imports and initialization.
- **Specify Classpath Explicitly**: Use the ``classpath`` argument to ensure
  all required JAR files and directories are loaded.
- **Disable String Conversion**: Set ``convertStrings=False`` for better
  control and performance.
- **Avoid Restarting the JVM**: JPype does not support restarting the JVM after
  it has been shut down. Design your application to start the JVM once and keep
  it running for the program's lifetime.
- **Monitor Resource Usage**: If your application uses large Java objects,
  monitor memory usage to avoid out-of-memory errors.

.. _controlling_the_jvm_starting_the_jvm_summary:

Summary of JVM starting
-----------------------
Starting the JVM is a critical step in using JPype to integrate Python with
Java. By following the guidelines in this section, you can ensure a smooth
startup process, avoid common pitfalls, and configure the JVM to meet your
application's needs. Proper classpath configuration, architecture matching, and
memory allocation are key to successful integration. Debugging tools and best
practices are available to help troubleshoot issues and optimize performance.


.. _shutdownJVM:

Shutting Down the JVM
======================

At the end of your program, you may want to shut down the JVM to terminate the
Java environment explicitly. While this is possible, it is generally not
recommended unless absolutely necessary. JPype automatically shuts down the JVM
when the Python process terminates, ensuring a clean exit without manual
intervention.

.. _controlling_the_jvm_risks_of_shutting_down_the_jvm:

Risks of Shutting Down the JVM
------------------------------

Shutting down the JVM manually can lead to serious risks and instability,
especially if there are lingering Java references or shared resources. Once the
JVM is shut down, all Java objects become invalid, and any attempt to access
them will result in errors. This includes:

- **Lingering Java References**: Any Java objects held by Python will become
  invalid after the JVM is shut down. Accessing these objects will raise
  exceptions and could result in undefined behavior.

- **Shared Resources**: Shared resources such as buffers (e.g., memory mapped
  from Java to NumPy) will become unstable. Accessing these buffers after the
  JVM is shut down may cause crashes or memory corruption.

- **Proxies and Threads**: If Java threads or proxies are active when the JVM is
  shut down, they will be terminated abruptly, potentially leaving the system in
  an inconsistent state.

- **Non-Daemon Threads**: All threads must be attached as daemon threads before
  shutting down the JVM. Non-daemon threads will block the shutdown process,
  causing it to hang indefinitely. Python threads that interact with Java are
  automatically attached as daemon threads by JPype, but any custom threads
  created in Java must also be marked as daemon.

For most applications, it is safer to allow the JVM to shut down automatically
when the Python process exits. This ensures that all resources are cleaned up
properly and avoids the risks associated with manual shutdown.

.. _controlling_the_jvm_how_jpype_shuts_down_the_jvm:

How JPype Shuts Down the JVM
----------------------------

JPype performs the following steps during JVM shutdown to ensure proper cleanup:

1. **Request JVM Shutdown**: JPype requests the JVM to shut down gracefully.
2. **Wait for Non-Daemon Threads**: The JVM waits for all non-daemon threads to
   terminate. If you have active Java threads, ensure they are properly
   terminated or marked as daemon before shutting down the JVM.
3. **Execute Shutdown Hooks**: The JVM executes any registered shutdown hooks.
   These hooks can be used to clean up resources before the JVM terminates.
4. **Release JPype Reference Queue**: JPype shuts down its internal reference
   queue, which is responsible for dereferencing Python resources tied to Java
   objects.
5. **Release JPype Type Manager**: JPype releases its type manager, which
   handles mappings between Python and Java types.
6. **Unload JVM Shared Library**: The JVM shared library is unloaded, freeing
   memory used by the JVM.
7. **Finalize Python Resources**: JPype cleans up any remaining Python handles
   tied to Java objects, ensuring that no invalid references remain.

Once the JVM is shut down, all Java objects are considered dead and cannot be
reactivated. Any attempt to access their data field will raise an exception.

.. _controlling_the_jvm_managing_threads_during_jvm_shutdown:

Managing Threads During JVM Shutdown
------------------------------------

The JVM requires all threads to be attached as daemon threads during shutdown.
Daemon threads are background threads that do not prevent the JVM from
terminating. Non-daemon threads, on the other hand, will block the shutdown
process, causing it to hang indefinitely until those threads terminate.

JPype automatically attaches Python threads that interact with Java as daemon
threads. However, if you create custom threads in Java, you must explicitly mark
them as daemon threads to ensure they do not block the JVM shutdown.

To mark a Java thread as a daemon, use the following pattern:

.. code-block:: python

    import java.lang.Thread

    # Create a Java thread
    thread = java.lang.Thread()

    # Mark the thread as daemon
    thread.setDaemon(True)

    # Start the thread
    thread.start()

If you need to check whether a thread is a daemon, use the `isDaemon()` method:

.. code-block:: python

    print(f"Thread is daemon: {thread.isDaemon()}")

Ensure that all non-daemon threads are properly terminated or marked as daemon
before shutting down the JVM. Failure to do so may cause the shutdown process to
hang indefinitely.

.. _controlling_the_jvm_how_to_shut_down_the_jvm:

How to Shut Down the JVM
------------------------

If you must shut down the JVM manually, you can use the `jpype.shutdownJVM()`
function. This should only be called from the main Python thread. Calling it
from any other thread will raise an exception.

.. code-block:: python

    import jpype

    # Shut down the JVM
    jpype.shutdownJVM()


Numerous examples found on the internet explicity state that `shutdownJVM` is a
good practice.  These examples are legecy from early developement.  At the time
shutdownJVM brutally closed the JVM and bypassed all for the JVM shutdown routines
thus causing the program to skip over errors in the JPype module resulting
from mishandled race conditions.   While it is still acceptable to shutdown the
JVM and may be desireable to do so if a module needs a particular order to shutdown
cleanly, the use of an explicit shutdown is discouraged.


.. _controlling_the_jvm_debugging_jvm_shutdown:

Debugging JVM Shutdown
----------------------

If the JVM shutdown process hangs or fails, it is often due to lingering threads
or resources that were not properly terminated. Use the following techniques to
debug shutdown issues:

1. **Check Active Threads**: Before shutting down the JVM, check for active
   non-daemon threads that may be preventing the shutdown. You can use the
   following Java code to list all active threads:

   .. code-block:: python

       import java.lang.Thread

       # Get all active threads
       threads = java.lang.Thread.getAllStackTraces().keySet()
       for thread in threads:
           print(f"Thread: {thread.getName()}, Daemon: {thread.isDaemon()}")

   Ensure that all non-daemon threads are terminated or marked as daemon before
   calling `jpype.shutdownJVM()`.

2. **Inspect Shutdown Hooks**: If you have attached shutdown hooks, verify that
   they complete quickly and do not hang. Long-running shutdown hooks can delay
   or block JVM termination.

3. **Monitor Resource Usage**: If shared resources such as buffers are in use,
   ensure that they are properly released before shutting down the JVM. For
   example, copy buffer contents to a Python object to preserve data.

4. **Enable Debugging Logs**: JPype can provide additional diagnostics during
   the shutdown process. Use the following command to enable debugging logs:

   .. code-block:: python

       import _jpype
       _jpype.enableStacktraces(True)

   This will print detailed stack traces for exceptions that occur during the
   shutdown process.

5. **Handle Hanging Threads**: If the JVM shutdown hangs due to threads that
   cannot terminate, you can forcefully terminate the Python process using
   `os._exit()` or `java.lang.Runtime.exit()`. **However, note that calling
   `exit` will bypass normal `atexit` routines in both Python and Java.** This
   means that any cleanup tasks, such as writing logs (e.g., Jacoco coverage
   reports) or flushing buffers, will not be executed. Use this approach only
   as a last resort when all other debugging techniques fail.

.. _controlling_the_jvm_best_practices_for_jvm_shutdown:

Best Practices for JVM Shutdown
-------------------------------

- **Avoid Manual Shutdown**: Whenever possible, allow the JVM to shut down
  automatically when the Python process exits. This avoids the risks of lingering
  references and shared resource instability.

- **Terminate Threads Properly**: Ensure all non-daemon Java threads are
  terminated or marked as daemon before shutting down the JVM. Failure to do so
  may cause the shutdown process to hang indefinitely.

- **Handle Buffers Carefully**: If you are using shared buffers (e.g., Java
  direct buffers with NumPy), avoid accessing them after the JVM is shut down.
  If you need to preserve data, copy the buffer contents to a Python object
  before shutting down the JVM.

- **Use Shutdown Hooks**: Attach shutdown hooks only when necessary to clean up
  resources. Ensure that the hooks complete quickly to avoid delaying JVM
  termination.

- **Avoid Forceful Termination**: Avoid using `os._exit()` or `java.lang.Runtime.exit()`
  unless absolutely necessary. These methods prevent normal cleanup routines from
  executing, which can result in missing logs, incomplete resource cleanup, or
  other unintended consequences.


.. _controlling_the_jvm_summary_of_jvm_shutdown:

Summary of JVM Shutdown
------------------------

JPype's shutdown process is designed to ensure that resources are cleaned up
properly and the JVM terminates gracefully. While shutting down the JVM manually
is possible, it introduces risks that can lead to instability and crashes. For
most applications, the JVM should be allowed to shut down automatically when the
Python process exits. If manual shutdown is required, take precautions to ensure
that all Java references and shared resources are properly cleaned up before
shutting down the JVM. Avoid forceful termination unless absolutely necessary,
as it bypasses critical cleanup routines in both Python and Java.



.. _customization:

Customization
*************

JPype supports customization to enhance the integration between Java and Python.
This allows users to modify Java classes and type conversions to better suit
their needs, making Java APIs more Pythonic or enabling seamless interaction
with Python data structures.

There are two primary types of customizations available:

1. **Class Customizers**: Add Python methods and properties to Java classes to
   make them behave like native Python classes.
2. **Type Conversion Customizers**: Define implicit conversions between Python
   types and Java types for seamless interoperability.

.. _customization_class_customizers:

Class Customizers
=================

Customizers are applied to JPype wrapper classes to enhance their Pythonic
interface. By adding Python methods and properties to Java classes, customizers
make Java objects behave like native Python objects. These customizations are
applied to wrappers, whether they encapsulate a proxy or a Java reference.

Java wrappers can be customized to better match the expected behavior in Python.
Customizers are defined using decorators. Applying the annotations
``@JImplementationFor`` and ``@JOverride`` to a regular Python class will
transfer methods and properties to a Java class.

``@JImplementationFor`` requires the class name as a string, a Java class
wrapper, or a Java class instance. Only a string can be used prior to starting
the JVM. ``@JOverride``, when applied to a Python method, will hide the Java
implementation, allowing the Python method to replace the Java implementation.
When a Java method is overridden, it is renamed with a preceding underscore to
appear as a private method. Optional arguments to ``@JOverride`` can be used to
control the renaming and force the method override to apply to all classes that
derive from a base class ("sticky").

Generally speaking, a customizer should be defined before the first instance of
a given class is created so that the class wrapper and all instances will have
the customization.

.. _customization_example_customizing_javautilmap:

Example: Customizing ``java.util.Map``
--------------------------------------

The following example demonstrates how to customize the ``java.util.Map`` class
to behave like a Python dictionary:

.. code-block:: python

   @_jcustomizer.JImplementationFor('java.util.Map')
   class _JMap:
       def __jclass_init__(self):
           Mapping.register(self)

       def __len__(self):
           return self.size()

       def __iter__(self):
           return self.keySet().iterator()

       def __delitem__(self, i):
           return self.remove(i)

The name of the class does not matter for the purposes of the customizer,
though it should be a private class so that it does not get used accidentally.
The customizer code will steal from the prototype class rather than acting as a
base class, ensuring that the methods will appear on the most derived Python
class and are not hidden by the Java implementations.

The customizer copies methods, callable objects, ``__new__``, class member
strings, and properties.


.. _customization_type_conversion_customizers:

Type Conversion Customizers
===========================

JPype allows users to define custom conversion methods that are called whenever
a specified Python type is passed to a particular Java type. To specify a
conversion method, add ``@JConversion`` to an ordinary Python function with the
name of the Java class to be converted to and one keyword of ``exact`` or
``instanceof``. The keyword controls how strictly the conversion will be
applied:

- ``exact``: Restricted to Python objects whose type exactly matches the
  specified type.
- ``instanceof``: Accepts anything that matches ``isinstance`` to the specified
  type or protocol.

In some cases, the existing protocol definition will be overly broad. Adding
the keyword argument ``excludes`` with a type or tuple of types can be used to
prevent the conversion from being applied. Exclusions always apply first.

User-supplied conversions are tested after all internal conversions have been
exhausted and are always considered to be an implicit conversion.


.. _customization_example_converting_python_sequences_to_java_collections:

Example: Converting Python Sequences to Java Collections
--------------------------------------------------------

The following example demonstrates how to convert Python sequences into Java
collections:

.. code-block:: python

   @JConversion("java.util.Collection", instanceof=Sequence,
                             excludes=str)
   def _JSequenceConvert(jcls, obj):
       return _jclass.JClass('java.util.Arrays').asList(obj)

JPype supplies customizers for certain Python classes by default. These include:

========================= ==============================
Python class              Implicit Java Class
========================= ==============================
pathlib.Path              java.io.File
pathlib.Path              java.nio.file.Path
datetime.datetime         java.time.Instant
collections.abc.Sequence  java.util.Collection
collections.abc.Mapping   java.util.Map
========================= ==============================


.. _customization_jpype_beans_module:

JPype Beans Module
==================

.. _customization_overview_of_jpype_beans:

Overview of JPype Beans
-----------------------

The `jpype.beans` module is an optional feature that converts Java Bean-style
getter and setter methods into Python properties. This customization is
particularly useful for interactive programming or when working with Java
classes that follow the Bean pattern.

However, this behavior is not enabled by default because it can lead to
confusion about whether a class is exposing a variable or a property added by
JPype. Additionally, it violates Python's principle of *"There should be one--
and preferably only one --obvious way to do it."* and the C++ principle of
*"You only pay for what you use."*

If you find this feature useful, you can enable it explicitly by importing the
`jpype.beans` module.

.. _customization_enabling_beans_as_properties:

Enabling Beans as Properties
----------------------------

To enable the `jpype.beans` module, simply import it into your Python program:

.. code-block:: python

  import jpype.beans

Once enabled, the module applies globally to all Java classes that have already
been loaded, as well as any classes loaded afterward. This behavior cannot be
undone after the module is imported.

.. _customization_how_it_jpype_beans_works:

How It JPype beans Works
------------------------

The `jpype.beans` module scans Java classes for methods that follow the Bean
naming conventions:

- **Getter methods**: Methods prefixed with `get` (e.g., `getName`) are treated
  as property accessors.
- **Setter methods**: Methods prefixed with `set` (e.g., `setName`) are treated
  as property mutators.

For example, a Java class with the following methods:

.. code-block:: java

  public class Person {
      private String name;

      public String getName() {
          return name;
      }

      public void setName(String name) {
          this.name = name;
      }
  }

Will automatically expose the `name` field as a Python property:

.. code-block:: python

  import jpype
  import jpype.beans

  jpype.startJVM()

  Person = jpype.JClass("Person")
  person = Person()
  person.name = "Alice"  # Calls setName("Alice")
  print(person.name)     # Calls getName(), Output: Alice

.. _customization_implementation_details_of_jpype_beans:

Implementation Details of JPype beans
-------------------------------------

The module works by:

1. Identifying getter and setter methods in Java classes using the
   `_isBeanAccessor()` and `_isBeanMutator()` methods.
2. Creating Python properties for these methods.
3. Adding the properties to the class dynamically.

The customization applies retroactively to all classes currently loaded and
globally to all future classes.

.. _customization_limitations_of_jpype_beans:

Limitations of JPype beans
--------------------------

1. **Global Behavior**: Once enabled, the customization applies to all Java
   classes globally. It cannot be undone.
2. **Confusion with Existing Members**: If a Java class already has a Python
   member with the same name as a property, the property will not be added to
   avoid conflicts.
3. **Ambiguity**: This feature can make it unclear whether a field is a true
   Java variable or a property added by JPype.

.. _customization_best_practices_for_jpype_beans:

Best Practices for JPype beans
------------------------------

- Use this module only when working with Java classes that heavily rely on the
  Bean pattern.
- Avoid enabling this module in large projects unless absolutely necessary, as
  the global behavior may lead to unintended consequences.
- Document its usage clearly in your codebase to avoid confusion for other
  developers.

.. _customization_summary_of_jpype_beans:

Summary of JPype beans
----------------------

The `jpype.beans` module provides a convenient way to work with Java Bean-style
classes in Python by exposing getter and setter methods as Python properties.
While useful in certain scenarios, it is an optional feature that must be
explicitly enabled and should be used with caution due to its global and
irreversible behavior.

.. _customization_resolving_method_name_conflicts_with_customizers:

Resolving Method Name Conflicts with Customizers
================================================

.. _customization_overview_of_conflict_resolution:

Overview of conflict resolution
-------------------------------

When working with Java classes in Python, conflicts can arise between public
fields and methods that share the same name. JPype provides tools to resolve
these conflicts using customizers, allowing you to rename fields or methods
dynamically and expose them in a Pythonic way.

This section demonstrates how to use a customizer to resolve such conflicts by
renaming fields or methods and exposing them as Python properties.

.. _customization_example_renaming_conflicting_fields_and_methods:

Example: Renaming Conflicting Fields and Methods
------------------------------------------------

Consider a Java class with a field and a method that share the same name.
Without customization, JPype will expose the method, and the field will be
hidden. To resolve this, you can use a customizer to rename the conflicting
field or method and expose it as a Python property.

Here’s an example:

.. code-block:: python

    def asProperty(field):
        def get(E):
            return field.get(E)
        def set(E, V):
            field.set(E, V)
        return property(get, set)

    @jpype.JImplementationFor("java.lang.Object")  # Use your base class.
    class MyCustomizer(object):

        # This is applied to every class that derives from the type
        def __jclass_init__(cls):
            # Traverse the fields
            for field in cls.class_.getDeclaredFields():
                name = str(field.getName())
                tp = type(cls.__dict__.get(str(field.getName()), None))

                # Watch for private methods
                if tp is type(None):
                    continue

                # Resolve conflicts between public fields and methods
                if tp is jpype.JMethod:
                    cls._customize("%s_" % name, asProperty(field))

.. _customization_how_it_conflict_resolution_works:

How It Conflict Resolution Works
--------------------------------

1. **Field Traversal**: The customizer iterates over all declared fields in the
   class using `getDeclaredFields()`.
2. **Conflict Detection**: For each field, it checks whether a public method
   with the same name exists.
3. **Renaming**: If a conflict is detected, the field is renamed by appending
   an underscore (`_`) to its name.
4. **Property Creation**: The renamed field is exposed as a Python property
   using the `property()` function.

.. _customization_example_usage_of_conflict_resolution:

Example Usage of Conflict Resolution
------------------------------------

Suppose you have a Java class `A` with a field `mean` and a method `mean`.
Without customization, the field would be inaccessible. Using the customizer
above, you can expose the field as `mean_`:

.. code-block:: python

    A = jpype.JClass("A")
    a = A()
    print(a.mean_)  # Access the renamed field
    a.mean_ = 2      # Modify the field
    print(a.mean_)   # Verify the updated value

.. _customization_notes_on_global_customizers:

Notes on Global Customizers
---------------------------

- The customizer is applied globally to all classes that derive from the
  specified base class (`java.lang.Object` in this example). You can replace
  the base class with a more specific class to limit the scope of the
  customization.
- This approach is particularly useful for resolving conflicts in large Java
  libraries or frameworks where method and field names overlap frequently.

.. _customization_best_practices_regarding_name_resolution_customizers:

Best Practices Regarding Name Resolution Customizers
----------------------------------------------------

- Use meaningful naming conventions when renaming fields or methods to avoid
  confusion.
- Document customizations clearly in your codebase to help other developers
  understand the changes.
- Test the customizer thoroughly to ensure it behaves as expected across all
  relevant classes.

.. _customization_summary_of_naming_conflict_resolution:

Summary of Naming Conflict Resolution
-------------------------------------

This example demonstrates how to use JPype customizers to resolve conflicts
between fields and methods in Java classes. By renaming conflicting fields or
methods and exposing them as Python properties, you can create a more Pythonic
interface for interacting with Java classes.


.. _customization_best_practices_for_class_customization:

Best Practices For Class Customization
======================================

To ensure effective use of customizations, follow these best practices:

1. **Define Customizers Early**: Always define customizers before the first
   instance of the class is created to ensure proper initialization.

2. **Test Customizations Thoroughly**: Verify that the customized behavior
   works as expected, especially for complex or heavily-used classes.

3. **Avoid Conflicts**: Ensure that customizers do not introduce conflicting
   methods or properties, especially when customizing multiple interfaces.

4. **Monitor Performance**: Be mindful of performance implications when adding
   extensive customizations.

5. **Document Customizations**: Clearly document the purpose and behavior of
   customizations to assist other developers working on the codebase.

By leveraging class and type conversion customizers, JPype users can create
seamless integrations between Python and Java, making Java APIs feel native to
Python programmers.


.. _collections:

Collections
***********

JPype uses customizers to augment Java collection classes to operate like Python
collections. Enhanced objects include ``java.util.List``, ``java.util.Set``,
``java.util.Map``, and ``java.util.Iterator``. These classes generally comply
with the Python API except in cases where there is a significant name conflict.
This section details the integration of Java collections with Python constructs.

.. _collections_specialized_collection_wrappers:

Specialized Collection Wrappers
===============================

JPype customizes Java collection classes to behave like Python collections,
making them intuitive for Python developers. This includes support for iteration,
indexing, and key-value access. Below are the key behaviors of specific Java
collection types.

.. _collections_iterable:

Iterable
--------

Java classes that implement ``java.util.Iterable`` are customized to support
Python's iteration constructs. This allows seamless use in Python `for` loops
and list comprehensions. For example, a Java ``ArrayList`` can be iterated
directly:

.. code-block:: python

    from java.util import ArrayList

    jlist = ArrayList()
    jlist.add("apple")
    jlist.add("orange")
    jlist.add("banana")

    for item in jlist:
        print(item)

This integration ensures that Java collections behave like Python sequences,
providing a natural experience for Python developers.

.. _collections_iterators:

Iterators
---------

Java classes that implement ``java.util.Iterator`` act as Python iterators.
This means they can be used in Python `for` loops and list comprehensions
without requiring additional conversion. For example:

.. code-block:: python

    from java.util import Vector

    jvector = Vector()
    jvector.add("apple")
    jvector.add("orange")

    iterator = jvector.iterator()
    for item in iterator:
        print(item)

.. _collections_collection:

Collection
----------

Java classes that inherit from ``java.util.Collection`` integrate seamlessly
with Python's collection constructs. They support operations such as length
retrieval, iteration, and implicit conversion of Python sequences into Java
collections. For example:

.. code-block:: python

    from java.util import ArrayList

    pylist = ["apple", "orange", "banana"]
    jlist = ArrayList(pylist)  # Convert Python list to Java collection

    print(len(jlist))  # Output: 3
    for item in jlist:
        print(item)

Methods that accept Java collections can automatically convert Python sequences
if all elements are compatible with Java types. Otherwise, a ``TypeError`` is
raised.

.. _java.util.List:

Lists
-----

Java `List` classes, such as ``ArrayList`` and ``LinkedList``, can be used in
Python `for` loops and list comprehensions. They also support indexing and
deletion, making them behave like Python lists. For example:

.. code-block:: python

    from java.util import ArrayList

    jlist = ArrayList()
    jlist.add("apple")
    jlist.add("orange")
    jlist.add("banana")

    print(jlist[0])  # Output: apple
    del jlist[1]     # Remove "orange"
    print(jlist)     # Output: [apple, banana]

Java lists can also be converted to Python lists and vice versa using the copy
constructor. For example:

.. code-block:: python

    pylist = ["apple", "orange", "banana"]
    jlist = ArrayList(pylist)  # Convert Python list to Java list
    pylist2 = list(jlist)      # Convert Java list back to Python list

Note that individual elements remain Java objects when converted to Python.
Converting to Java will attempt to convert each argument
individually to Java.  If there is no conversion it will produce a
``TypeError``.  The conversion can be forced by casting to the appropriate
Java type with a list comprehension or by defining a new conversion
customizer.

Lists also have iterable, length, item deletion, and indexing.  Note that
indexing of ``java.util.LinkedList`` is supported but can have a large
performance penalty for large lists.  Use of iteration is much for efficient.


.. _java.util.Map:

Maps
----

Java classes that implement ``java.util.Map`` behave like Python dictionaries.
They support key-value access, iteration, and deletion. 
Here is a summary of their capabilities:

=========================== ================================
Action                       Python
=========================== ================================
Place a value in the map     ``jmap[key]=value``
Delete an entry              ``del jmap[key]``
Get the length               ``len(jmap)``
Lookup the value             ``v=jmap[key]``
Get the entries              ``jmap.items()``
Fetch the keys               ``jmap.key()``
Check for a key              ``key in jmap``
=========================== ================================

Example using Java HashMap with Pythonic interface:

.. code-block:: python

    from java.util import HashMap

    jmap = HashMap()
    jmap.put("key1", "value1")
    jmap.put("key2", "value2")

    print(jmap["key1"])  # Output: value1
    del jmap["key2"]     # Remove "key2"
    print(len(jmap))     # Output: 1

Maps also support iteration over keys and values:

.. code-block:: python

    for key, value in jmap.items():
        print(f"{key}: {value}")

Methods that accept Java maps can implicitly convert Python dictionaries if
all keys and values are compatible with Java types. Otherwise, a ``TypeError``
is raised.

.. _collections_map_entries:

Map Entries
-----------

Java map entries unpack into key-value pairs, allowing easy iteration in Python
loops. For example:

.. code-block:: python

    for key, value in jmap.items():
        print(f"{key}: {value}")

.. _collections_sets:

Sets
----

Java classes that implement ``java.util.Set`` behave like Python sets. They
support operations such as item deletion, iteration, and length retrieval. For
example:

.. code-block:: python

    from java.util import HashSet

    jset = HashSet()
    jset.add("apple")
    jset.add("orange")

    print(len(jset))  # Output: 2
    jset.remove("orange")
    print(jset)       # Output: [apple]

.. _collections_enumeration:

Enumeration
-----------

Java classes that implement ``java.util.Enumeration`` act as Python iterators.
This allows them to be used in Python `for` loops and list comprehensions. For
example:

.. code-block:: python

    from java.util import Vector

    jvector = Vector()
    jvector.add("apple")
    jvector.add("orange")

    enumeration = jvector.elements()
    for item in enumeration:
        print(item)


.. _collections_integrating_pythonic_constructs_with_java_collections:

Integrating Pythonic Constructs with Java Collections
======================================================

JPype enables Python developers to interact with Java collections and streams
while leveraging Python's idiomatic constructs, such as list comprehensions and
generator expressions. This section explores how Pythonic constructs and Java
methods can be used interchangeably or combined for efficient manipulation of
data structures.



.. _collections_using_pythonic_constructs_with_java_collections:

Using Pythonic Constructs with Java Collections
------------------------------------------------
JPype enables Python developers to interact with Java collections while
leveraging Python's idiomatic constructs, such as list comprehensions and
generator expressions. For example:

.. code-block:: python

    from java.util import ArrayList

    jlist = ArrayList()
    jlist.add("apple")
    jlist.add("orange")
    jlist.add("banana")

    filtered = [item.upper() for item in jlist if item.startswith("a")]
    print(filtered)  # Output: ['APPLE']

Combining Pythonic constructs with Java methods allows developers to use the
best tools for the task, whether they prefer Python's simplicity or Java's
robustness.


.. _collections_using_java_streams_for_functional_operations:

Using Java Streams for Functional Operations
---------------------------------------------

Java's `Stream` API provides powerful functional programming constructs, such
as `filter`, `map`, and `reduce`. JPype allows Python developers to use these
methods with Java collections, enabling them to leverage Java's robust
libraries.



.. _collections_example_filtering_and_mapping_with_java_streams:

Example: Filtering and Mapping with Java Streams
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   from java.util.stream import Collectors

   # Use Java Stream API for filtering and mapping
   filtered = jlist.stream().filter(lambda s: s.startswith("a")).map(
       lambda s: s.upper()).collect(Collectors.toList())
   print(filtered)  # Output: [APPLE]

Advantages of Java Streams:
- Integration with Java's enterprise libraries.
- Parallel processing capabilities (e.g., `.parallelStream()`).
- Type-safe operations with Java's generics.



.. _collections_comparison_pythonic_constructs_vs_java_methods:

Comparison: Pythonic Constructs vs Java Methods
------------------------------------------------

+---------------------------+---------------------------------------+
| **Feature**               | **Pythonic Constructs**               |
|                           | **(List Comprehensions)**             |
+---------------------------+---------------------------------------+
| Syntax                    | Concise and readable                  |
+---------------------------+---------------------------------------+
| Performance               | Python interpreter overhead           |
+---------------------------+---------------------------------------+
| Parallel Processing       | Requires external libraries           |
|                           | (e.g., `multiprocessing`)             |
+---------------------------+---------------------------------------+
| Type Safety               | Dynamic typing                        |
+---------------------------+---------------------------------------+
| Ease of Use               | Familiar to Python developers         |
+---------------------------+---------------------------------------+


.. _collections_combining_pythonic_constructs_and_java_methods:

Combining Pythonic Constructs and Java Methods
----------------------------------------------

JPype allows developers to mix Pythonic constructs and Java methods for maximum
flexibility. For example, you can use Java streams for complex operations and
Pythonic constructs for post-processing.


.. _collections_example_combining_streams_and_list_comprehensions:

Example: Combining Streams and List Comprehensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   # Use Java Stream API for filtering
   filtered_stream = jlist.stream().filter(lambda s: s.startswith("a")).collect(
       Collectors.toList())

   # Use Pythonic list comprehension for further processing
   final_result = [item.lower() for item in filtered_stream]
   print(final_result)  # Output: ['apple']


.. _collections_when_to_use_each_approach:

When to Use Each Approach
-------------------------

+-------------------------------------------+---------------------------+
| **Scenario**                              | **Recommended Approach**  |
+-------------------------------------------+---------------------------+
| Simple filtering or mapping               | Pythonic constructs       |
|                                           | (list comprehensions)     |
+-------------------------------------------+---------------------------+
| Complex operations (e.g., grouping,       | Java Streams              |
| reducing)                                 |                           |
+-------------------------------------------+---------------------------+
| Integration with Java enterprise          | Java Streams              |
| libraries                                 |                           |
+-------------------------------------------+---------------------------+
| Quick prototyping or debugging            | Pythonic constructs       |
+-------------------------------------------+---------------------------+
| Parallel processing                       | Java Streams              |
|                                           | (`parallelStream`)        |
+-------------------------------------------+---------------------------+



.. _collections_best_practices_for_collection_processing:

Best Practices for Collection Processing
----------------------------------------

1. **Choose the Right Tool for the Job**:
   - Use Pythonic constructs for simplicity and readability.
   - Use Java streams for performance-critical or enterprise applications.

2. **Leverage JPype's Seamlessness**:
   - Combine Pythonic constructs and Java methods to get the best of both worlds.

3. **Optimize for Performance**:
   - Avoid frequent back-and-forth calls between Python and Java. Cache results when possible.



.. _collections_conclusion_on_collection_processing:

Conclusion on Collection Processing
-----------------------------------

JPype enables Python developers to work with Java collections using both
Pythonic constructs and Java methods. Whether you prefer Python's simplicity or
Java's robustness, JPype provides the flexibility to choose the paradigm that
best fits your workflow.


.. _serialization_with_jpickler:

Serialization with JPickler
***************************

JPype provides the **JPickler** utility for serializing (`pickling`) Java objects
into Python-compatible byte streams. This is particularly useful for saving Java
objects to disk, transferring them between systems, or debugging their state.



.. _serialization_with_jpickler_why_use_jpickler:

Why Use JPickler?
=================

When working with Java objects in Python, serialization is often required for:

1. **Persistence**: Saving Java objects to files for later use.
2. **Data Exchange**: Transferring Java objects between Python applications or
   systems.
3. **Debugging**: Capturing the state of Java objects during execution for
   offline analysis.

However, Python's default `pickle` module does not support Java objects.
JPickler bridges this gap by encoding Java objects into a format compatible
with Python's serialization tools.



.. _serialization_with_jpickler_how_jpickler_works:

How JPickler Works
------------------

JPickler uses Java's `Serializable` interface to serialize Java objects into a
byte stream that can be stored or transferred. It also provides a companion
utility, **JUnpickler**, for deserializing these byte streams back into Java
objects.



.. _serialization_with_jpickler_example_1_basic_serialization:

Example 1: Basic Serialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The following example demonstrates how to serialize and deserialize Java
objects using JPickler and JUnpickler.

.. code-block:: python

    import jpype
    import jpype.imports
    from jpype.pickle import JPickler, JUnpickler

    # Start the JVM
    jpype.startJVM()

    # Create a Java object
    java_list = jpype.java.util.ArrayList()
    java_list.add("Hello")
    java_list.add("World")

    # Serialize the Java object to a file
    with open("serialized_java_list.pkl", "wb") as f:
        JPickler(f).dump(java_list)

    print("Java object serialized successfully!")

    # Deserialize the Java object from the file
    with open("serialized_java_list.pkl", "rb") as f:
        deserialized_list = JUnpickler(f).load()

    print("Deserialized Java object:", deserialized_list)
    # Output: [Hello, World]



.. _serialization_with_jpickler_example_2_serializing_complex_java_objects:

Example 2: Serializing Complex Java Objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

JPickler can handle any Java object that implements `java.io.Serializable`.
Here's an example with a custom Java class:

.. code-block:: java

    // Save this as MySerializableClass.java and compile it
    import java.io.Serializable;

    public class MySerializableClass implements Serializable {
        private String name;
        private int value;

        public MySerializableClass(String name, int value) {
            this.name = name;
            this.value = value;
        }

        @Override
        public String toString() {
            return "MySerializableClass{name='" + name + "', value=" + value + "}";
        }
    }

.. code-block:: python

    import jpype
    import jpype.imports
    from jpype.pickle import JPickler, JUnpickler

    # Start the JVM
    jpype.startJVM(classpath=["."])

    # Create an instance of the custom Java class
    MySerializableClass = jpype.JClass("MySerializableClass")
    java_object = MySerializableClass("TestObject", 42)

    # Serialize the Java object to a file
    with open("serialized_java_object.pkl", "wb") as f:
        JPickler(f).dump(java_object)

    print("Custom Java object serialized successfully!")

    # Deserialize the Java object from the file
    with open("serialized_java_object.pkl", "rb") as f:
        deserialized_object = JUnpickler(f).load()

    print("Deserialized Java object:", deserialized_object)
    # Output: MySerializableClass{name='TestObject', value=42}



.. _serialization_with_jpickler_best_practices_with_jpicker:

Best Practices with JPicker
===========================

1. **Ensure Objects Are Serializable**:

   - Only Java objects that implement `java.io.Serializable` can be serialized.
     Ensure your custom Java classes implement this interface.

2. **Validate Serialization**:

   - Test serialization and deserialization to ensure data integrity.

3. **Handle Non-Serializable Fields**:

   - If a Java object contains non-serializable fields, mark them as `transient`
     to exclude them during serialization.

4. **Avoid Reference Loops**:

   - Break reference loops between Python and Java objects to prevent memory
     leaks.


.. _serialization_with_jpickler_limitations_of_jpickler:

Limitations of JPickler
=======================

1. **Non-Serializable Objects**:

   - Java objects that do not implement `java.io.Serializable` cannot be
     serialized with JPickler.

2. **Cross-Version Compatibility**:

   - Serialized Java objects may not be compatible across different JVM
     versions.

3. **Performance**:

   - Serialization and deserialization can be resource-intensive for large or
     complex objects.


.. _serialization_with_jpickler_use_cases_of_jpickler:

Use Cases of JPickler
=====================

1. **Persistence**:

   - Save Java objects to disk for later use.

   - Example: Storing application state or configuration.

2. **Data Exchange**:

   - Transfer Java objects between Python applications or systems.

   - Example: Network communication or distributed systems.

3. **Debugging**:

   - Capture the state of Java objects during execution for offline analysis.

   - Example: Serialize problematic objects for inspection after a crash.


.. _serialization_with_jpickler_conclusion_for_jpicker:

Conclusion for JPicker
======================

JPickler simplifies serialization of Java objects in Python, enabling seamless
integration between the two ecosystems. By following best practices and
understanding its limitations, you can use JPickler effectively for
persistence, data exchange, and debugging tasks.


.. _working_with_numpy:

Working with NumPy
******************

JPype provides seamless integration between Python's NumPy library and Java,
enabling efficient data exchange and manipulation across both ecosystems. By
leveraging JPype's ability to transfer arrays bidirectionally, users can combine
NumPy's powerful numerical computing capabilities with Java's robust libraries
for machine learning, scientific computing, and enterprise applications. Whether
transferring data to NumPy for analysis or sending arrays to Java for processing,
JPype ensures high performance and compatibility with minimal overhead. This
integration is particularly useful for applications requiring large-scale
numerical computations or interoperability between Python and Java-based systems.


.. _working_with_numpy_transferring_arrays_between_python_and_java:

Transferring Arrays Between Python and Java
===========================================

JPype supports bidirectional transfers of arrays between Python (NumPy) and Java.
This allows seamless integration of numerical libraries with Java's ecosystem.



.. _working_with_numpy_transferring_arrays_to_numpy:

Transferring Arrays to NumPy
----------------------------

Java arrays can be transferred into NumPy arrays using Python's `memoryview`.
This enables efficient bulk data transfer for rectangular arrays.

**Example: Transferring a Java Array to NumPy**

.. code-block:: python

   import jpype
   import numpy as np

   # Start the JVM
   jpype.startJVM()

   # Create a Java array
   java_array = jpype.JDouble[:]([1.1, 2.2, 3.3])

   # Transfer the Java array to NumPy
   numpy_array = np.array(memoryview(java_array))

   print(numpy_array)  # Output: [1.1 2.2 3.3]

**Constraints**:
- The Java array must be rectangular. Jagged arrays are not supported.
- Only primitive types (e.g., `double`, `int`) are supported for direct transfer.



.. _working_with_numpy_transferring_arrays_to_java:

Transferring Arrays to Java
---------------------------

NumPy arrays can be transferred to Java using the `JArray.of` function. This maps
the structure of a NumPy array to a Java multidimensional array.

**Example: Transferring a NumPy Array to Java**

.. code-block:: python

   import jpype
   import numpy as np

   # Start the JVM
   jpype.startJVM()

   # Create a NumPy array
   numpy_array = np.zeros((5, 10, 20))  # 5x10x20 array filled with zeros

   # Transfer the array to Java
   java_array = jpype.JArray.of(numpy_array)

   print(java_array[0][0][0])  # Output: 0.0

**Constraints**:
- The NumPy array must be rectangular. Jagged arrays are not supported.
- Data types must be compatible with Java primitives (e.g., `np.float64` → `double`).



.. _working_with_numpy_requirements_and_constraints:

Requirements and Constraints
----------------------------

1. **Rectangular Arrays**:

   - Both NumPy and Java arrays must be rectangular for direct transfer.

2. **Data Type Compatibility**:

   - NumPy types must map to Java primitives (e.g., `np.int32` → `int`).

3. **Error Handling**:

   - Jagged arrays or incompatible types will raise a `TypeError`.



.. _working_with_numpy_best_practices_with_numpy:

Best Practices with NumPy
-------------------------

1. **Validate Array Structure**:
   - Ensure arrays are rectangular before transferring.

2. **Optimize Data Types**:
   - Use NumPy types that map directly to Java primitives for efficiency.

3. **Monitor Memory Usage**:
   - Large arrays can consume significant memory. Monitor resources carefully.



.. _working_with_numpy_summary_of_numpy:

Summary of NumPy
----------------

JPype provides efficient bidirectional array transfers between Python and Java.
By following the outlined constraints and best practices, users can achieve
seamless integration for numerical and scientific applications.


.. _working_with_numpy_buffer_backed_numpy_arrays:

Buffer Backed NumPy Arrays
==========================

Java direct buffers provide a mechanism for shared memory between Java and
Python, enabling high-speed data exchange by bypassing the JNI layer. These
buffers are particularly useful for applications requiring efficient handling
of large datasets, such as scientific computing or memory-mapped files.

Direct buffers are part of the Java ``nio`` package and can be accessed using
the ``jpype.nio`` module. NumPy arrays can be backed by Java direct buffers,
allowing Python and Java to operate on the same memory space. However, direct
buffers are not managed by the garbage collector, so improper use may lead to
memory leaks or crashes.


.. _working_with_numpy_creating_buffer_backed_arrays:

Creating Buffer Backed Arrays
-----------------------------

To create a buffer-backed NumPy array, you can either originate the buffer in
Java or Python. The following examples demonstrate both approaches:

**Example 1: Creating a Buffer in Java**

.. code-block:: python

   import jpype
   import numpy as np

   # Start the JVM
   jpype.startJVM()

   # Allocate a direct buffer in Java
   jb = java.nio.ByteBuffer.allocateDirect(80)  # Allocates 80 bytes
   db = jb.asDoubleBuffer()                     # Converts to a double buffer

   # Convert the buffer to a NumPy array
   np_array = np.asarray(db)                    # NumPy array backed by Java buffer
   print(np_array)

**Example 2: Creating a Buffer in Python**

.. code-block:: python

   import jpype
   import numpy as np

   # Start the JVM
   jpype.startJVM()

   # Create a Python bytearray
   py_buffer = bytearray(80)                    # Allocates 80 bytes
   jb = jpype.nio.convertToDirectBuffer(py_buffer)  # Maps the bytearray to Java
   db = jb.asDoubleBuffer()                     # Converts to a double buffer

   # Convert the buffer to a NumPy array
   np_array = np.asarray(db)                    # NumPy array backed by Python buffer
   print(np_array)


.. _working_with_numpy_important_considerations_for_buffer_backed_arrays:

Important Considerations for Buffer Backed Arrays
-------------------------------------------------

1. **Buffer Lifetime**:

   - Python and NumPy cannot detect when a Java buffer becomes invalid. Once the
     JVM is shut down, all buffers originating from Java become invalid, and any
     access to them may result in crashes.

   - To avoid this, create buffers in Python and pass them to Java, ensuring
     Python retains control over the memory.

2. **JVM Shutdown**:

   - If buffers are created in Java, consider using ``java.lang.Runtime.exit``
     to terminate both the Java and Python processes simultaneously. This
     prevents accidental access to dangling buffers.

3. **Applications**:

   - Buffer-backed memory is not limited to NumPy. It can be used for shared
     memory between processes, memory-mapped files, or any application requiring
     efficient data exchange.


.. _working_with_numpy_summary_of_buffer_backed_arrays:

Summary of Buffer Backed Arrays
-------------------------------

Buffer-backed NumPy arrays provide a powerful mechanism for high-speed data
exchange between Python and Java. However, users must carefully manage buffer
lifetimes and ensure proper handling during JVM shutdown to avoid crashes or
memory leaks.


.. _working_with_numpy_numpy_primitives:

Both Python and Java have a notion of readonly memory (bytes vs bytearray in
Python). ConvertToDirectBuffer will honor the the writability of the passed
object and return a readonly Java ByteBuffer if the source object is readonly.


NumPy Primitives
================

JPype provides seamless integration with NumPy, allowing efficient data
transfers between Python and Java. NumPy arrays can be mapped to Java boxed
types or primitive arrays. However, certain types, such as `np.float16`, are
converted to compatible Java types during transfer.

.. _working_with_numpy_supported_numpy_types:

Supported NumPy Types
---------------------

The following table summarizes how NumPy types are mapped to Java boxed types
and primitive arrays:

=================  ============================
NumPy Type         Java Type (Boxed/Primitive)
=================  ============================
np.int8            java.lang.Byte / byte[]
np.int16           java.lang.Short / short[]
np.int32           java.lang.Integer / int[]
np.int64           java.lang.Long / long[]
np.float16         java.lang.Float / float[] (*)
np.float32         java.lang.Float / float[]
np.float64         java.lang.Double / double[]
=================  ============================

(*) `np.float16` will be automatically converted to `float32` (`java.lang.Float`
or `float[]`) during the transfer to Java.

.. note::
   `np.float16` can be transferred to Java, but it will be automatically
   converted to `float32` (`java.lang.Float` for boxed types or `float[]` for
   primitive arrays) on the Java side. This is because Java does not natively
   support `float16`. If precise handling of `float16` is required, consider
   converting the data to `float32` or `float64` explicitly in Python before
   transferring it.

.. _working_with_numpy_examples:

Examples
--------

The following examples demonstrate how to transfer `np.float16` data to Java
as boxed types or primitive arrays.

.. _working_with_numpy_example_1_transferring_float16_to_a_boxed_type:

Example 1: Transferring `float16` to a Boxed Type
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   import jpype
   import numpy as np

   # Start the JVM
   jpype.startJVM()

   # Create a NumPy array with float16 data
   float16_array = np.array([1.1, 2.2, 3.3], dtype=np.float16)

   # Transfer the array to a Java boxed type (java.util.ArrayList)
   java_list = jpype.java.util.ArrayList()
   for value in float16_array:
       java_list.add(jpype.JFloat(value))  # Automatically converted to float32

   print(java_list)  # Output: [1.1, 2.2, 3.3] (as float32)

.. _working_with_numpy_example_2_transferring_float16_to_a_primitive_array:

Example 2: Transferring `float16` to a Primitive Array
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   import jpype
   import numpy as np

   # Start the JVM
   jpype.startJVM()

   # Create a NumPy array with float16 data
   float16_array = np.array([1.1, 2.2, 3.3], dtype=np.float16)

   # Transfer the array to a Java primitive array
   java_primitive_array = jpype.JArray(jpype.JFloat)(float16_array)  # Converted
                                                                     # to float32[]

   print(java_primitive_array)  # Output: [1.1, 2.2, 3.3] (as float32[])

.. _working_with_numpy_summary_of_numpy_automatic_converstions:

Summary of NumPy Automatic Converstions
---------------------------------------

JPype supports transferring NumPy arrays to Java, with automatic conversions
for certain types. While `np.float16` can be transferred, it is converted to
`float32` on the Java side for compatibility. Users should be aware of this
behavior and plan accordingly when working with `float16` data.


.. _Proxies:

Calling Python Code from Java
*****************************
Proxies in JPype enable Python objects to implement Java interfaces directly,
allowing seamless interaction between Python and Java. These proxies are
specifically designed to implement Java interfaces, acting as wrapper classes
that disguise the Python nature of the object in a Java type-safe manner.

In Java, proxies are foreign elements that pretend to implement a Java
interface. JPype leverages this proxy API to allow Python code to implement any
Java interface. While proxies allow Python objects to fulfill the contract of a
Java interface, they are not equivalent to subclassing Java classes in Python.

Fortunately, many Java APIs are designed to minimize the need for subclassing.
For example, frameworks like AWT and SWING allow developers to create complete
user interfaces without requiring a single subclass. Subclassing is typically
reserved for more advanced features or specialized use cases.

For those cases where sub-classing is absolutely necessary (i.e. using Java's
SAXP classes), it is necessary to create an interface and a simple
subclass in Java that delegates the calls to that interface.  The interface
can then be implemented in Python using a proxy.

There are three APIs for supporting of Java proxies. The direct method is to
pass a Python function, method, bound method, or lambda to any Java method
that accepts a FunctionInterface or other SAM.  If more complex behaviors
need to be exchanged Python can implement a Java interface. Implementation of an
interface uses decorators which features strong error checking and easy
notation.  The older low-level interface allows any Python object or dictionary
to act as a proxy even if it does not provide the required methods for the
interface.

.. _calling_python_code_from_java_passing_python_callables_to_java_functional_interfaces:

Passing Python Callables to Java Functional Interfaces
=======================================================

JPype supports passing Python functions, methods, and bound methods directly to
Java methods or fields that implement `FunctionalInterface`. This allows Python
code to seamlessly integrate with Java's functional programming constructs,
such as lambdas and method references, without requiring a proxy or explicit
implementation of the interface.

### Supported Use Cases

This feature works with any Java method or field that expects a
`FunctionalInterface`. Common examples include:
- Java Streams (`java.util.stream`)
- Java Executors (`java.util.concurrent`)
- Custom functional interfaces defined in Java code

### Example: Passing a Python Function to a Java Method

Suppose you have a Java method that expects a `java.util.function.Function`:

.. code-block:: java

    import java.util.function.Function;

    public class Example {
        public static String applyFunction(Function<String, String> func, String input) {
         return func.apply(input);
        }
    }

You can pass a Python function directly to this method:

.. code-block:: python

    import jpype import jpype.imports
    jpype.startJVM()

    from java.util.function import Function from Example import Example

    # Define a Python function
    def to_uppercase(s):
        return s.upper()

    # Pass the Python function to the Java method
    result = Example.applyFunction(to_uppercase, "hello")
    print(result)  #Output: HELLO

### Example: Using a Lambda Expression

Python lambdas can also be passed to Java methods:

.. code-block:: python

    # Pass a lambda expression
    result = Example.applyFunction(lambda s: s[::-1], "hello")
    print(result)  #Output: olleh

### Example: Using a Bound Method

Bound methods of Python objects can be passed as well:

.. code-block:: python

    class StringManipulator:
        def reverse(self, s):
            return s[::-1]

    manipulator = StringManipulator()
    result = Example.applyFunction(manipulator.reverse, "hello")
    print(result)  # Output: olleh

### Notes and Best Practices

1. **Performance**: While using Python callables is convenient, it may not be
as performant as implementing a full Java proxy for high-frequency calls. Use
proxies for performance-critical applications.

2. **Error Handling**: If an exception occurs within the Python callable, it
will be wrapped in a `RuntimeException` when passed back to Java.

3. **Type Matching**: Ensure that the Python callable returns a type compatible
with the expected Java return type. Implicit conversions will be applied where
possible.

By leveraging this feature, you can simplify integration between Python and
Java, especially when working with Java's functional programming APIs.


.. _@JImplements:

Implements
==========

The newer style of proxy works by decorating any ordinary Python class to
designate it as a proxy.  This is most effective when you
control the Python class definition.  If you don't control the class definition
you either need to encapsulate the Python object in another object or
use the older style.

Implementing a proxy is simple.  First construct an ordinary Python class with
method names that match the Java interface to be implemented.  Then add
the ``@JImplements`` decorator to the class definition.  The first argument
to the decorator is the interface to implement.  Then mark each
method corresponding to a Java method in the interface with ``@JOverride``.
When the proxy class is declared, the methods will be checked against the Java
interface.  Any missing method will result in JPype raising an exception.

High-level proxies have one other important behavior.  When a proxy created
using the high-level API returns from Java it unpacks back to the original
Python object complete with all of its attributes.  This occurs whether the
proxy is the ``self`` argument for a method or
proxy is returned from a Java container such as a list.  This is accomplished
because the actually proxy is a temporary Java object with no substance,
thus rather than returning a useless object, JPype unpacks the proxy
to its original Python object.

.. _calling_python_code_from_java_proxy_method_overloading:

Proxy Method Overloading
------------------------

Overloaded methods will issue to a single method with the matching name.  If
they take different numbers of arguments then it is best to implement a method
dispatch:

.. code-block:: python

    @JImplements(JavaInterface)
    class MyImpl:
        @JOverride
        def callOverloaded(self, *args):
            # always use the wild card args when implementing a dispatch
            if len(args)==2:
                return self.callMethod1(*args)
            if len(args)==1 and isinstance(args[0], JString):
                return self.callMethod2(*args)
            raise RuntimeError("Incorrect arguments")

       def callMethod1(self, a1, a2):
            # ...
       def callMethod2(self, jstr):
            # ...

.. _calling_python_code_from_java_multiple_interfaces:

Multiple interfaces
-------------------

Proxies can implement multiple interfaces as long as none of those interfaces
have conflicting methods.  To implement more than one interface, use a
list as the argument to the JImplements decorator.  Each interface must be
implemented completely.

.. _calling_python_code_from_java_deferred_realization:

Deferred realization
--------------------

Sometimes it is useful to implement proxies before the JVM is started.  To
achieve this, specify the interface using a string and add the keyword argument
``deferred`` with a value of ``True`` to the decorator.

.. code-block:: python

    @JImplements("org.foo.JavaInterface", deferred=True)
    class MyImpl:
        # ...


Deferred proxies are not checked at declaration time, but instead at the time
for the first usage.  Because of this, when uses an deferred proxy the code
must be able to handle initialization errors wherever the proxy is created.

Other than the raising of exceptions on creation, there is no penalty to
deferring a proxy class. The implementation is checked once on the first
usage and cached for the remaining life of the class.

.. _calling_python_code_from_java_proxy_factory:

Proxy Factory
=============

When a foreign object from another module for which you do not control the class
implementation needs to be passed into Java, the low level API is appropriate.
In this API you manually create a JProxy object.  The proxy object must either
be a Python object instance or a Python dictionary.  Low-level proxies use the
JProxy API.

.. _calling_python_code_from_java_jproxy:

JProxy
------

The ``JProxy`` allows Python code to "implement" any number of Java interfaces,
so as to receive callbacks through them.  The JProxy factory has the signature::

   JProxy(intr, [dict=obj | inst=obj] [, deferred=False])

The first argument is the interface to be implemented.  This may be either
a string with the name of the interface, a Java class, or a Java class instance.
If multiple interfaces are to be implemented the first argument is
replaced by a Python sequence.  The next argument is a keyword argument
specifying the object to receive methods.  This can either be a dictionary
``dict`` which names the methods as keys or an object instance ``inst`` which
will receive method calls.  If more than one option is selected, a ``TypeError``
is raised.  When Java calls the proxy the method is looked up in either
the dictionary or the instance and the resulting method is called.  Any
exceptions generated in the proxy will be wrapped as a ``RuntimeException``
in Java.  If that exception reaches back to Python it is unpacked to return
the original Python exception.

Assume a Java interface like:

.. code-block:: java

  public interface ITestInterface2
  {
          int testMethod();
          String testMethod2();
  }

You can create a proxy *implementing* this interface in two ways.
First, with an object:

.. code-block:: python

  class C:
      def testMethod(self):
          return 42

      def testMethod2(self):
          return "Bar"

  c = C()  # create an instance
  proxy = JProxy("ITestInterface2", inst=c)  # Convert it into a proxy

or you can use a dictionary.

.. code-block:: python

    def _testMethod():
        return 32

    def _testMethod2():
        return "Fooo!"

    d = { 'testMethod': _testMethod, 'testMethod2': _testMethod2, }
    proxy = JProxy("ITestInterface2", dict=d)

.. _calling_python_code_from_java_wrapping_a_python_instance_with_new_behaviors_for_java:

Wrapping a Python instance with new behaviors for Java
======================================================

JPype allows a JProxy to implement Java interfaces using a combination of a
dictionary (dict) and an object instance (inst). This feature enables arbitrary
Python objects to dynamically define methods via a dictionary while also
providing methods from the object's class. The combined approach is
particularly useful for cases where some methods are predefined in a Python
class and others need to be dynamically added or overridden.  This is useful when
the names and functionality of a Python object need to be made to conform to
Java's expected behaviors.

.. _calling_python_code_from_java_syntax:

Syntax
------
The JProxy factory supports both dict and inst as keyword arguments. When both are provided:

 * Methods in the dictionary take precedence.
 * The inst object is passed as the self argument to methods defined in the dictionary.
 * If a method is not found in the dictionary, JPype will fall back to the default method implementation in Java.

.. code-block:: python

    JProxy(interface, dict=my_dict, inst=my_instance)

Example: Combining dict and inst
Suppose you have a Java interface:

.. code-block:: java

    public interface MyInterface {
        String method1();
        String method2();
    }

You can implement this interface using both a dictionary and an object instance:

.. code-block:: python

    public interface MyInterface {
        String method1();
        default String method2() {
            return "hello";
        }
    }
    You can implement this interface using both a dictionary and an object instance:

    .. code-block:: python

    from jpype import JProxy

    class MyClass:
        def __init__(self, name):
            self.name = name

    # Define a dictionary with methods
    my_dict = {
        "method1": lambda self: f"Hello, {self.name} from method1"
    }

    # Create an instance of the class
    my_instance = MyClass("Alice")

    # Combine the dictionary and instance in a JProxy
    proxy = JProxy("MyInterface", dict=my_dict, inst=my_instance)

    # Use the proxy in Java
    print(proxy.method1())  # Output: Hello, Alice from method1
    print(proxy.method2())  # Falls back to Java's default method implementation


.. _calling_python_code_from_java_notes_and_best_practices:

Notes and Best Practices
------------------------
Method Resolution:

 * Methods in the dictionary take precedence over methods in the instance.

 * If a method is not found in the dictionary, JPype will attempt to resolve it in the
   instance.

Error Handling:

 * If neither the dictionary nor the instance provides the required method, a NotImplementedError will be raised.

Flexibility:

This approach allows dynamic addition or overriding of methods via the dictionary while retaining the benefits of object-oriented programming with the instance.

Example: Dynamic Overrides
You can dynamically override methods in the instance using the dictionary:

.. code-block:: python

    class MyClass:
        def __init__(self, name):
            self.name = name

    # Define a dictionary to override methods
    my_dict = {
        "method1": lambda self: f"Overridden method1 for {self.name}"
    }

    my_instance = MyClass("Bob")

    proxy = JProxy("MyInterface", dict=my_dict, inst=my_instance)

    print(proxy.method1())  # Output: Overridden method1 for Bob
    print(proxy.method2())  # Falls back to Java's default method implementation


.. _calling_python_code_from_java_proxying_python_objects:

Proxying Python objects
=======================

Sometimes it is necessary to push a Python object into Java memory space as an
opaque object.  This can be achieved using be implementing a proxy for
an interface which has no methods.  For example, ``java.io.Serializable`` has
no arguments and little functionality beyond declaring that an object can be
serialized. As low-level proxies to not automatically convert back to Python
upon returning to Java, the special keyword argument ``convert`` should be set
to True.

For example, let's place a generic Python object such as NumPy array into Java.

.. code-block:: python

    import numpy as np
    u = np.array([[1,2],[3,4]])
    ls = java.util.ArrayList()
    ls.add(jpype.JProxy(java.io.Serializable, inst=u, convert=True))
    u2 = ls.get(0)
    print(u is u2)  # True!

We get the expected result of ``True``.  The Python has passed through Java
unharmed.  In future versions of JPype, this method will be extended to provide
access to Python methods from within Java by implementing a Java interface that
points to back to Python objects.


.. _calling_python_code_from_java_reference_loops:

Reference Loops
===============

It is strongly recommended that object used in proxies must never hold a
reference to a Java container.  If a Java container is asked to hold a Python
object and the Python object holds a reference to the container, then a
reference loop is formed.  Both the Python and Java garbage collectors are
aware of reference loops within themselves and have appropriate handling for
them.  But the memory space of the other machine is opaque and neither Java nor
Python is aware of the reference loop.  Therefore, unless you manually break
the loop by either clearing the container, or removing the Java reference from
Python these objects can never be collected.  Once you lose the handle they
will both become immortal.

Ordinarily the proxy by itself would form a reference loop.  The Python
object points to a Java invocation handler and the invocation handler points
back to Python object to prevent the Python object from going away as long
as Java is holding onto the proxy.  This is resolved internally by making
the Python weak reference the Java portion.  If Java ever garbage collects
the Java half, it is recreated again when the proxy is next used.

This does have some consequences for the use of proxies.  Proxies must never
be used as synchronization objects.  Whenever
they are garbage collected, they lose their identity.  In addition, their
hashCode and system id both are reissued whenever they are refreshed.
Therefore, using a proxy as a Java map key can be problematic.  So long as
it remains in the Java map, it will maintain the same identify.  But once
it is removed, it is free to switch identities every time it is garbage
collected.

.. _awtswing:

AWT/Swing
*********

Java GUI elements can be used from Python.  To use Swing
elements the event loop in Java must be started from a user thread.
This will prevent the JVM from shutting down until the user thread
is completed.

Here is a simple example which creates a hello world frame and
launches it from within Python.

.. code-block:: python

    import jpype
    import jpype.imports

    jpype.startJVM()
    import java
    import javax
    from javax.swing import *

    def createAndShowGUI():
        frame = JFrame("HelloWorldSwing")
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
        label = JLabel("Hello World")
        frame.getContentPane().add(label)
        frame.pack()
        frame.setVisible(True)

    # Start an event loop thread to handling gui events
    @jpype.JImplements(java.lang.Runnable)
    class Launch:
        @jpype.JOverride
        def run(self):
            createAndShowGUI()
    javax.swing.SwingUtilities.invokeLater(Launch())



.. _concurrent_processing:

Concurrent Processing
*********************

This chapter covers the topic of threading, synchronization, and multiprocess.
Much of this material depends on the use of Proxies_ covered in the prior
chapter.

.. _concurrent_processing_threading:

Threading
=========

JPype supports all types of threading subject to the restrictions placed by
Python.  Java is inherently threaded and support a vast number of threading
styles such as execution pools, futures, and ordinary thread.  Python is
somewhat more limited.  At its heart Python is inherently single threaded
and requires a master lock known as the GIL (Global Interpreter Lock) to
be held every time a Python call is made.  Python threads are thus more
cooperative that Java threads.

To deal with this behavior, JPype releases the GIL every time it leaves from
Python into Java to any user defined method.  Shorter defined calls such as
to get a string name from from a class may not release the GIL.  Every time
the GIL is released it is another opportunity for Python to switch to a different
cooperative thread.

.. _concurrent_processing_threading_python_threads:

Python Threads
--------------

For the most part, Python threads based on OS level threads (i.e. POSIX
threads) will work without problem. The only challenge is how Java sees threads.
In order to operate on a Java method, the calling thread must be attached to
Java.  Failure to attach a thread will result in a segmentation fault.  It used
to be a requirement that users manually attach their thread to call a Java
function, but as the user has no control over the spawning of threads by other
applications such as an IDE, this inevitably lead to unexpected segmentation
faults.  Rather that crashing randomly, JPype automatically attachs any
thread that invokes a Java method.  These threads are attached automatically as
daemon threads so that will not prevent the JVM from shutting down properly
upon request.  If a thread must be attached as a non-daemon, use the method
``java.lang.Thread.attach()`` from within the thread context.  Once this is
done the JVM will not shut down until that thread is completed.

There is a function called ``java.lang.Thread.isAttached()`` which will check
if a thread is attached.  As threads automatically attach to Java, the only
way that a thread would not be attached is if it has never called a Java method.

The downside of automatic attachment is that each attachment allocates a
small amount of resources in the JVM.  For applications that spawn frequent
dynamically allocated threads, these threads will need to be detached prior
to completing the thread with ``java.lang.Thread.detach()``.  When
implementing dynamic threading, one can detach the thread
whenever Java is no longer needed.  The thread will automatically reattach if
Java is needed again.  There is a performance penalty each time a thread is
attached and detached.

.. _concurrent_processing_threading_java_threads:

Java Threads
------------

To use Java threads, create a Java proxy implementins
``java.lang.Runnable``.  The Runnable can then be passed any Java threading
mechanism to be executed.  Each time that Java threads transfer control
back to Python, the GIL is reacquired.

.. _concurrent_processing_threading_other_threads:

Other Threads
-------------

Some Python libraries offer other kinds of thread, (i.e. microthreads). How
they interact with Java depends on their nature. As stated earlier, any OS-
level threads will work without problem. Emulated threads, like microthreads,
will appear as a single thread to Java, so special care will have to be taken
for synchronization.


.. _concurrent_processing_customizing_javalangthread:

Customizing java.lang.Thread
============================

.. _concurrent_processing_overview:

Overview
--------

JPype automatically attaches Python threads to the JVM when they interact with
Java resources. Threads are attached as daemon threads to ensure that they do
not block JVM shutdown. While this behavior simplifies integration, it can lead
to resource leaks in thread-heavy applications if threads are not properly
detached when they terminate.

To address this, JPype customizes `java.lang.Thread` with additional methods
for managing thread attachment and detachment. These methods allow developers
to explicitly detach threads, freeing resources in the JVM and preventing leaks.

.. _concurrent_processing_customized_methods:

Customized Methods
------------------

The following methods are added to `java.lang.Thread` by JPype:

.. method:: java.lang.Thread.attach()

   Attaches the current thread to the JVM as a user thread.

   User threads prevent the JVM from shutting down until they are terminated or
   detached. This method can be used to convert a daemon thread to a user
   thread.

   **Raises**:
     - `RuntimeError`: If the JVM is not running.

.. method:: java.lang.Thread.attachAsDaemon()

   Attaches the current thread to the JVM as a daemon thread.

   Daemon threads act as background tasks and do not prevent the JVM from
   shutting down. JPype automatically attaches threads as daemon threads when
   they interact with Java resources. Use this method to explicitly attach a
   thread as a daemon.

   **Raises**:
     - `RuntimeError`: If the JVM is not running.

.. method:: java.lang.Thread.detach()

   Detaches the current thread from the JVM.

   This method frees the associated resources in the JVM for the current thread.
   It is particularly important for thread-heavy applications to prevent leaks.
   Detaching a thread does not interfere with its ability to reattach later.

   **Notes**:
     - This method cannot fail and is safe to call even if the JVM is not
       running.
     - There is no harm in calling this method multiple times or detaching
       threads early.

.. _concurrent_processing_examples_with_java_thread:

Examples with Java Thread
-------------------------

Here are examples of how to use the customized methods for `java.lang.Thread`:

.. code-block:: python

   import jpype
   import jpype.imports

   jpype.startJVM()

   # Attach the thread as a user thread
   java.lang.Thread.attach()
   print("Thread attached as a user thread.")

   # Perform Java operations here...

   # Detach the thread after completing Java operations
   java.lang.Thread.detach()
   print("Thread detached from the JVM.")

   # Attach the thread as a daemon thread
   java.lang.Thread.attachAsDaemon()
   print("Thread attached as a daemon thread.")

.. _concurrent_processing_best_practices_for_java_thread:

Best Practices for Java Thread
------------------------------

- **Detach Threads When They End**: For thread-heavy applications, ensure that
  Python threads detach themselves from the JVM before they terminate. This
  prevents resource leaks and ensures efficient memory usage.

- **Avoid Excessive Attachments**: While JPype automatically attaches threads,
  excessive thread creation without proper detachment can lead to resource
  exhaustion in the JVM.

- **Detach Early**: Detaching threads early, after completing all Java
  operations, is safe and does not interfere with reattachment later. This is
  especially important for applications that spawn many short-lived threads.

- **Monitor Resource Usage**: Regularly monitor JVM memory usage in
  thread-heavy applications to identify potential leaks caused by lingering
  thread attachments.

.. _concurrent_processing_summary_of_java_thread:

Summary of Java Thread
----------------------

JPype customizes `java.lang.Thread` to provide additional methods for managing
thread attachment and detachment to/from the JVM. While JPype automatically
attaches threads as daemon threads, it is crucial to detach threads explicitly
in thread-heavy applications to prevent resource leaks. By following best
practices, developers can ensure efficient memory usage and smooth integration
between Python and Java.


.. _synchronized:

Synchronization
===============

Java synchronization support can be split into two categories. The first is the
``synchronized`` keyword, both as prefix on a method and as a block inside a
method. The second are the three methods available on the Object class
(``notify, notifyAll, wait``).

To support the ``synchronized`` functionality, JPype defines a method called
``synchronized(obj)`` to be used with the Python ``with`` statement, where
obj has to be a Java object. The return value is a monitor object that will
keep the synchronization on as long as the object is kept alive.  For example,

.. code-block:: python

    from jpype import synchronized

    mySharedList = java.util.ArrayList()

    # Give the list to another thread that will be adding items
    otherThread.setList(mySharedList)

    # Lock the list so that we can access it without interference
    with synchronized(mySharedList):
        if not mySharedList.isEmpty():
            ...  # process elements
    # Resource is unlocked once we leave the block

The Python ``with`` statement is used to control the scope.  Do not
hold onto the monitor without a ``with`` statement.  Monitors held outside of a
``with`` statement will not be released until they are broken when the monitor
is garbage collected.

The other synchronization methods are available as-is on any Java object.
However, as general rule one should not use synchronization methods on Java
String as internal string representations may not be complete objects.

For synchronization that does not have to be shared with Java code, use
Python's support directly rather than Java's synchronization to avoid
unnecessary overhead.


.. _concurrent_processing_threading_examples:

Threading examples
==================

Java provides a very rich set of threading tools.  This can be used in Python
code to extend many of the benefits of Java into Python.  However, as Python
has a global lock, the performance of Java threads while using Python is not
as good as native Java code.

.. _concurrent_processing_limiting_execution_time:

Limiting execution time
-----------------------

We can combine proxies and threads to produce achieve a number of interesting
results.  For example:

.. code-block:: python

    def limit(method, timeout):
        """ Convert a Java method to asynchronous call with a specified timeout. """
        def f(*args):
            @jpype.JImplements(java.util.concurrent.Callable)
            class g:
                @jpype.JOverride
                def call(self):
                    return method(*args)
            future = java.util.concurrent.FutureTask(g())
            java.lang.Thread(future).start()
            try:
                timeunit = java.util.concurrent.TimeUnit.MILLISECONDS
                return future.get(int(timeout*1000), timeunit)
            except java.util.concurrent.TimeoutException as ex:
                future.cancel(True)
            raise RuntimeError("canceled", ex)
        return f

    print(limit(java.lang.Thread.sleep, timeout=1)(200))
    print(limit(java.lang.Thread.sleep, timeout=1)(20000))

Here we have limited the execution time of a Java call.


.. _concurrent_processing_multiprocessing:

Multiprocessing
===============

Because only one JVM can be started per process, JPype cannot be used with
processes created with ``fork``.  Forks copy all memory including the JVM.  The
copied JVM usually will not function properly thus JPype cannot support
multiprocessing using fork.

To use multiprocessing with JPype, processes must be created with "spawn".  As
the multiprocessing context is usually selected at the start and the default
for Unix is fork, this requires the creating the appropriate spawn context.  To
launch multiprocessing properly the following recipe can be used.

.. code-block:: python

   import multiprocessing as mp

   ctx = mp.get_context("spawn")
   process = ctx.Process(...)
   queue = ctx.Queue()
   # ...

When using multiprocessing, Java objects cannot be sent through the default
Python ``Queue`` methods as calls pickle without any Java support.  This can be
overcome by wrapping Python ``Queue`` to first encode to a byte stream using
the JPickle package.  By wrapping a ``Queue`` with the Java pickler any
serializable Java object can be transferred between processes.

In addition, a standard Queue will not produce an error if is unable to pickle
a Java object.  This can cause deadlocks when using multiprocessing IPC, thus
wrapping any Queue is required.


.. _managing_crossplatform_gui_environments:

Managing Cross-Platform GUI Environments
****************************************

JPype provides utility functions, `setupGuiEnvironment` and
`shutdownGuiEnvironment`, to manage GUI environments across platforms,
ensuring compatibility with macOS, Linux, and Windows. These functions are
particularly useful for Swing and JavaFX-based applications, where macOS
imposes specific requirements for GUI event loops. Even on Linux and Windows,
using `setupGuiEnvironment` ensures consistent behavior and avoids potential
issues with threading and event loops.

.. _managing_crossplatform_gui_environments_setupguienvironmentcb:

setupGuiEnvironment(cb)
=======================

**Description**:

`setupGuiEnvironment` ensures that GUI applications can run correctly across
all platforms. It is specifically designed to address macOS's requirement for
the main thread to run the event loop, but it is also recommended for Swing
and JavaFX applications on Linux and Windows to maintain cross-platform
compatibility and proper threading behavior.

**Parameters**:

- **cb**: A callback function that initializes and launches the GUI application.

**Behavior**:

- **macOS**:
  - Creates a Java thread using a `Runnable` proxy.
  - Starts the macOS event loop using `PyObjCTools.AppHelper.runConsoleEventLoop()`.

- **Other Platforms (Linux, Windows)**:
  - Executes the callback function directly.

**Why Use This Function for Swing and JavaFX Applications?**

Swing and JavaFX applications often rely on proper threading and event loop
management to function correctly. While macOS has strict requirements for
running the event loop on the main thread, using `setupGuiEnvironment` on
Linux and Windows ensures consistent behavior and avoids potential threading
issues, such as race conditions or improper GUI updates.

**Example**:

.. code-block:: python

    from jpype import setupGuiEnvironment
    from javafx.application import Platform

    def say_hello_later():
        """Test function for scheduling a task on the JavaFX Application Thread."""
        print("Hello from JavaFX!")

    def launch_gui():
        """Launch the GUI application."""
        # Example: Schedule a task on the JavaFX Application Thread
        Platform.runLater(say_hello_later)
        print("GUI launched")

    # Use setupGuiEnvironment to ensure cross-platform compatibility
    setupGuiEnvironment(launch_gui)

.. _managing_crossplatform_gui_environments_reestablishing_an_interactive_shell_on_another_thread:

Reestablishing an Interactive Shell on Another Thread
=====================================================

When using `setupGuiEnvironment`, the main thread may be occupied by the GUI
event loop (particularly on macOS). To allow interactive debugging in Python,
you can launch an interactive shell (e.g., IPython) on a separate thread.

**Steps**:

1. Use `setupGuiEnvironment` to start the GUI application.
2. Launch an interactive shell on a separate thread using Python's `threading`
   module.

**Example**:

.. code-block:: python

    import threading
    import IPython

    def launch_interactive_shell():
        """Launch an interactive shell on a separate thread."""
        IPython.embed()

    # Start the interactive shell on another thread
    thread = threading.Thread(target=launch_interactive_shell)
    thread.start()

By combining this approach with `setupGuiEnvironment`, you can interact with
the Python environment while the GUI application is running.

.. _managing_crossplatform_gui_environments_shutdownguienvironment:

shutdownGuiEnvironment()
========================

**Description**:

`shutdownGuiEnvironment` is used to cleanly terminate the macOS event loop. On
other platforms, it performs no action.

**Behavior**:

- **macOS**:
  - Stops the macOS event loop using `PyObjCTools.AppHelper.stopEventLoop()`.

- **Other Platforms (Linux, Windows)**:
  - No action is taken.

**Example**:

.. code-block:: python

    from jpype import shutdownGuiEnvironment

    # Shutdown the GUI environment (macOS-specific)
    shutdownGuiEnvironment()

.. _managing_crossplatform_gui_environments_best_practices_on_guis:

Best Practices on GUIs
--------------------------

- **Use `setupGuiEnvironment` for All Platforms**:
  Even though macOS has specific requirements, using `setupGuiEnvironment`
  ensures consistent behavior across all platforms, particularly for Swing
  and JavaFX applications.

- **Thread Safety**:
  Always schedule GUI updates using JavaFX's `Platform.runLater` or Swing's
  `SwingUtilities.invokeLater` to ensure they occur on the appropriate thread.

- **Interactive Debugging**:
  Launch an interactive shell on a separate thread for debugging while the GUI
  application is running.

- **Exception Handling**:
  Wrap callback functions in `try-except` blocks to prevent unhandled
  exceptions from disrupting the GUI.

- **Cross-Platform Testing**:
  Test the application on macOS, Linux, and Windows to ensure compatibility.

.. _managing_crossplatform_gui_environments_summary_of_guis:

Summary of GUIs
===============

The `setupGuiEnvironment` function is a critical tool for managing GUI
environments across platforms, particularly for Swing and JavaFX-based
applications. It ensures compatibility with macOS's event loop requirements
while maintaining simplicity on other platforms. Combined with the ability to
launch an interactive shell on a separate thread, this approach provides a
robust solution for developing and debugging GUI applications in Python.


.. _miscellaneous_topics:

Miscellaneous topics
********************

This chapter contains all the stuff that did not fit nicely into the narrative
about JPype.  Topics include database interfacing, code completion, performance,
debugging Java within JPype, debugging JNI and other JPype failures, how caller sensitive
methods are dealt with, and finally limitations of JPype.


.. _miscellaneous_topics_database_access_with_jpypedbapi2:

Database Access with `jpype.dbapi2`
===================================

JPype provides the `jpype.dbapi2` module, which allows Python applications to
interact with Java-based database drivers using the Python Database API
Specification (PEP 249). This module bridges Python and Java, enabling seamless
access to databases that lack native Python drivers but provide JDBC drivers.

.. _miscellaneous_topics_key_features_of_dbapi2:

Key Features of dbapi2
----------------------
- **PEP 249 Compliance**: Implements the Python Database API Specification for
  standardized database interaction.
- **JDBC Integration**: Uses Java's JDBC (Java Database Connectivity) to connect
  to databases.
- **Cross-Platform**: Supports any database with a JDBC driver, including
  enterprise databases like Oracle, DB2, and SQL Server.

.. _miscellaneous_topics_prerequisites_for_dbapi2:

Prerequisites for dbapi2
------------------------
- Ensure the JVM is started with the appropriate classpath for the JDBC driver.
- Obtain the JDBC driver for the target database and include its path in the
  `classpath`.

.. _miscellaneous_topics_example_usage_of_dbapi2:

Example Usage of dbapi2
-----------------------
.. code-block:: python

    import jpype
    import jpype.dbapi2 as dbapi2

    # Start the JVM with the JDBC driver
    jpype.startJVM(classpath=["path/to/jdbc/driver.jar"])

    # Connect to the database
    connection = dbapi2.connect(
        "jdbc:database_url",  # JDBC URL for the database
        {"user": "username", "password": "password"}  # Connection properties
    )

    # Create a cursor and execute a query
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM my_table")

    # Fetch and process results
    results = cursor.fetchall()
    for row in results:
        print(row)

    # Close the cursor and connection
    cursor.close()
    connection.close()

    # Shut down the JVM
    jpype.shutdownJVM()


.. _miscellaneous_topics_benefits_of_dbapi2:

Benefits of dbapi2
------------------
- Access databases that lack native Python drivers but provide JDBC drivers.
- Leverage advanced features of Java-based database drivers.
- Maintain compatibility with Python's standard database API.


.. _miscellaneous_topics_limitations_of_dbapi2:

Limitations of dbapi2
----------------------
- Requires a running JVM, which may introduce overhead compared to native Python
  database drivers.
- Performance may be slightly impacted due to Python-Java interaction.

.. _miscellaneous_topics_use_cases_of_dbapi2:

Use Cases of dbapi2
-------------------
- Connecting to enterprise databases like Oracle, SQL Server, or DB2.
- Utilizing advanced capabilities of JDBC drivers within Python applications.


.. _miscellaneous_topics_javadoc:

Javadoc
=======

JPype can display javadoc in ReStructured Text as part of the Python
documentation.  To access the javadoc, the javadoc package must be located on
the classpath.  This includes the JDK package documentation.

For example to get the documentation for ``java.lang.Class``, we start the JVM
with the JDK documentation zip file on the classpath.

.. code-block: java

     import jpype
     jpype.startJVM(classpath='jdk-11.0.7_doc-all.zip')

We can then access the java docs for the String with ``help(java.lang.String)``
or for the methods with ``help(java.lang.String.trim)``.  To use the javadoc
supplied by a third party include the both the jar and javadoc in the
classpath.

.. code-block: java

     import jpype
     jpype.startJVM(classpath=['gson-2.8.5.jar', 'gson-2.8.5-javadoc.jar'])

The parser will ignore any javadoc which cannot be extracted.  It has some
robustness against tags that are not properly closed or closed twice.  Javadoc
with custom page layouts will likely not be extracted.

If javadoc for a class cannot be located or extracted properly, default
documentation will be generated using Java reflection.

.. _miscellaneous_topics_autopep8:

Autopep8
========

When Autopep8 is applied a Python script, it reorganizes the imports to conform
to E402_. This has the unfortunate side effect of moving the Java imports above
the startJVM statement.  This can be avoided by either passing in ``--ignore
E402`` or setting the ignore in ``.pep8``.

.. _E402: https://www.flake8rules.com/rules/E402.html

Example:

.. code-block:: python

        import jpype
        import jpype.imports

        jpype.startJVM()

        from gov.llnl.math import DoubleArray


Result without ``--ignore E402``

.. code-block:: python

        from gov.llnl.math import DoubleArray  # Fails, no JVM running
        import jpype
        import jpype.imports

        jpype.startJVM()


.. _miscellaneous_topics_performance:

Performance
===========

JPype uses JNI, which is well known in the Java world as not being the most
efficient of interfaces. Further, JPype bridges two very different runtime
environments, performing conversion back and forth as needed. Both of these
can impose performance bottlenecks.

JNI is the standard native interface for most, if not all, JVMs, so there is
no getting around it. Down the road, it is possible that interfacing with CNI
(GCC's Java native interface) may be used. Right now, the best way to reduce
the JNI cost is to move time critical code over to Java.

Follow the regular Python philosophy : **Write it all in Python, then write
only those parts that need it in C.** Except this time, it's write the parts
that need it in Java.

Everytime an object is passed back and forth, it will incure a conversion
cost.. In cases where a given object (be it a string, an object, an array, etc
...) is passed often into Java, the object should be converted once and cached.
For most situations, this will address speed issues.

To improve speed issues, JPype has converted all of the base classes into
CPython.  This is a very significant speed up over the previous versions of
the module.  In addition, JPype provides a number of fast buffer transfer
methods. These routines are triggered automatically working with any buffer
aware class such as those in NumPy.

As a final note, while a JPype program will likely be slower than its pure
Java counterpart, it has a good chance of being faster than the pure Python
version of it. The JVM is a memory hog, but does a good job of optimizing
code execution speeds.


.. _miscellaneous_topics_code_completion:

Code completion
===============

Python supports a number of different code completion engines that are
integrated in different Python IDEs.  JPype has been tested with both the
IPython greedy completion engine and Jedi.  Greedy has the disadvantage
that is will execute code resulting potentially resulting in an undesirable
result in Java.

JPype is Jedi aware and attempts to provide whatever type information that
is available to Jedi to help with completion tasks.  Overloaded methods are
opaque to Jedi as the return type cannot be determined externally.  If all of
the overloads have the same return type, the JPype will add the return type
annotation permitting Jedi to autocomplete through a method return.

For example:

.. code-block:: python

        JString("hello").substring.__annotations__
        # Returns {'return': <java class 'java.lang.String'>}

Jedi can manually be tested using the following code.

.. code-block:: python

        js = JString("hello")
        src = 'js.s'
        script = jedi.Interpreter(src, [locals()])
        compl = [i.name for i in script.completions()]

This will produce a list containing all method and field that begin with
the letter "s".

JPype has not been tested with other autocompletion engines such as Kite.


.. _miscellaneous_topics_garbage_collection:

Garbage collection
==================

Garbage collection (GC) is supposed to make life easier for the programmer by
removing the need to manually handle memory.  For the most part it is a good
thing.  However, just like running a kitchen with two chiefs is a bad idea,
running with two garbage collections is also bad.  In JPype we have to contend
with the fact that both Java and Python provide garbage collection for their
memory and neither provided hooks for interacting with an external garbage
collector.

For example, Python is creating a bunch a handles to Java memory for a
period of time but they are in a structure with a reference loop internal to
Python.  The structures and handles are small so Python doesn't see an issue,
but each of those handles is holding 1M of memory in Java space.  As the heap
fills up Java begins garbage collecting, but the resources can't be freed
because Python hasn't cleanup up these structures.  The reverse occurs if a
proxy has any large NumPy arrays.  Java doesn't see a problem as it has plenty
of space to work in but Python is running its GC like mad trying to free up
space to work.

To deal with this issue, JPype links the two garbage collectors.  Python is
more aggressive in calling GC than Java and Java is much more costly than
Python in terms of clean up costs.  So JPype manages the balance.  JPype
installs a sentinel object in Java.  Whenever that sentinel is collected Java
is running out of space and Python is asked to clean up its space as well.  The
reverse case is more complicated as Python can't just call Java's expensive
routine any time it wants.  Instead JPype maintains a low-water and high-water
mark on Python owned memory.  Each time it nears a high-water mark during a
Python collection, Java GC gets called.  If the water level shrinks than
Java was holding up Python memory and the low-water mark is reset.
Depending on the amount of memory being exchanged the Java GC may trigger
as few as once every 50 Python GC cycles or as often as every other.
The sizing on this is dynamic so it should scale to the memory use of
a process.


.. _miscellaneous_topics_using_jpype_for_debugging_java_code:

Using JPype for debugging Java code
===================================

One common use of JPype is to function as a Read-Eval-Print Loop for Java. When
operating Java though Python as a method of developing or debugging Java there
are a few tricks that can be used to simplify the job.  Beyond being able to
probe and plot the Java data structures interactively, these methods include:

1) Attaching a debugger to the Java JVM being run under JPype.
2) Attaching debugging information to a Java exception.
3) Serializing the state of a Java process to be evaluated at a later point.

We will briefly discuss each of these methods.


.. _miscellaneous_topics_using_jpype_for_debugging_java_code_attaching_a_debugger:

Attaching a Debugger
--------------------

Interacting with Java through a shell is great, but sometimes it is necessary
to drop down to a debugger. To make this happen we need to start the JVM
with options to support remote debugging.

We start the JVM with an agent which will provide a remote debugging port which
can be used to attach your favorite Java debugging tool.  As the agent is
altering the Java code to create additional debugging hooks, this process can
introduce additional errors or alter the flow of the code.  Usually this is
used by starting the JVM with the agent, placing a pause marker in the Python
code so that developer can attach the Java debugger, executing the Python code
until it hits the pause, attaching the debugger, setting break point in Java,
and then asking Python to proceed.

So lets flesh out the details of how to accomplish this...

.. code-block:: python

    jpype.startJVM("-Xint", "-Xdebug", "-Xnoagent",
      "-Xrunjdwp:transport=dt_socket,server=y,address=12999,suspend=n")

Next, add a marker in the form of a pause statement at the location where
the debugger should be attached.

.. code-block:: python

    input("pause to attach debugger")
    myobj.callProblematicMethod()

When Python reaches that point during execution, switch to a Java IDE such as
NetBeans and select Debug : Attach Debugger.  This brings up a window (see
example below).  After attaching (and setting desired break points) go back to
Python and hit enter to continue.  NetBeans should come to the foreground when
a breakpoint is hit.

.. image:: attach_debugger.png


Attach data to an Exception
---------------------------

Sometimes getting to the level of a debugger is challenging especially if the
code is large and error occurs rarely. In this case, it is often beneficial to
attach data to an exception. To achieve this, we need to write a small utility
class. Java exceptions are not strictly speaking expandable, but they can be
chained. Thus, it we create a dummy exception holding a ``java.util.Map`` and
attach it to as the cause of the exception, it will be passed back down the
call stack until it reaches Python. We can then use ``getCause()`` to retrieve
the map containing the relevant data.


.. _miscellaneous_topics_capturing_the_state:

Capturing the state
-------------------

If the program is not running in an interactive shell or the program run time
is long, we may not want to deal with the problem during execution. In this
case, we can serialize the state of the relevant classes and variables. To use
this option, we mus make sure all of the classes in Java that we are using
are ``Serializable``.  Then add a condition that detects the faulty algorithm state.
When the fault occurs, create a ``java.util.HashMap`` and populate it with
the values to be examined from within Python.  Use serialization to write
the entire structure to a file.  Execute the program and collect all of the
state files.

Once the state files have been collected, start Python with an interactive
shell and launch JPype with a classpath for the jars.  Finally,
deserialize the state files to access the Java structures that have
been recorded.


.. _miscellaneous_topics_getting_additional_diagnostics:

Getting Additional Diagnostics
==============================

For the most part, JPype operates as intended, but that does not mean there are
no bugs or edge cases. Given the complexity of interactions between Python and
Java, untested scenarios may occasionally arise. JPype provides several
diagnostic tools to assist in debugging these issues. These tools require
accessing private JPype symbols, which may change in future releases. As such,
they should not be used in production code.

.. _checking-type-cast:

Checking the Type of a Cast
---------------------------

Sometimes it is difficult to understand why a particular method overload is
selected by the method dispatch. To check the match type for a conversion, use
the private method ``Class._canConvertToJava``. This will return a string
indicating the type of conversion performed: ``none``, ``explicit``,
``implicit``, or ``exact``.

To test the result of the conversion process, call ``Class._convertToJava``.
Unlike an explicit cast, this method attempts to perform the conversion without
bypassing the logic involved in casting. It replicates the exact process used
when a method is called or a field is set.

.. _cpp-exceptions:

C++ Exceptions in JPype
------------------------

Internally, JPype can generate C++ exceptions, which are converted into Python
exceptions for the user. To trace an error back to its C++ source, you can
enable stack traces for C++ exceptions. Use the following command:

.. code-block:: python

   import _jpype
   _jpype.enableStacktraces(True)

Once enabled, all C++ exceptions that fall through a C++ exception handling
block will produce an augmented stack trace. If the JPype source code is
available, the stack trace can even include the corresponding lines of code
where the exceptions occurred. This can help identify the source of errors that
originate in C++ code but propagate to Python as exceptions.

.. _tracing:

Tracing
-------

Tracing mode logs every JNI call, along with object addresses and exceptions,
to the console. To enable tracing, JPype must be recompiled with the
``--enable-tracing`` option.

Tracing is useful for identifying failures that originate in one JNI call but
manifest later. However, this mode produces verbose logs and is recommended
only for advanced debugging.


.. _instrumentation:

Instrumentation
---------------

JPype supports an instrumentation mode for testing error-handling paths. This
mode allows you to simulate faults at designated points in JPype's execution
flow. To enable instrumentation, recompile JPype with the ``--enable-coverage``
option.

Once instrumentation is enabled, use the private module command
``_jpype.fault`` to trigger an error. The argument to the fault command must be
the name of a function or a predefined fault point. When the fault point is
encountered, a ``SystemError`` is raised. Instrumentation is primarily useful
for verifying the robustness of JPype's exception handling mechanisms.


.. _using-debugger:

Using a Debugger
----------------

If JPype crashes, it may be necessary to use a debugger to obtain a backtrace.
However, debugging JPype can be challenging due to the JVM's handling of
segmentation faults. The JVM intercepts segmentation faults to allocate memory
or handle internal operations, which can corrupt stack frames.

To debug JPype using tools such as ``gdb`, you must configure the debugger to
ignore segmentation faults intentionally triggered by the JVM. For example, use
the following command to start ``gdb`` and ignore the first fault:

.. code-block:: shell

   gdb --args python script.py
   (gdb) handle SIGSEGV nostop noprint pass

This configuration allows the debugger to bypass JVM-related faults while
capturing legitimate errors. Additionally, disable Python's fault handler to
avoid interference with segmentation fault reporting.


.. _caller sensitive:

Caller-Sensitive Methods
-------------------------

Java's security model tracks the caller of certain methods to determine the
level of access. These methods, known as "caller-sensitive methods," require
special handling in JPype. Examples of caller-sensitive methods include
``Class.forName``, ``java.lang.ClassLoader`` methods, and certain methods in
``java.sql.DriverManager``.

To handle caller-sensitive methods, JPype routes calls through an internal
Java package, ``org.jpype``, which executes the method within the JVM. This
ensures proper security context and avoids access errors. Although this
mechanism introduces slight overhead, it is necessary for compatibility with
Java's security model.


.. _limitations_jvm:

JPype Known limitations
=======================

This section lists those limitations that are unlikely to change, as they come
from external sources.


.. _miscellaneous_topics_jpype_known_limitations_annotations:

Annotations
-----------

Some frameworks such as Spring use Java annotations to indicate specific
actions.  These may be either runtime annotations or compile time annotations.
Occasionally while using JPype someone would like to add a Java annotation to a
JProxy method so that a framework like Spring can pick up that annotation.

JPype uses the Java supplied ``Proxy`` to implement an interface.  That API
does not support addition of a runtime annotation to a method or class.  Thus,
all methods and classes when probed with reflection that are implemented in
Python will come back with no annotations.

Further, the majority of annotation magic within Java is actually performed at
compile time.  This is accomplished using an annotation processor.  When a
class or method is annotated, the compiler checks to see if there is an
annotation processor which then can produce new code or modify the class
annotations.  As this is a compile time process, even if annotations were added
by Python to a class they would still not be active as the corresponding
compilation phase would not have been executed.

This is a limitation of the implementation of annotations by the Java virtual
machine.  It is technically possible though the use of specialized code
generation with the ASM library or other code generation to add a runtime
annotation.  Or through exploits of the Java virtual machine annotation
implementation one can add annotation to existing Java classes.  But these
annotations are unlikely to be useful. As such JPype will not be able to
support class or method annotations.



.. _miscellaneous_topics_restarting_the_jvm:

Restarting the JVM
-------------------

JPype caches many resources to the JVM. Those resource are still allocated
after the JVM is shutdown as there are still Python objects that point to those
resources.  If the JVM is restarted, those stale Python objects will be in a
broken state and the new JVM instance will obtain the references to these
resulting in a memory leak. Thus it is not possible to start the JVM after it
has been shut down with the current implementation.


.. _miscellaneous_topics_running_multiple_jvm:

Running multiple JVM
--------------------

JPype uses the Python global import module dictionary, a global Python to Java
class map, and global JNI TypeManager map.  These resources are all tied to the
JVM that is started or attached. Thus operating more than one JVM does not
appear to be possible under the current implementation.  Further, as of Java
1.2 there is no support for creating more than one JVM in the same process.

Difficulties that would need to be overcome to remove this limitation include:

- Finding a JVM that supports multiple JVMs running in the same process.
  This can be achieved on some architectures by loading the same shared
  library multiple times with different names.
- Alternatively as all available JVM implementations support on one JVM
  instance per process, a communication layer would have to proxy JNI
  class from JPype to another process. But this has the distinct problem that
  remote JVMs cannot register native methods nor share memory without
  considerable effort.
- Which JVM would a static class method call. The class types
  would need to be JVM specific (ie. ``JClass('org.MyObject', jvm=JVM1)``)
- How would a wrapper from two different JVM coexist in the
  ``jpype._jclass`` module with the same name if different class
  is required for each JVM.
- How would the user specify which JVM a class resource is created in
  when importing a module.
- How would objects in one JVM be passed to another.
- How can boxed and String types hold which JVM they will box to on type
  conversion.

Thus it appears prohibitive to support multiple JVMs in the JPype
class model.


.. _miscellaneous_topics_jpype_known_limitations_errors_reported_by_python_fault_handler:

Errors reported by Python fault handler
---------------------------------------

The JVM takes over the standard fault handlers resulting in unusual behavior if
Python handlers are installed.  As part of normal operations the JVM will
trigger a segmentation fault when starting and when interrupting threads.
Pythons fault handler can intercept these operations and interpret these as
real faults.  The Python fault handler with then reporting extraneous fault
messages or prevent normal JVM operations.  When operating with JPype, Python
fault handler module should be disabled.

This is particularly a problem for running under pytest as the first action it
performs is to take over the error handlers. This can be disabled by adding
this block as a fixture at the start of the test suite.

.. code-block:: python

    try:
        import faulthandler
        faulthandler.enable()
        faulthandler.disable()
    except:
        pass

This code enables fault handling and then returns the default handlers which
will point back to those set by Java.

Python faulthandlers can also interfer with the JIT compiler.  The Java
Just-In-Time (JIT) compiler determines when a portion of code needs to be
compiled into machine code to improve performance.  When it does, it triggers
either a SEGSEGV or SEGBUS depending on the machine architecture which breaks
out any threads which are currently executing the existing code.  Because the
JIT compiler self triggers, this will cause a failure to appear in a call which
worked earlier in the execution without an issue.

If the Python fault handler interrupts this process, it will produce a "Fatal
Python Error:" followed by either SIGSEGV or SEGBUS.  This error message then
fails to hit the needed Java handler resulting in a crash.  This message will
disappear if the JIT compiler is disabled with the option "-Xint".  Running
without the JIT compiler creates a severe performance penalty so disabling the
fault handler should be the preferred solution.

Some modules such as Abseil Python Common Libraries (absl) automatically and
unconditionally install faulthandlers as part of their normal operation.  To
prevent an issue simply insert a call to disable the faulthandler after the
module has enabled it, using

.. code-block:: python

    import faulthandler
    faulthandler.disable()

For example, absl installs faulthandlers in ``app.run``, thus the first call to
main routine would need to disable faulthandlers to avoid potential crashes.



.. _miscellaneous_topics_unsupported_java_versions:

Unsupported Java Versions
-------------------------

JPype now requires the use of the module API, which was introduced in **Java
9**. As a result, the earliest version of Java supported by JPype is **Java
11**, which is part of the Long-Term Support (LTS) release.

If you need to use **Java 8**, you must use JPype version **1.5.2 or earlier**,
as newer versions of JPype no longer support Java 8.



.. _miscellaneous_topics_unsupported_python_versions:

Unsupported Python versions
---------------------------


.. _miscellaneous_topics_python_38_and_earlier:

Python 3.8 and earlier
~~~~~~~~~~~~~~~~~~~~~~

The oldest version of Python that we currently support is Python 3.5.  Before
Python 3.5 there were a number of structural difficulties in the object model
and the buffering API.  In principle, those features could be excised from
JPype to extend support to older Python 3 series version, but that is unlikely
to happen without a significant effort.  Recent changes in memory models
require Python 3.8 or later.


.. _miscellaneous_topics_python_2:

Python 2
~~~~~~~~

CPython 2 support was removed starting in 2020.  Please do not report to us
that Python 2 is not supported.  Python 2 was a major drag on this project for
years.  Its object model is grossly outdated and thus providing for it greatly
impeded progress.  When the life support was finally pulled on that beast,
I like many others breathed a great sigh of relief and gladly cut out the
Python 2 code.  Since that time JPype operating speed has improved anywhere
from 300% to 10000% as we can now implement everything back in CPython rather
than band-aiding it with interpreted Python code.


.. _miscellaneous_topics_pypy:

PyPy
~~~~

The GC routine in PyPy 3 does not play well with Java. It runs when it thinks
that Python is running out of resources. Thus a code that allocates a lot
of Java memory and deletes the Python objects will still be holding the
Java memory until Python is garbage collected. This means that out of
memory failures can be issued during heavy operation.  We have addressed linking
the garbage collectors between CPython and Java, but PyPy would require a
modified strategy.

Further, when we moved to a completely Python 3 object model we unfortunately
broke some of the features that are different between CPython and PyPy.  The
errors make absolutely no sense to me.  So unless a PyPy developer generously
volunteering time for this project, this one is unlikely to happen.


.. _miscellaneous_topics_jython_python:

Jython Python
~~~~~~~~~~~~~

If for some reason you wandered here to figure out how to use Java from
Jython using JPype, you are clearly in the wrong place. On the other hand,
if you happen to be a Jython developer who is looking for inspiration on how
to support a more JPype like API that perhaps we can assist you.  Jython aware
Python modules often mistake JPype for Jython at least up until the point
that differences in the API triggers an error.



.. _miscellaneous_topics_unsupported_java_virtual_machines:

Unsupported Java virtual machines
---------------------------------

The open JVM implementations *Cacao* and *JamVM* are known not to work with
JPype.


.. _miscellaneous_topics_unsupported_platforms:

Unsupported Platforms
---------------------

Some platforms are problematic for JPype due to interactions between the
Python libraries and the JVM implementation.


.. _miscellaneous_topics_cygwin:

Cygwin
~~~~~~

Cygwin was usable with previous versions of JPype, but there were numerous
issues for which there is was not good solution solution.

Cygwin does not appear to pass environment variables to the JVM properly
resulting in unusual behavior with certain windows calls. The path
separator for Cygwin does not match that of the Java DLL, thus specification
of class paths must account for this.  Threading between the Cygwin libraries
and the JVM was often unstable.

.. _freezing:

Freezing
========

JPype supports freezing and deployment with
`PyInstaller <https://pyinstaller.readthedocs.io/>`_.  The hook is included
with JPype installations and no extra configuration should be needed.


.. _miscellaneous_topics_glossary:

Useless Trivia
==============

Thrameos, the primary developer, maintains the correct pronounciation of
JPype is Jay-Pie-Pee like the word recipe.  His position is that application
of a silient e is inappropriate for this made up name.

1) Jay-Pie is more emblematic of the project goal which is connection of
Java and Python.

2) Rules in English regarding a silent e following a p are poor and depend
mostly on the origin of the word.  Is it like type from the Greek word
typus or French récipé?  As the y in not being modified as it would otherwise
be pronounced as Pie like NumPy and SciPy, that means the only logical
conclusion is that it was intended to be voiced.

3) Jay-pipe or gh-pipe implies that this project is built on pipes (also known
as series of tubes such as the internet).  JPype is based on JNI (Jay-eN-Ey).
If you are looking for a pipe based Java connection use Py4J.  If you are looking
for solution based on JNI use JPypé.





Glossary
========

.. _miscellaneous_topics_glossary_b:

B
-

**Boxed Types**
Immutable Java objects that wrap primitive types (e.g., `java.lang.Integer`
for `int`). Used when primitives need to be treated as objects.

.. _miscellaneous_topics_glossary_c:

C
-

**Caller Sensitive Methods**
Java methods that determine the caller's access level based on the call stack.
JPype uses special mechanisms to handle these methods safely.

**Classpath**
A parameter specifying the location of Java classes or JAR files required by
the JVM. It is essential for loading Java libraries.

.. _miscellaneous_topics_glossary_d:

D
-

**Deferred Proxy**
A proxy that is created before the JVM is started by specifying the interface
as a string and using the `deferred=True` argument. The implementation is
checked only when the proxy is first used.

.. _miscellaneous_topics_glossary_e:

E
-

**Exact Conversion**
A type conversion in JPype where the Python type matches the Java type
exactly. Example: Python `int` to Java `int`.

.. _miscellaneous_topics_glossary_f:

F
-

**Functional Interface**
A Java interface with a single abstract method (SAM). JPype allows Python
callables (e.g., functions, lambdas) to be passed directly to Java methods
expecting a functional interface.

.. _miscellaneous_topics_glossary_g:

G
-

**Garbage Collection (GC)**
The process of automatically reclaiming memory occupied by unused objects.
JPype links Python's and Java's garbage collectors to avoid memory issues.

.. _miscellaneous_topics_glossary_i:

I
-

**Implicit Conversion**
A type conversion in JPype where Python types are automatically converted to
compatible Java types. Example: Python `int` to Java `long`.

**Interface**
A Java construct that defines a set of methods without implementations. JPype
allows Python classes to implement Java interfaces using proxies.


.. _miscellaneous_topics_glossary_m:

M
-

**Mapping**
A Python concept for key-value pairs. JPype customizes Java `Map` classes to
behave like Python dictionaries.

**Multidimensional Arrays**
Java arrays with multiple dimensions. JPype supports creating and working with
these arrays using nested lists.

.. _miscellaneous_topics_glossary_n:

N
-

**NumPy Integration**
JPype's ability to efficiently transfer data between Java arrays and NumPy
arrays using memory buffers.

.. _miscellaneous_topics_glossary_o:

O
-

**Object Instance**
A Java object created from a class. Example: `obj = MyClass()` creates an
instance of `MyClass`.

**Overloaded Methods**
Java methods with the same name but different parameter types or counts. JPype
selects the appropriate overload based on the Python arguments provided.

.. _miscellaneous_topics_glossary_p:

P
-

**Primitive Types**
Basic data types in Java (e.g., `int`, `float`, `boolean`). JPype maps these
types to Python equivalents (e.g., `JInt`, `JFloat`, `JBoolean`).

**Proxy**
A proxy is an intermediary that allows Python objects to implement Java
interfaces. In the context of JPype, Proxies focus solely on providing the
required Java interface functionality.

.. _miscellaneous_topics_glossary_s:

S
-

**SAM (Single Abstract Method)**
A Java interface with a single abstract method. Used in functional programming
and supported by JPype for Python callables.

**Synchronized**
A Java keyword for thread-safe operations. JPype provides the
`jpype.synchronized()` method for similar functionality in Python.

.. _miscellaneous_topics_glossary_t:

T
-

**Type Factory**
A JPype mechanism for creating Java types in Python. Examples include `JClass`
for classes and `JArray` for arrays.

.. _miscellaneous_topics_glossary_u:

U
-

**UnsupportedClassVersionError**
A JVM error indicating that a JAR file was compiled for a newer Java version
than the JVM being used.

.. _miscellaneous_topics_glossary_w:

W
-

**Wrapper**
A wrapper is an object used to represent an object from one programming language
in another programming language, providing a native look and feel. In JPype,
wrappers are used to present Java objects to Python, making them behave like
native Python objects while retaining their underlying Java functionality.
Wrappers encapsulate Java references, such as class instances, arrays, or boxed
types, and may also include proxies when implementing Java interfaces.

Future versions of JPype aim to introduce the ability to manipulate Python
objects from Java. In this case, wrappers will represent Python objects from the
perspective of Java, providing a seamless interface for Java code to interact
with Python objects.