Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/user/Python-on-JVM.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ assert issubclass(PythonLevel, Level)
assert PythonLevel.parse("INFO").getName() == "INFO"
```

Two important caveats:

1. You cannot use other metaclasses, so inheriting from `ABC` and a Java class is not supported.
2. If you want to implement `__init__` to accept additional arguments, you must also override `__new__` to avoid passing the additional arguments to the Java constructor, which would not know how to handle them.

## Embedding Python into Java

Expand Down
20 changes: 16 additions & 4 deletions graalpython/com.oracle.graal.python.test/src/tests/test_interop.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ class MyHandler (Handler):
counter = 0;
def isLoggable(self, logrecord):
self.counter = self.counter + 1
return self.__super__.isLoggable(logrecord)
return super().isLoggable(logrecord)
def sayHello(self):
return 'Hello'

Expand Down Expand Up @@ -726,9 +726,9 @@ def test_extend_java_class_03(self):

class MyLogRecord(LogRecord):
def getLevel(self):
if self.__super__.getLevel() == Level.FINEST:
self.__super__.setLevel(Level.WARNING)
return self.__super__.getLevel()
if super().getLevel() == Level.FINEST:
super().setLevel(Level.WARNING)
return super().getLevel()

message = "log message"
my_lr1 = MyLogRecord(Level.WARNING, message)
Expand Down Expand Up @@ -1503,6 +1503,18 @@ def getName(self):
assert pl.callStaticFromPython("INFO").getName() == "INFO"
assert PythonLevel2.parse("INFO").getName() == "INFO"

def test_java_subclassing_with_new_arguments(self):
from java.util.logging import Level

class PythonLevel(Level, new_style=True):
def __new__(cls, misc_value):
return super().__new__(cls, "default name", 2)

def __init__(self, misc_value):
self.misc_value = misc_value

pl = PythonLevel(123)
assert pl.misc_value == 123

def test_jython_star_import(self):
if __graalpython__.jython_emulation_enabled:
Expand Down
10 changes: 7 additions & 3 deletions graalpython/lib-graalpython/__graalpython__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -98,7 +98,7 @@ def import_current_as_named_module_with_delegate(module, module_name, delegate_n


@builtin
def build_java_class(module, ns, name, base, new_style=False):
def build_java_class(module, ns, name, base, new_style=True):
if new_style:
return build_new_style_java_class(ns, name, base)
import warnings
Expand Down Expand Up @@ -174,6 +174,11 @@ def __instancecheck__(cls, obj):
def __subclasscheck__(cls, derived):
return cls is derived or issubclass(derived, JavaClass)

def __call__(cls, *args, **kwds):
java_object = cls.__new__(cls, *args, **kwds)
java_object.this.__init__(*args, **kwds)
return java_object

def __new__(mcls, name, bases, namespace):
if bases:
new_class = None
Expand Down Expand Up @@ -232,7 +237,6 @@ def __new__(cls, *args, **kwds):
delegate = object.__new__(cls)
java_object = polyglot.__new__(JavaClass, *(args + (delegate,)))
delegate.__this__ = java_object
delegate.__init__(*args, **kwds)
return java_object

return type(name, (DelegateSuperclass,), ns)
Loading