@@ -6,75 +6,181 @@ stable Jython release, and these only come in Python 2.x versions. The GraalVM
6
6
implementation of Python, in contrast, is only targeting Python 3.x.
7
7
8
8
Nonetheless, there are certain features of Jython's Java integration that we can
9
- offer similarly. Some features are more expensive to offer, and thus are hidden
10
- behind a command line flag, ` --python.EmulateJython ` .
11
-
12
- ## Importing Java Classes and Packages
13
-
14
- In the default mode, Java classes can only be imported through the ` java `
15
- package. Additionally, only Java classes can be imported, not packages. In
16
- Jython compatibility mode, importing works more directly, at the cost worse
17
- performance for import failures in the general case.
18
-
19
- #### Normal mode
20
-
21
- Suppose you want to import the class ` sun.misc.Signal ` , normal usage looks like
22
- this:
23
-
24
- import java.sun.misc.Signal as Signal
25
-
26
- For the ` java ` namespace, you do not have to repeat the ` java ` name (but can):
27
-
28
- import java.lang.System as System
29
-
30
- #### Jython mode
31
-
32
- In Jython mode, Java packages can be imported and traversed, and they can be
33
- imported directly without going through the ` java ` module.
34
-
35
- import sun.misc.Signal as Signal
36
-
37
- import org.antlr
38
-
39
- type(org.antlr.v4.runtime) # => module
40
- org.antlr.v4.runtime.Token
41
-
42
- The downside of this is that everytime an import fails (and there are many
43
- speculative imports in the standard library), we ask the Java classloader to
44
- list currently available packages and traverse them to check if we should create
45
- a Java package. This slows down startup significantly.
46
-
47
- ## Interacting with Java Objects
48
-
49
- Once you get hold of a Java object or class, interaction in both modes works
50
- naturally. Public fields and methods can be read and invoked as expected.
51
-
52
- ## Subclassing Java Classes and Implementing Interfaces with Python Classes
53
-
54
- This is not supported at all right now, there's no emulation available even in
55
- Jython compatibility mode. We have not seen many uses of this in the wild. Let
56
- us know if this is of interest to you!
57
-
58
- ## Catching Java exceptions
59
-
60
- By default this is not allowed, because of the additional cost of checking for
61
- Java exceptions in the except statement execution. However, in Jython
62
- compatibility mode, the common case of catching a Java exception directly works:
63
-
64
- import java.lang.NumberFormatException as NumberFormatException
65
- import java.lang.Integer as Integer
66
-
67
- try:
68
- Integer.parseInt("99", 8)
69
- except NumberFormatException as e:
70
- pass
71
-
72
- Note that even in this mode, Java exceptions are never caught by generic except
73
- handlers, so this * will not* work:
74
-
75
- import java.lang.Integer as Integer
76
-
77
- try:
78
- Integer.parseInt("99", 8)
79
- except:
80
- pass
9
+ offer similarly. Here is an example:
10
+
11
+ >>> import java.awt as awt
12
+ >>> win = awt.Frame()
13
+ >>> win.setSize(200, 200)
14
+ >>> win.setTitle("Hello from Python!")
15
+ >>> win.getSize().toString()
16
+ 'java.awt.Dimension[width=200,height=200]'
17
+ >>> win.show()
18
+
19
+ This example works exactly the same on both Jython and Python on GraalVM. Some
20
+ features of Jython are more expensive at runtime, and thus are hidden behind a
21
+ command line flag on Graal: ` --python.EmulateJython ` .
22
+
23
+ ### Importing
24
+
25
+ Import statements allow you to import Java classes, but (unlike Jython), only
26
+ packages in the ` java ` namespace can be directly imported. So this works:
27
+
28
+ import java.lang as lang
29
+
30
+ But this doesn't:
31
+
32
+ import javax.swing as swing
33
+ from javax.swing import *
34
+
35
+ Instead, you'll have to import one of the classes you're interested in directly:
36
+
37
+ import javax.swing.Window as Window
38
+
39
+ ### Basic Object Usage
40
+
41
+ Constructing and working with Java objects and classes is done with natural
42
+ Python syntax. The methods of Java objects can also be retrieved and passed
43
+ around as first class objects (bound to their instance) the same as Python
44
+ methods:
45
+
46
+ >>> from java.util import Random
47
+ >>> rg = Random(99)
48
+ >>> boundNextInt = rg.nextInt
49
+ >>> rg.nextInt()
50
+ 1491444859
51
+ >>> boundNextInt = rg.nextInt
52
+ 1672896916
53
+
54
+ ### Java-to-Python Types: Automatic Conversion
55
+
56
+ Method overloads are resolved by matching the Python arguments in a best-effort
57
+ manner to the available parameter types. This is also when data conversion
58
+ happens. The goal here is to make using Java from Python as smooth as
59
+ possible. The matching we do here is similar to Jython, but Graal Python uses a
60
+ more dynamic approach to matching &mdash ; Python types emulating ` int ` or
61
+ ` float ` are also converted to the appropriate Java types. This allows, for
62
+ example, to use Pandas frames as ` double[][] ` or NumPy array elements as ` int[] `
63
+ when the elements fit into those Java primitive types.
64
+
65
+ | Java type | Python type |
66
+ | :-----------------------| :----------------------------------------------------------------------------------|
67
+ | null | None |
68
+ | boolean | bool |
69
+ | byte, short, int, long | int, any object that has an ` __int__ ` method |
70
+ | float | float, any object that has a ` __float__ ` method |
71
+ | char | str of length 1 |
72
+ | java.lang.String | str |
73
+ | byte[ ] | bytes, bytearray, wrapped Java array, Python list with only the appropriate types |
74
+ | Java arrays | Wrapped Java array or Python list with only the appropriate types |
75
+ | Java objects | Wrapped Java object of the appropriate type |
76
+ | java.lang.Object | Any object |
77
+
78
+ ### Special Jython Modules
79
+
80
+ We do not offer any of the special Jython modules. For example, the ` jarray `
81
+ module on Jython allows construction of primitive Java arrays. This can be
82
+ achieved as follows on GraalPython:
83
+
84
+ >>> import java
85
+ >>> java.type("int[]")(10)
86
+
87
+ Code that only needs to pass a Java array can also use Python types. However,
88
+ implicitly this may entail a copy of the array data, which can be deceiving when
89
+ using Java arrays as output parameters:
90
+
91
+ >>> i = java.io.ByteArrayInputStream(b"foobar")
92
+ >>> buf = [0, 0, 0]
93
+ >>> i.read(buf) # buf is automatically converted to a byte[] array
94
+ 3
95
+ >>> buf
96
+ [0, 0, 0] # the converted byte[] array got lost
97
+ >>> jbuf = java.type("byte[]")(3)
98
+ >>> i.read(jbuf)
99
+ 3
100
+ >>> jbuf
101
+ [98, 97, 122]
102
+
103
+ ### Exceptions from Java
104
+
105
+ Catching all kinds of Java exceptions comes with a performance penalty, and is
106
+ only enabled with the ` --python.EmulateJython ` flag.
107
+
108
+ >>> import java
109
+ >>> v = java.util.Vector()
110
+ >>> try:
111
+ ... x = v.elementAt(7)
112
+ ... except java.lang.ArrayIndexOutOfBoundsException as e:
113
+ ... print(e.getMessage())
114
+ ...
115
+ 7 >= 0
116
+
117
+ ### Java Collections
118
+
119
+ There is no automatic mapping of the Python syntax for accessing dictionary
120
+ elements to the ` java.util ` mapping and list classes' ` get ` , ` set ` , or ` put `
121
+ methods. To use these mapping and list clases, you must call the Java methods:
122
+
123
+ >>> ht = java.util.Hashtable()
124
+ >>> ht.put("foo", "bar")
125
+ >>> ht.get("foo")
126
+ 'bar'
127
+
128
+ We also do not support Python-style iteration of Java ` java.util.Enumerable ` ,
129
+ ` java.util.Iterator ` , or ` java.lang.Iterable ` . For these, you'll have to use a
130
+ ` while ` loop and use the ` hasNext() ` and ` next() ` (or equivalent) methods.
131
+
132
+ ### No Inheriting from Java
133
+
134
+ Python classes cannot inherit from Java classes. A workaround can be to create a
135
+ flexible subclass in Java, compile it, and use delegation instead. Take this
136
+ example:
137
+
138
+ import java.util.logging.Handler;
139
+
140
+ public class PythonHandler extends Handler {
141
+ private final Value pythonDelegate;
142
+
143
+ public PythonHandler(Value pythonDelegate) {
144
+ this.pythonDelegate = pythonDelegate;
145
+ }
146
+
147
+ public void publish(LogRecord record) {
148
+ pythonDelegate.invokeMember("publish", record);
149
+ }
150
+
151
+ public void flush() {
152
+ pythonDelegate.invokeMember("flush");
153
+ }
154
+
155
+ public void close() {
156
+ pythonDelegate.invokeMember("close");
157
+ }
158
+ }
159
+
160
+ Then you can use it like this in Python:
161
+
162
+ from java.util.logging import LogManager, Logger
163
+
164
+ class MyHandler():
165
+ def publish(self, logRecord): print("[python]", logRecord.toString())
166
+ def flush(): pass
167
+ def close(): pass
168
+
169
+ LogManager.getLogManager().addLogger(Logger('my.python.logger', None, MyHandler()))
170
+
171
+ ## Embedding Python into Java
172
+
173
+ The other way to use Jython is to embed it into Java applications. Where above,
174
+ Graal Python offered some measure of compatibility with existing Jython code, we
175
+ do not offer any in this case. Existing code using Jython depends directly on
176
+ the Jython package (for example, in the Maven configuration), because the Java
177
+ code has references to Jython internal classes such as ` PythonInterpreter ` .
178
+
179
+ For Graal Python, no dependency other than on the [ GraalVM
180
+ SDK] ( https://mvnrepository.com/artifact/org.graalvm.sdk/graal-sdk ) is
181
+ required. There are no APIs particular to Python that are exposed, and
182
+ everything is done through the GraalVM API. Important to know is that as long as
183
+ your application is executed on a GraalVM with the Python language installed,
184
+ you can embed Python in your programs. Please refer to [ our embedding
185
+ documentation] ( https://www.graalvm.org/docs/reference-manual/embed/#Function_Python )
186
+ for more details.
0 commit comments