CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyjnius

A Python module to access Java classes as Python classes using JNI.

Pending
Overview
Eval results
Files

manual-classes.mddocs/

Manual Class Definition

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.

Capabilities

Base Classes

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."""

Method 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
    """

Field Wrappers

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
    """

Core Java Object Wrapper

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 Python-Java Class

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 Method Binding

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:

Basic Manual Class Definition

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"

Class with Fields

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()

Using Java Method Decorator

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)

Python-to-Java Interface Implementation

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)

Method Introspection

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 method

Performance Comparison

Manual class definition offers several advantages over autoclass:

  • Faster instantiation: No runtime reflection overhead
  • Smaller memory footprint: Only declared methods and fields are bound
  • Type safety: Explicit signatures catch errors at definition time
  • Custom behavior: Ability to override or extend Java functionality
  • Selective exposure: Choose which methods and fields to expose

However, manual definition requires:

  • Knowledge of JNI signature format
  • Manual maintenance when Java classes change
  • More verbose code compared to autoclass

Install with Tessl CLI

npx tessl i tessl/pypi-pyjnius

docs

autoclass.md

environment.md

index.md

manual-classes.md

signatures.md

utilities.md

tile.json