API¶
This part of the documentation covers all the interfaces of jtypes.pyjnius.
Reflection classes¶
-
class
jnius.
JavaClass
¶ Base for reflecting a Java class. The idea is to subclass this JavaClass, add few
JavaMethod
,JavaStaticMethod
,JavaField
,JavaStaticField
, and you’re done.You need to define at minimum the
__javaclass__
attribute, and set the__metaclass__
toMetaJavaClass
.So the minimum class definition would look like:
from jt.jnius import JavaClass, MetaJavaClass class Stack(JavaClass): __javaclass__ = 'java/util/Stack' __metaclass__ = MetaJavaClass
-
__metaclass__
¶ Must be set to
MetaJavaClass
, otherwise, all the methods/fields declared will be not linked to the JavaClass.Note
Make sure to choose the right metaclass specifier. In Python 2 there is
__metaclass__
class attribute, in Python 3 there is a new syntaxclass Stack(JavaClass, metaclass=MetaJavaClass)
.For more info see PEP 3115.
-
__javaclass__
¶ Represents the Java class name, in the format ‘org/lang/Class’ (e.g. ‘java/util/Stack’), not ‘org.lang.Class’.
-
__javaconstructor__
¶ If not set, we assume the default constructor takes no parameters. Otherwise, it can be a list of all possible signatures of the constructor. For example, a reflection of the String java class would look like:
class String(JavaClass): __javaclass__ = 'java/lang/String' __metaclass__ = MetaJavaClass __javaconstructor__ = ( '()V', '(Ljava/lang/String;)V', '([C)V', '([CII)V', # ... )
-
-
class
jnius.
JavaMethod
¶ Reflection of a Java method.
-
__init__
(signature, static=False)¶ Create a reflection of a Java method. The signature is in the JNI format. For example:
class Stack(JavaClass): __javaclass__ = 'java/util/Stack' __metaclass__ = MetaJavaClass peek = JavaMethod('()Ljava/lang/Object;') empty = JavaMethod('()Z')
The name associated with the method is automatically set from the declaration within the JavaClass itself.
The signature can be found with javap -s. For example, if you want to fetch the signatures available for java.util.Stack:
$ javap -s java.util.Stack Compiled from "Stack.java" public class java.util.Stack extends java.util.Vector{ public java.util.Stack(); Signature: ()V public java.lang.Object push(java.lang.Object); Signature: (Ljava/lang/Object;)Ljava/lang/Object; public synchronized java.lang.Object pop(); Signature: ()Ljava/lang/Object; public synchronized java.lang.Object peek(); Signature: ()Ljava/lang/Object; public boolean empty(); Signature: ()Z public synchronized int search(java.lang.Object); Signature: (Ljava/lang/Object;)I }
-
-
class
jnius.
JavaStaticMethod
¶ Reflection of a static Java method.
-
class
jnius.
JavaField
¶ Reflection of a Java field.
-
__init__
(signature, static=False)¶ Create a reflection of a Java field. The signature is in the JNI format. For example:
class System(JavaClass): __javaclass__ = 'java/lang/System' __metaclass__ = MetaJavaClass out = JavaField('()Ljava/io/InputStream;', static=True)
The name associated to the method is automatically set from the declaration within the JavaClass itself.
-
-
class
jnius.
JavaStaticField
¶ Reflection of a static Java field.
-
class
jnius.
JavaMultipleMethod
¶ Reflection of a Java method that can be called from multiple signatures. For example, the method getBytes in the String class can be called from:
public byte[] getBytes(java.lang.String) public byte[] getBytes(java.nio.charset.Charset) public byte[] getBytes()
Let’s see how you could declare that method:
class String(JavaClass): __javaclass__ = 'java/lang/String' __metaclass__ = MetaJavaClass getBytes = JavaMultipleMethod([ '(Ljava/lang/String;)[B', '(Ljava/nio/charset/Charset;)[B', '()[B'])
Then, when you try to access this method, it will choose the best method available according to the type of the arguments you’re using. Internally, we calculate a “match” score for each available signature, and take the best one. Without going into the details, the score calculation looks something like:
a direct type match is +10
a indirect type match (like using a float for an int argument) is +5
object with unknown type (
JavaObject
) is +1otherwise, it’s considered as an error case, and returns -1
Reflection functions¶
-
jnius.
autoclass
(name)¶ Return a
JavaClass
that represents the class passed from name. The name must be written in the format a.b.c, not a/b/c.>>> from jt.jnius import autoclass >>> autoclass('java.lang.System') <class 'jnius.reflect.java.lang.System'>
autoclass can also represent a nested Java class:
>>> from jt.jnius import autoclass >>> autoclass('android.provider.Settings$Secure') <class 'jnius.reflect.android.provider.Settings$Secure'>
Note
There are sometimes cases when a Java class contains a member that is a Python keyword (such as from, class, etc). You will need to use getattr() to access the member and then you will be able to call it:
from jt.jnius import autoclass func_from = getattr(autoclass('some.java.Class'), 'from') func_from()
There is also a special case for a SomeClass.class class literal which you will find either as a result of SomeClass.getClass() or in the __javaclass__ python attribute.
Warning
Currently SomeClass.getClass() returns a different Python object, therefore to safely compare whether something is the same class in Java use A.hashCode() == B.hashCode().
Java class implementation in Python¶
-
class
jnius.
PythonJavaClass
¶ Base for creating a Java class from a Python class. This allows us to implement java interfaces completely in Python.
In reality, you’ll create a Python class that mimics the list of declared
__javainterfaces__
. When you give an instance of this class to Java, Java will just accept it and call the interface methods as declared. Under the hood, we are catching the call, and redirecting it to use your declared Python method.Your class will act as a Proxy to the Java interfaces.
You need to define at minimum the
__javainterfaces__
attribute, and declare java methods with thejava_method()
decorator.Note
Static methods and static fields are not supported.
For example, you could implement the java/util/ListIterator interface in Python like this:
from jt.jnius import PythonJavaClass, java_method class PythonListIterator(PythonJavaClass): __javainterfaces__ = ['java/util/ListIterator'] def __init__(self, collection, index=0): super(TestImplemIterator, self).__init__() self.collection = collection self.index = index @java_method('()Z') def hasNext(self): return self.index < len(self.collection.data) # <AK> fix, was: len(...) - 1 @java_method('()Ljava/lang/Object;') def next(self): obj = self.collection.data[self.index] self.index += 1 return obj # etc...
-
__javainterfaces__
¶ List of the Java interfaces you want to proxify, in the format ‘org/lang/Class’ (e.g. ‘java/util/Iterator’), not ‘org.lang.Class’.
-
__javacontext__
¶ Indicate which class loader to use, ‘system’ or ‘app’. The default is ‘system’.
By default, we assume that you are going to implement a Java interface declared in the Java API. It will use the ‘system’ class loader.
On android, all the java interfaces that you ship within the APK are not accessible with the system class loader, but with the application thread class loader. So if you wish to implement a class from an interface you’ve done in your app, use ‘app’.
-
-
jnius.
java_method
(java_signature, name=None)¶ Decoration function to use with
PythonJavaClass
. The java_signature must match the wanted signature of the interface. The name of the method will be the name of the Python method by default. You can still force it, in case of multiple signature with the same Java method name.For example:
class PythonListIterator(PythonJavaClass): __javainterfaces__ = ['java/util/ListIterator'] @java_method('()Ljava/lang/Object;') def next(self): obj = self.collection.data[self.index] self.index += 1 return obj
Another example with the same Java method name, but 2 differents signatures:
class TestImplem(PythonJavaClass): __javainterfaces__ = ['java/util/List'] @java_method('()Ljava/util/ListIterator;') def listIterator(self): return PythonListIterator(self) @java_method('(I)Ljava/util/ListIterator;', name='ListIterator') def listIteratorWithIndex(self, index): return PythonListIterator(self, index)
Java signature format¶
Java signatures have a special format that could be difficult to understand at first. Let’s look at the details. A signature is in the format:
(<argument1><argument2><...>)<return type>
All the types for any part of the signature can be one of:
L<java class>; = represent a Java object of the type <java class>
Z = represent a java/lang/Boolean;
B = represent a java/lang/Byte;
C = represent a java/lang/Character;
S = represent a java/lang/Short;
I = represent a java/lang/Integer;
J = represent a java/lang/Long;
F = represent a java/lang/Float;
D = represent a java/lang/Double;
V = represent void, available only for the return type
All the types can have the [ prefix to indicate an array. The return type can be V or empty.
A signature like:
(ILjava/util/List;)V
-> argument 1 is an integer
-> argument 2 is a java.util.List object
-> the method doesn't return anything.
(java.util.Collection;[java.lang.Object;)V
-> argument 1 is a Collection
-> argument 2 is an array of Object
-> nothing is returned
([B)Z
-> argument 1 is a Byte []
-> a boolean is returned
When you implement Java in Python, the signature of the Java method must match. Java provides a tool named javap to get the signature of any java class. For example:
$ javap -s java.util.Iterator
Compiled from "Iterator.java"
public interface java.util.Iterator{
public abstract boolean hasNext();
Signature: ()Z
public abstract java.lang.Object next();
Signature: ()Ljava/lang/Object;
public abstract void remove();
Signature: ()V
}
The signature for methods of any android class can be easily seen by following these steps:
1. $ cd path/to/android/sdk/
2. $ cd platforms/android-xx/ # Replace xx with your android version
3. $ javap -s -classpath android.jar android.app.Activity # Replace android.app.Activity with any
# android class whose methods' signature
# you want to see
JVM options and the class path¶
JVM options need to be set before from jt import jnius is called, as they cannot be changed after the VM starts up. To this end, you can:
from jt import jnius_config
jnius_config.add_options('-Xrs', '-Xmx4096')
jnius_config.set_classpath('.', '/usr/local/fem/plugins/*')
from jt import jnius
If a classpath is set with these functions, it overrides any CLASSPATH environment variable. Multiple options or path entries should be supplied as multiple arguments to the add_ and set_ functions. If no classpath is provided and CLASSPATH is not set, the path defaults to ‘.’. This functionality is not available on Android.
jtypes.pyjnius and threads¶
-
jnius.
detach
()¶ Each time you create a native thread in Python and use jtypes.pyjnius, any call to jtypes.pyjnius methods will force attachment of the native thread to the current JVM. But you must detach it before leaving the thread, and jtypes.pyjnius cannot do it for you.
Example:
import threading
from jt import jnius
def run(...):
try:
# use jnius here
finally:
jnius.detach()
If you don’t, it will crash on dalvik and ART / Android:
D/dalvikvm(16696): threadid=12: thread exiting, not yet detached (count=0)
D/dalvikvm(16696): threadid=12: thread exiting, not yet detached (count=1)
E/dalvikvm(16696): threadid=12: native thread exited without detaching
E/dalvikvm(16696): VM aborting
Or:
W/art (21168): Native thread exiting without having called DetachCurrentThread (maybe it's going to use a pthread_key_create destructor?): Thread[16,tid=21293,Native,Thread*=0x4c25c040,peer=0x677eaa70,"Thread-16219"]
F/art (21168): art/runtime/thread.cc:903] Native thread exited without calling DetachCurrentThread: Thread[16,tid=21293,Native,Thread*=0x4c25c040,peer=0x677eaa70,"Thread-16219"]
F/art (21168): art/runtime/runtime.cc:203] Runtime aborting...
F/art (21168): art/runtime/runtime.cc:203] (Aborting thread was not attached to runtime!)
F/art (21168): art/runtime/runtime.cc:203] Dumping all threads without appropriate locks held: thread list lock mutator lock
F/art (21168): art/runtime/runtime.cc:203] All threads:
F/art (21168): art/runtime/runtime.cc:203] DALVIK THREADS (16):
...