0
# Exception Handling
1
2
Handle Java exceptions within Python and bridge between Python and Java exception systems. This module provides seamless exception interoperability, allowing Python code to catch Java exceptions and Java code to handle Python exceptions.
3
4
## Capabilities
5
6
### Exception Base Classes
7
8
Base classes for Java exception handling in Python.
9
10
```python { .api }
11
class JException(Exception):
12
"""Base class for all Java exceptions.
13
14
Bridges Java exceptions to Python exception system.
15
All Java exceptions are subclasses of JException.
16
"""
17
18
def __init__(self, *args):
19
"""Initialize Java exception.
20
21
Args:
22
*args: Exception arguments
23
"""
24
25
def getMessage(self) -> str:
26
"""Get the Java exception message.
27
28
Returns:
29
str: Exception message from Java
30
"""
31
32
def getStackTrace(self):
33
"""Get Java stack trace.
34
35
Returns:
36
Java array of StackTraceElement objects
37
"""
38
39
def printStackTrace(self):
40
"""Print Java stack trace to standard error."""
41
42
def getCause(self):
43
"""Get the cause of this exception.
44
45
Returns:
46
JException or None: The underlying cause
47
"""
48
```
49
50
## Usage Examples
51
52
### Basic Exception Handling
53
54
```python
55
import jpype
56
57
jpype.startJVM()
58
59
try:
60
# This will cause a Java exception
61
string_obj = jpype.java.lang.String("test")
62
char = string_obj.charAt(10) # StringIndexOutOfBoundsException
63
except jpype.JException as e:
64
print(f"Caught Java exception: {e}")
65
print(f"Exception type: {type(e)}")
66
print(f"Message: {e.getMessage()}")
67
68
jpype.shutdownJVM()
69
```
70
71
### Catching Specific Java Exceptions
72
73
```python
74
import jpype
75
76
jpype.startJVM()
77
78
# Access Java exception classes
79
NumberFormatException = jpype.java.lang.NumberFormatException
80
IllegalArgumentException = jpype.java.lang.IllegalArgumentException
81
82
try:
83
# Parse invalid number
84
result = jpype.java.lang.Integer.parseInt("not_a_number")
85
except NumberFormatException as e:
86
print(f"Number format error: {e.getMessage()}")
87
except IllegalArgumentException as e:
88
print(f"Illegal argument: {e.getMessage()}")
89
except jpype.JException as e:
90
print(f"Other Java exception: {e}")
91
92
jpype.shutdownJVM()
93
```
94
95
### Exception Hierarchy
96
97
```python
98
import jpype
99
100
jpype.startJVM()
101
102
# Java exception hierarchy maps to Python
103
RuntimeException = jpype.java.lang.RuntimeException
104
NullPointerException = jpype.java.lang.NullPointerException
105
106
try:
107
# Create null pointer situation
108
null_string = None
109
# This would cause NullPointerException in Java context
110
raise jpype.java.lang.NullPointerException("Test null pointer")
111
except NullPointerException as e:
112
print("Caught NullPointerException")
113
except RuntimeException as e:
114
print("Caught RuntimeException (parent class)")
115
except jpype.JException as e:
116
print("Caught general Java exception")
117
118
jpype.shutdownJVM()
119
```
120
121
### Stack Trace Information
122
123
```python
124
import jpype
125
126
jpype.startJVM()
127
128
try:
129
# Create a method that throws an exception
130
Collections = jpype.java.util.Collections
131
empty_list = Collections.emptyList()
132
element = empty_list.get(0) # IndexOutOfBoundsException
133
except jpype.JException as e:
134
print(f"Exception message: {e.getMessage()}")
135
print(f"Exception class: {e.getClass().getName()}")
136
137
# Print Java stack trace
138
print("\nJava stack trace:")
139
e.printStackTrace()
140
141
# Get stack trace elements
142
stack_trace = e.getStackTrace()
143
print(f"\nStack trace has {len(stack_trace)} elements")
144
145
if len(stack_trace) > 0:
146
top_element = stack_trace[0]
147
print(f"Top frame: {top_element.getClassName()}.{top_element.getMethodName()}")
148
print(f"Line number: {top_element.getLineNumber()}")
149
150
jpype.shutdownJVM()
151
```
152
153
### Exception Chaining
154
155
```python
156
import jpype
157
158
jpype.startJVM()
159
160
try:
161
try:
162
# Cause initial exception
163
jpype.java.lang.Integer.parseInt("invalid")
164
except jpype.JException as e:
165
# Wrap in another exception
166
RuntimeException = jpype.java.lang.RuntimeException
167
wrapped = RuntimeException("Wrapped exception", e)
168
raise wrapped
169
except jpype.JException as e:
170
print(f"Outer exception: {e.getMessage()}")
171
172
# Get the original cause
173
cause = e.getCause()
174
if cause:
175
print(f"Original cause: {cause.getMessage()}")
176
print(f"Cause type: {cause.getClass().getName()}")
177
178
jpype.shutdownJVM()
179
```
180
181
### Throwing Java Exceptions from Python
182
183
```python
184
import jpype
185
from jpype import JImplements, JOverride
186
187
jpype.startJVM()
188
189
# Throw Java exceptions from Python code
190
def risky_operation(value):
191
if value < 0:
192
raise jpype.java.lang.IllegalArgumentException("Value cannot be negative")
193
if value == 0:
194
raise jpype.java.lang.ArithmeticException("Division by zero")
195
return 100 / value
196
197
try:
198
result1 = risky_operation(-5)
199
except jpype.java.lang.IllegalArgumentException as e:
200
print(f"Illegal argument: {e.getMessage()}")
201
202
try:
203
result2 = risky_operation(0)
204
except jpype.java.lang.ArithmeticException as e:
205
print(f"Arithmetic error: {e.getMessage()}")
206
207
# Normal case
208
result3 = risky_operation(10)
209
print(f"Normal result: {result3}")
210
211
jpype.shutdownJVM()
212
```
213
214
### Exception Handling in Interface Implementations
215
216
```python
217
import jpype
218
from jpype import JImplements, JOverride
219
220
jpype.startJVM()
221
222
Callable = jpype.java.util.concurrent.Callable
223
224
@JImplements(Callable)
225
class ExceptionThrowingTask:
226
def __init__(self, should_fail, error_type="runtime"):
227
self.should_fail = should_fail
228
self.error_type = error_type
229
230
@JOverride
231
def call(self):
232
if not self.should_fail:
233
return "Success"
234
235
# Throw different types of Java exceptions
236
if self.error_type == "runtime":
237
raise jpype.java.lang.RuntimeException("Task failed with runtime error")
238
elif self.error_type == "illegal_state":
239
raise jpype.java.lang.IllegalStateException("Invalid task state")
240
elif self.error_type == "io":
241
raise jpype.java.io.IOException("I/O operation failed")
242
else:
243
raise jpype.java.lang.Exception("Generic task failure")
244
245
# Use with ExecutorService
246
executor = jpype.java.util.concurrent.Executors.newSingleThreadExecutor()
247
248
# Test different exception types
249
test_cases = [
250
("runtime", jpype.java.lang.RuntimeException),
251
("illegal_state", jpype.java.lang.IllegalStateException),
252
("io", jpype.java.io.IOException),
253
("generic", jpype.java.lang.Exception)
254
]
255
256
for error_type, expected_exception in test_cases:
257
task = ExceptionThrowingTask(True, error_type)
258
future = executor.submit(task)
259
260
try:
261
result = future.get()
262
except jpype.java.util.concurrent.ExecutionException as e:
263
cause = e.getCause()
264
print(f"Task with {error_type} error failed: {cause.getMessage()}")
265
print(f"Exception type: {cause.getClass().getName()}")
266
267
executor.shutdown()
268
jpype.shutdownJVM()
269
```
270
271
### Exception Translation
272
273
```python
274
import jpype
275
276
jpype.startJVM()
277
278
def python_to_java_exception(python_func):
279
"""Decorator to translate Python exceptions to Java exceptions."""
280
def wrapper(*args, **kwargs):
281
try:
282
return python_func(*args, **kwargs)
283
except ValueError as e:
284
raise jpype.java.lang.IllegalArgumentException(str(e))
285
except FileNotFoundError as e:
286
raise jpype.java.io.FileNotFoundException(str(e))
287
except Exception as e:
288
raise jpype.java.lang.RuntimeException(f"Python error: {str(e)}")
289
return wrapper
290
291
@python_to_java_exception
292
def parse_positive_int(value_str):
293
"""Parse string to positive integer, raising appropriate exceptions."""
294
if not isinstance(value_str, str):
295
raise ValueError("Input must be a string")
296
297
try:
298
value = int(value_str)
299
except ValueError:
300
raise ValueError(f"'{value_str}' is not a valid integer")
301
302
if value <= 0:
303
raise ValueError("Value must be positive")
304
305
return value
306
307
# Test exception translation
308
test_values = ["123", "abc", "-5", 42]
309
310
for test_val in test_values:
311
try:
312
result = parse_positive_int(test_val)
313
print(f"Parsed {test_val} -> {result}")
314
except jpype.JException as e:
315
print(f"Java exception for {test_val}: {e.getClass().getSimpleName()} - {e.getMessage()}")
316
317
jpype.shutdownJVM()
318
```
319
320
### Custom Exception Classes
321
322
```python
323
import jpype
324
from jpype import JImplements
325
326
jpype.startJVM()
327
328
# Create custom Java exception by extending existing ones
329
@JImplements("java.lang.RuntimeException", deferred=True)
330
class CustomBusinessException:
331
def __init__(self, message, error_code=None):
332
super().__init__(message)
333
self.error_code = error_code
334
335
def getErrorCode(self):
336
return self.error_code
337
338
# Use custom exception
339
def business_operation(account_id):
340
if account_id < 0:
341
raise CustomBusinessException("Invalid account ID", "INVALID_ACCOUNT")
342
if account_id == 999:
343
raise CustomBusinessException("Account suspended", "ACCOUNT_SUSPENDED")
344
return f"Operation successful for account {account_id}"
345
346
# Test custom exception
347
try:
348
result = business_operation(-1)
349
except CustomBusinessException as e:
350
print(f"Business error: {e.getMessage()}")
351
print(f"Error code: {e.getErrorCode()}")
352
353
jpype.shutdownJVM()
354
```