A Python module to access Java classes as Python classes using JNI.
—
Manual class definition provides precise control over Java class access by explicitly declaring which methods and fields to expose. This approach offers better performance than autoclass and enables custom behavior, but requires knowledge of Java class signatures.
Foundation classes for creating manual Java wrapper classes.
class JavaClass:
"""
Base class for manually defined Java class wrappers.
All manual Java class wrappers must inherit from this class and use
MetaJavaClass as their metaclass.
"""
class MetaJavaClass(type):
"""
Metaclass for Java class wrappers that handles method and field binding.
Automatically processes class definitions to bind Java methods and fields
to Python wrapper classes during class creation.
"""
class MetaJavaBase(type):
"""Base metaclass for Java class wrappers."""Wrapper classes for binding Java methods to Python classes.
def JavaMethod(signature: str, varargs: bool = False) -> callable:
"""
Create wrapper for Java instance method.
Args:
signature: JNI method signature (e.g., '(Ljava/lang/String;)V')
varargs: Whether method accepts variable arguments
Returns:
Callable that can be assigned to class attribute. The returned
method object has a signatures() method for introspection.
"""
def JavaStaticMethod(signature: str, varargs: bool = False) -> callable:
"""
Create wrapper for Java static method.
Args:
signature: JNI method signature (e.g., '()Ljava/lang/String;')
varargs: Whether method accepts variable arguments
Returns:
Callable that can be assigned to class attribute
"""
def JavaMultipleMethod(signatures: list) -> callable:
"""
Create wrapper for overloaded Java methods.
Args:
signatures: List of (signature, is_static, varargs) tuples
Returns:
Callable that dispatches to appropriate overload based on arguments
"""Wrapper classes for binding Java fields to Python classes.
def JavaField(signature: str) -> property:
"""
Create wrapper for Java instance field.
Args:
signature: JNI field type signature (e.g., 'Ljava/lang/String;')
Returns:
Property that can be assigned to class attribute
"""
def JavaStaticField(signature: str) -> property:
"""
Create wrapper for Java static field.
Args:
signature: JNI field type signature (e.g., 'I' for int)
Returns:
Property that can be assigned to class attribute
"""Base wrapper for individual Java objects.
class JavaObject:
"""
Base wrapper class for individual Java objects.
Provides low-level access to Java objects with automatic memory management
and method dispatch. Typically not used directly - JavaClass is preferred.
"""Enhanced base class with built-in Java method implementations.
class PythonJavaClass(JavaClass):
"""
Enhanced JavaClass with built-in Java method implementations.
Can be used to create Python classes that implement Java interfaces
by setting __javainterfaces__ class attribute.
Automatically provides standard Java object methods like hashCode(),
toString(), and equals() with Python-compatible implementations.
"""
def hashCode() -> int:
"""Java-compatible hash code based on Python object id."""
def toString() -> str:
"""Java-compatible string representation using Python repr."""
def equals(other: object) -> bool:
"""Java-compatible equality check using hash codes."""
def invoke(self, method: str, *args) -> any:
"""Invoke Java method by name with arguments."""
def _invoke(self, method: str, *args) -> any:
"""Internal method invocation handler."""Decorator for binding Java methods to Python methods.
def java_method(signature: str, name: str = None, varargs: bool = False) -> callable:
"""
Decorator for binding Java methods to Python methods.
Args:
signature: JNI method signature
name: Java method name (defaults to Python method name)
varargs: Whether method accepts variable arguments
Returns:
Decorator function for Python methods
"""Usage Examples:
from jnius import JavaClass, MetaJavaClass, JavaMethod, JavaStaticMethod, JavaField
class String(JavaClass, metaclass=MetaJavaClass):
__javaclass__ = 'java/lang/String'
# Constructor signatures
__javaconstructor__ = [
('()V', False), # Default constructor
('(Ljava/lang/String;)V', False), # String constructor
('([C)V', False), # char array constructor
]
# Instance methods
length = JavaMethod('()I')
charAt = JavaMethod('(I)C')
substring = JavaMultipleMethod([
('(I)Ljava/lang/String;', False, False),
('(II)Ljava/lang/String;', False, False),
])
toUpperCase = JavaMethod('()Ljava/lang/String;')
toLowerCase = JavaMethod('()Ljava/lang/String;')
equals = JavaMethod('(Ljava/lang/Object;)Z')
# Static methods
valueOf = JavaMultipleMethod([
('(I)Ljava/lang/String;', True, False),
('(F)Ljava/lang/String;', True, False),
('(D)Ljava/lang/String;', True, False),
('(Ljava/lang/Object;)Ljava/lang/String;', True, False),
])
# Usage
text = String('Hello World')
print(text.length()) # 11
print(text.toUpperCase()) # HELLO WORLD
print(String.valueOf(42)) # "42"from jnius import JavaClass, MetaJavaClass, JavaStaticField, JavaField
class System(JavaClass, metaclass=MetaJavaClass):
__javaclass__ = 'java/lang/System'
# Static fields
out = JavaStaticField('Ljava/io/PrintStream;')
err = JavaStaticField('Ljava/io/PrintStream;')
# Static methods
currentTimeMillis = JavaStaticMethod('()J')
getProperty = JavaStaticMethod('(Ljava/lang/String;)Ljava/lang/String;')
# Usage
System.out.println('Hello World')
version = System.getProperty('java.version')
timestamp = System.currentTimeMillis()from jnius import PythonJavaClass, MetaJavaClass, java_method
class MyJavaClass(PythonJavaClass, metaclass=MetaJavaClass):
__javaclass__ = 'com/example/MyClass'
@java_method('(Ljava/lang/String;)V')
def setName(self, name):
pass # Implementation handled by decorator
@java_method('()Ljava/lang/String;')
def getName(self):
pass # Implementation handled by decorator
@java_method('(I)I', name='multiply')
def multiplyByTwo(self, value):
pass # Java method named 'multiply', Python method named 'multiplyByTwo'
# Usage
obj = MyJavaClass()
obj.setName('example')
name = obj.getName()
result = obj.multiplyByTwo(5)from jnius import PythonJavaClass, MetaJavaClass, java_method
class MyRunnable(PythonJavaClass, metaclass=MetaJavaClass):
__javainterfaces__ = ['java/lang/Runnable']
@java_method('()V')
def run(self):
print("Running from Python implementation of Java Runnable!")
class MyComparator(PythonJavaClass, metaclass=MetaJavaClass):
__javainterfaces__ = ['java/util/Comparator']
@java_method('(Ljava/lang/Object;Ljava/lang/Object;)I')
def compare(self, o1, o2):
# Custom comparison logic in Python
return str(o1).lower() < str(o2).lower()
# Usage - pass Python objects as Java interfaces
from jnius import autoclass
Thread = autoclass('java.lang.Thread')
Arrays = autoclass('java.util.Arrays')
# Use Python Runnable with Java Thread
runnable = MyRunnable()
thread = Thread(runnable)
thread.start()
# Use Python Comparator with Java sorting
comparator = MyComparator()
string_array = Arrays.asList(['Zebra', 'apple', 'Banana'])
string_array.sort(comparator)Java method wrappers provide introspection capabilities for examining signatures.
# Available on JavaMethod, JavaStaticMethod, and JavaMultipleMethod instances
def signatures() -> list:
"""
Get list of method signatures for introspection.
Returns:
List of signature tuples (args, return_type) for the method
"""Usage Examples:
from jnius import autoclass
# Automatic introspection with autoclass
String = autoclass('java.lang.String')
print(String.format.signatures())
# Output: [(['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/lang/String'),
# (['java/lang/String', 'java/lang/Object...'], 'java/lang/String')]
# Manual class introspection
class MyString(JavaClass, metaclass=MetaJavaClass):
__javaclass__ = 'java/lang/String'
format = JavaMultipleMethod([
('(Ljava/util/Locale;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;', True, True),
('(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;', True, True),
])
print(MyString.format.signatures())
# Shows available overloads for the format methodManual class definition offers several advantages over autoclass:
However, manual definition requires:
Install with Tessl CLI
npx tessl i tessl/pypi-pyjnius