mirror of https://github.com/kivy/pyjnius.git
commit
f2e66661f5
|
@ -7,3 +7,6 @@ build
|
|||
.*.swp
|
||||
*.class
|
||||
.idea
|
||||
*~
|
||||
*.so
|
||||
*.iml
|
||||
|
|
19
.travis.yml
19
.travis.yml
|
@ -1,15 +1,24 @@
|
|||
language: python
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
# command to install dependencies
|
||||
- 2.7
|
||||
- 3.5
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install python-pip openjdk-7-jdk
|
||||
|
||||
install:
|
||||
- pip install --upgrade cython --use-mirrors
|
||||
- make
|
||||
- pip install --upgrade cython six
|
||||
|
||||
# command to run tests
|
||||
script:
|
||||
- make
|
||||
- make tests
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- http://kivy.org:5000/travisevent
|
||||
on_success: always
|
||||
on_failure: always
|
||||
on_start: always
|
||||
|
|
165
COPYING
165
COPYING
|
@ -1,165 +0,0 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2010-2013 Kivy Team and other contributors
|
||||
Copyright (c) 2010-2015 Kivy Team and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
35
Makefile
35
Makefile
|
@ -1,17 +1,32 @@
|
|||
all: build_ext
|
||||
|
||||
.PHONY: build_ext tests
|
||||
|
||||
ifdef PYTHON3
|
||||
PYTHON=python3
|
||||
NOSETESTS=nosetests-3.4
|
||||
else
|
||||
PYTHON=python
|
||||
NOSETESTS=nosetests
|
||||
endif
|
||||
|
||||
JAVAC_OPTS=-target 1.6 -source 1.6
|
||||
JAVAC=javac $(JAVAC_OPTS)
|
||||
|
||||
ANT=ant
|
||||
|
||||
build_ext:
|
||||
javac jnius/src/org/jnius/NativeInvocationHandler.java
|
||||
python setup.py build_ext --inplace -f -g
|
||||
$(ANT) all
|
||||
$(PYTHON) setup.py build_ext --inplace -f -g
|
||||
|
||||
clean:
|
||||
$(ANT) clean
|
||||
rm -rf build jnius/config.pxi
|
||||
|
||||
html:
|
||||
$(MAKE) -C docs html
|
||||
|
||||
tests: build_ext
|
||||
cd tests && javac org/jnius/HelloWorld.java
|
||||
cd tests && javac org/jnius/BasicsTest.java
|
||||
cd tests && javac org/jnius/MultipleMethods.java
|
||||
cd tests && javac org/jnius/SimpleEnum.java
|
||||
cd tests && javac org/jnius/InterfaceWithPublicEnum.java
|
||||
cd tests && javac org/jnius/ClassArgument.java
|
||||
cd tests && env PYTHONPATH=..:$(PYTHONPATH) nosetests-2.7 -v
|
||||
# for use in travis; tests whatever you got.
|
||||
# use PYTHON3=1 to force python3 in other environments.
|
||||
tests:
|
||||
(cd tests; env CLASSPATH=../build/test-classes:../build/classes PYTHONPATH=..:$(PYTHONPATH) $(NOSETESTS) -v)
|
||||
|
|
60
README.md
60
README.md
|
@ -1,9 +1,11 @@
|
|||
PyJNIus
|
||||
=======
|
||||
|
||||
Python module to access Java class as Python class, using JNI.
|
||||
A Python module to access Java classes as Python classes using JNI.
|
||||
|
||||
(Work in progress.)
|
||||
PyJNIus is a "Work In Progress".
|
||||
|
||||
[![Build Status](https://travis-ci.org/kivy/pyjnius.svg?branch=master)](https://travis-ci.org/kivy/pyjnius)
|
||||
|
||||
Quick overview
|
||||
--------------
|
||||
|
@ -26,22 +28,22 @@ hello
|
|||
Usage on desktop
|
||||
----------------
|
||||
|
||||
You need a java JDK installed (openjdk will do), cython, and make to build it
|
||||
You need a java JDK installed (OpenJDK will do), Cython and make to build it.
|
||||
|
||||
make
|
||||
|
||||
That's it! you can run the tests with
|
||||
That's it! You can run the tests using
|
||||
|
||||
make tests
|
||||
|
||||
To make sure everything is running right.
|
||||
to ensure everything is running correctly.
|
||||
|
||||
Usage with python-for-android
|
||||
-----------------------------
|
||||
|
||||
* Get http://github.com/kivy/python-for-android
|
||||
* Compile a distribution with `-m "pyjnius kivy"`
|
||||
* Then, you can do this kind of things:
|
||||
* Then, you can do this kind of thing:
|
||||
|
||||
```python
|
||||
from time import sleep
|
||||
|
@ -87,9 +89,9 @@ I/python ( 5983): [0.13407529890537262, 9.4235782623291016, 2.2026655673980713]
|
|||
Advanced example
|
||||
----------------
|
||||
|
||||
When you use autoclass, it will discover all the methods and fields within the object, and resolve it.
|
||||
For now, it can be better to declare and use only what you need.
|
||||
The previous example can be done manually:
|
||||
When you use autoclass, it will discover all the methods and fields of the
|
||||
object and resolve them. For now, it is better to declare and use only what you
|
||||
need. The previous example can be done manually as follows:
|
||||
|
||||
```python
|
||||
from time import sleep
|
||||
|
@ -112,7 +114,41 @@ for x in xrange(20):
|
|||
sleep(.1)
|
||||
```
|
||||
|
||||
Support/Discussion
|
||||
------------------
|
||||
Support
|
||||
-------
|
||||
|
||||
mailto:pyjnius-dev@googlegroups.com
|
||||
If you need assistance, you can ask for help on our mailing list:
|
||||
|
||||
* User Group : https://groups.google.com/group/kivy-users
|
||||
* Email : kivy-users@googlegroups.com
|
||||
|
||||
We also have an IRC channel:
|
||||
|
||||
* Server : irc.freenode.net
|
||||
* Port : 6667, 6697 (SSL only)
|
||||
* Channel : #kivy
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
We love pull requests and discussing novel ideas. Check out our
|
||||
[contribution guide](http://kivy.org/docs/contribute.html) and
|
||||
feel free to improve PyJNIus.
|
||||
|
||||
The following mailing list and IRC channel are used exclusively for
|
||||
discussions about developing the Kivy framework and its sister projects:
|
||||
|
||||
* Dev Group : https://groups.google.com/group/kivy-dev
|
||||
* Email : kivy-dev@googlegroups.com
|
||||
|
||||
IRC channel:
|
||||
|
||||
* Server : irc.freenode.net
|
||||
* Port : 6667, 6697 (SSL only)
|
||||
* Channel : #kivy-dev
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
PyJNIus is released under the terms of the MIT License. Please refer to the
|
||||
LICENSE file.
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<project>
|
||||
<target name="clean">
|
||||
<delete dir="build/classes"/>
|
||||
<delete dir="build/test-classes"/>
|
||||
</target>
|
||||
|
||||
<target name="compile">
|
||||
<mkdir dir="build/classes"/>
|
||||
<javac srcdir="jnius/src" destdir="build/classes"
|
||||
includeantruntime='false' source='1.6' target='1.6' />
|
||||
</target>
|
||||
|
||||
<target name="test-compile">
|
||||
<mkdir dir="build/test-classes"/>
|
||||
<javac srcdir="tests/java-src" destdir="build/test-classes"
|
||||
includeantruntime='false' source='1.6' target='1.6' />
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
<jar destfile="build/pyjnius.jar" basedir="build/classes">
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="all" depends="jar,test-compile"/>
|
||||
</project>
|
|
@ -3,37 +3,40 @@
|
|||
Android
|
||||
=======
|
||||
|
||||
Android have a great and extensive API to control the device, your application
|
||||
etc. Some part of the Android API is accessible directly with Pyjnius, but some
|
||||
of them requires you to code in Java.
|
||||
Android has a great and extensive API to control devices, your application
|
||||
etc. Some parts of the Android API are directly accessible with Pyjnius but
|
||||
some of them require you to code in Java.
|
||||
|
||||
|
||||
Get the DPI
|
||||
-----------
|
||||
|
||||
The `DisplayMetrics
|
||||
<http://developer.android.com/reference/android/util/DisplayMetrics.html>`_ contains multiple fields that can return a lot of information about the device's screen::
|
||||
<http://developer.android.com/reference/android/util/DisplayMetrics.html>`_
|
||||
contains multiple fields that can return a lot of information about the device's
|
||||
screen::
|
||||
|
||||
from jnius import autoclass
|
||||
DisplayMetrics = autoclass('android.util.DisplayMetrics')
|
||||
metrics = DisplayMetrics()
|
||||
print 'DPI', metrics.getDeviceDensity()
|
||||
|
||||
Note: To access nested classes, use `$` like:
|
||||
`autoclass('android.provider.MediaStore$Images$Media')`.
|
||||
.. Note ::
|
||||
To access nested classes, use `$` like:
|
||||
`autoclass('android.provider.MediaStore$Images$Media')`.
|
||||
|
||||
Recording an audio file
|
||||
-----------------------
|
||||
|
||||
By looking at the `Audio Capture
|
||||
<http://developer.android.com/guide/topics/media/audio-capture.html>`_ guide
|
||||
from Android, you can see the simple step to do for recording an audio file.
|
||||
Let's do in with Pyjnius::
|
||||
for Android, you can see the simple steps for recording an audio file.
|
||||
Let's do it with Pyjnius::
|
||||
|
||||
from jnius import autoclass
|
||||
from time import sleep
|
||||
|
||||
# get the needed Java class
|
||||
# get the needed Java classes
|
||||
MediaRecorder = autoclass('android.media.MediaRecorder')
|
||||
AudioSource = autoclass('android.media.MediaRecorder$AudioSource')
|
||||
OutputFormat = autoclass('android.media.MediaRecorder$OutputFormat')
|
||||
|
@ -42,9 +45,9 @@ Let's do in with Pyjnius::
|
|||
# create out recorder
|
||||
mRecorder = MediaRecorder()
|
||||
mRecorder.setAudioSource(AudioSource.MIC)
|
||||
mRecorder.setOutputFormat(OutputFormat.THREE_GPP)
|
||||
mRecorder.setOutputFormat(OutputFormat.THREE_GPP)
|
||||
mRecorder.setOutputFile('/sdcard/testrecorder.3gp')
|
||||
mRecorder.setAudioEncoder(AudioEncoder.ARM_NB)
|
||||
mRecorder.setAudioEncoder(AudioEncoder.AMR_NB)
|
||||
mRecorder.prepare()
|
||||
|
||||
# record 5 seconds
|
||||
|
@ -83,16 +86,17 @@ using the Android Media Player too::
|
|||
mPlayer.release()
|
||||
|
||||
|
||||
Accessing to the Activity
|
||||
-------------------------
|
||||
Accessing the Activity
|
||||
----------------------
|
||||
|
||||
This example will show how to start a new Intent. Be careful, some Intent
|
||||
require you to setup some parts in the `AndroidManifest.xml`, and have some
|
||||
actions done within your own Activity. This is out of the scope of Pyjnius, but
|
||||
we'll show you what is the best approach for playing with it.
|
||||
This example will show how to start a new Intent. Be careful: some Intents
|
||||
require you to setup parts in the `AndroidManifest.xml` and have some
|
||||
actions performed within your Activity. This is out of the scope of Pyjnius but
|
||||
we'll show you what the best approach is for playing with it.
|
||||
|
||||
On Python-for-android project, you can access to the default `PythonActivity`.
|
||||
Let's see an example that demonstrate the `Intent.ACTION_VIEW`::
|
||||
Using the Python-for-android project, you can access the default
|
||||
`PythonActivity`. Let's look at an example that demonstrates the
|
||||
`Intent.ACTION_VIEW`::
|
||||
|
||||
from jnius import cast
|
||||
from jnius import autoclass
|
||||
|
@ -108,9 +112,9 @@ Let's see an example that demonstrate the `Intent.ACTION_VIEW`::
|
|||
intent.setData(Uri.parse('http://kivy.org'))
|
||||
|
||||
# PythonActivity.mActivity is the instance of the current Activity
|
||||
# BUT, startActivity is a method from the Activity class, not our
|
||||
# BUT, startActivity is a method from the Activity class, not from our
|
||||
# PythonActivity.
|
||||
# We need to cast our class into an activity, and use it
|
||||
# We need to cast our class into an activity and use it
|
||||
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
|
||||
currentActivity.startActivity(intent)
|
||||
|
||||
|
@ -120,12 +124,12 @@ Let's see an example that demonstrate the `Intent.ACTION_VIEW`::
|
|||
Accelerometer access
|
||||
--------------------
|
||||
|
||||
The accelerometer is a good example that show how you need to wrote a little
|
||||
The accelerometer is a good example that shows how to write a little
|
||||
Java code that you can access later with Pyjnius.
|
||||
|
||||
The `SensorManager
|
||||
<http://developer.android.com/reference/android/hardware/SensorManager.html>`_
|
||||
lets you access to the device's sensors. To use it, you need to register a
|
||||
lets you access the device's sensors. To use it, you need to register a
|
||||
`SensorEventListener
|
||||
<http://developer.android.com/reference/android/hardware/SensorEventListener.html>`_
|
||||
and overload 2 abstract methods: `onAccuracyChanged` and `onSensorChanged`.
|
||||
|
@ -147,7 +151,7 @@ everything needed for accessing the accelerometer::
|
|||
|
||||
// Contain the last event we got from the listener
|
||||
static public SensorEvent lastEvent = null;
|
||||
|
||||
|
||||
// Define a new listener
|
||||
static class AccelListener implements SensorEventListener {
|
||||
public void onSensorChanged(SensorEvent ev) {
|
||||
|
|
|
@ -293,7 +293,7 @@ All the types for any part of the signature can be one of:
|
|||
* D = represent a java/lang/Double;
|
||||
* V = represent void, available only for the return type
|
||||
|
||||
All the types can have the `[]` suffix to design an array. The return type can be `V` or empty.
|
||||
All the types can have the `[` prefix to design an array. The return type can be `V` or empty.
|
||||
|
||||
A signature like::
|
||||
|
||||
|
@ -302,14 +302,18 @@ A signature like::
|
|||
-> argument 2 is a java.util.List object
|
||||
-> the method doesn't return anything.
|
||||
|
||||
(java.util.Collection, java.lang.Object[]);
|
||||
(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 provide a tool named `javap` to get the signature of any java class. For
|
||||
Java provides a tool named `javap` to get the signature of any java class. For
|
||||
example::
|
||||
|
||||
$ javap -s java.util.Iterator
|
||||
|
@ -323,3 +327,59 @@ example::
|
|||
Signature: ()V
|
||||
}
|
||||
|
||||
|
||||
JVM options and the class path
|
||||
------------------------------
|
||||
|
||||
JVM options need to be set before `import jnius` is called, as they cannot be changed after the VM starts up.
|
||||
To this end, you can::
|
||||
|
||||
import jnius_config
|
||||
jnius_config.add_options('-Xrs', '-Xmx4096')
|
||||
jnius_config.set_classpath('.', '/usr/local/fem/plugins/*')
|
||||
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.
|
||||
|
||||
|
||||
Pyjnius and threads
|
||||
-------------------
|
||||
|
||||
.. function:: detach()
|
||||
|
||||
Each time you create a native thread in Python and uses Pyjnius, any call to
|
||||
Pyjnius methods will force attachment of the native thread to the current JVM.
|
||||
But you must detach it before leaving the thread, and Pyjnius cannot do it for
|
||||
you.
|
||||
|
||||
Example::
|
||||
|
||||
import threading
|
||||
import jnius
|
||||
|
||||
def run(...):
|
||||
try:
|
||||
# use pyjnius 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):
|
||||
...
|
||||
|
|
|
@ -11,3 +11,28 @@ __version__ = '1.1-dev'
|
|||
|
||||
from .jnius import *
|
||||
from .reflect import *
|
||||
|
||||
# XXX monkey patch methods that cannot be in cython.
|
||||
# Cython doesn't allow to set new attribute on methods it compiled
|
||||
|
||||
HASHCODE_MAX = 2 ** 31 - 1
|
||||
|
||||
class PythonJavaClass_(PythonJavaClass):
|
||||
|
||||
@java_method('()I', name='hashCode')
|
||||
def hashCode(self):
|
||||
return id(self) % HASHCODE_MAX
|
||||
|
||||
@java_method('()Ljava/lang/String;', name='hashCode')
|
||||
def hashCode_(self):
|
||||
return '{}'.format(self.hashCode())
|
||||
|
||||
@java_method('()Ljava/lang/String;', name='toString')
|
||||
def toString(self):
|
||||
return repr(self)
|
||||
|
||||
@java_method('(Ljava/lang/Object;)Z', name='equals')
|
||||
def equals(self, other):
|
||||
return self.hashCode() == other.hashCode()
|
||||
|
||||
PythonJavaClass = PythonJavaClass_
|
||||
|
|
|
@ -401,4 +401,5 @@ cdef extern from "jni.h":
|
|||
|
||||
ctypedef struct JNIInvokeInterface:
|
||||
jint (*AttachCurrentThread)(JavaVM *, JNIEnv **, void *)
|
||||
jint (*DetachCurrentThread)(JavaVM *)
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ Python::
|
|||
|
||||
__all__ = ('JavaObject', 'JavaClass', 'JavaMethod', 'JavaField',
|
||||
'MetaJavaClass', 'JavaException', 'cast', 'find_javaclass',
|
||||
'PythonJavaClass', 'java_method')
|
||||
'PythonJavaClass', 'java_method', 'detach')
|
||||
|
||||
from libc.stdlib cimport malloc, free
|
||||
from functools import partial
|
||||
|
@ -99,14 +99,19 @@ include "config.pxi"
|
|||
|
||||
IF JNIUS_PLATFORM == "android":
|
||||
include "jnius_jvm_android.pxi"
|
||||
ELSE:
|
||||
ELIF JNIUS_PLATFORM == "win32":
|
||||
include "jnius_jvm_desktop.pxi"
|
||||
ELSE:
|
||||
include "jnius_jvm_dlopen.pxi"
|
||||
|
||||
include "jnius_env.pxi"
|
||||
include "jnius_utils.pxi"
|
||||
include "jnius_conversion.pxi"
|
||||
include "jnius_localref.pxi"
|
||||
include "jnius_nativetypes.pxi"
|
||||
IF JNIUS_PYTHON3:
|
||||
include "jnius_nativetypes3.pxi"
|
||||
ELSE:
|
||||
include "jnius_nativetypes.pxi"
|
||||
|
||||
include "jnius_export_func.pxi"
|
||||
include "jnius_export_class.pxi"
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
from cpython.version cimport PY_MAJOR_VERSION
|
||||
|
||||
cdef jstringy_arg(argtype):
|
||||
return argtype in ('Ljava/lang/String;',
|
||||
'Ljava/lang/CharSequence;',
|
||||
'Ljava/lang/Object;')
|
||||
|
||||
cdef void release_args(JNIEnv *j_env, tuple definition_args, jvalue *j_args, args) except *:
|
||||
# do the conversion from a Python object to Java from a Java definition
|
||||
cdef JavaObject jo
|
||||
|
@ -9,7 +16,7 @@ cdef void release_args(JNIEnv *j_env, tuple definition_args, jvalue *j_args, arg
|
|||
if py_arg is None:
|
||||
j_args[index].l = NULL
|
||||
if isinstance(py_arg, basestring) and \
|
||||
argtype in ('Ljava/lang/String;', 'Ljava/lang/Object;'):
|
||||
jstringy_arg(argtype):
|
||||
j_env[0].DeleteLocalRef(j_env, j_args[index].l)
|
||||
elif argtype[0] == '[':
|
||||
ret = convert_jarray_to_python(j_env, argtype[1:], j_args[index].l)
|
||||
|
@ -19,7 +26,6 @@ cdef void release_args(JNIEnv *j_env, tuple definition_args, jvalue *j_args, arg
|
|||
pass
|
||||
j_env[0].DeleteLocalRef(j_env, j_args[index].l)
|
||||
|
||||
|
||||
cdef void populate_args(JNIEnv *j_env, tuple definition_args, jvalue *j_args, args) except *:
|
||||
# do the conversion from a Python object to Java from a Java definition
|
||||
cdef JavaClassStorage jcs
|
||||
|
@ -27,6 +33,7 @@ cdef void populate_args(JNIEnv *j_env, tuple definition_args, jvalue *j_args, ar
|
|||
cdef JavaClass jc
|
||||
cdef PythonJavaClass pc
|
||||
cdef int index
|
||||
cdef bytes py_str
|
||||
for index, argtype in enumerate(definition_args):
|
||||
py_arg = args[index]
|
||||
if argtype == 'Z':
|
||||
|
@ -48,10 +55,10 @@ cdef void populate_args(JNIEnv *j_env, tuple definition_args, jvalue *j_args, ar
|
|||
elif argtype[0] == 'L':
|
||||
if py_arg is None:
|
||||
j_args[index].l = NULL
|
||||
elif isinstance(py_arg, basestring) and \
|
||||
argtype in ('Ljava/lang/String;', 'Ljava/lang/Object;'):
|
||||
j_args[index].l = j_env[0].NewStringUTF(
|
||||
j_env, <char *><bytes>py_arg.encode('utf-8'))
|
||||
elif (isinstance(py_arg, basestring) or (PY_MAJOR_VERSION >=3 and isinstance(py_arg, str))) \
|
||||
and jstringy_arg(argtype):
|
||||
py_str = <bytes>py_arg.encode('utf-8')
|
||||
j_args[index].l = j_env[0].NewStringUTF(j_env, <char *>py_str)
|
||||
elif isinstance(py_arg, JavaClass):
|
||||
jc = py_arg
|
||||
check_assignable_from(j_env, jc, argtype[1:-1])
|
||||
|
@ -82,28 +89,30 @@ cdef void populate_args(JNIEnv *j_env, tuple definition_args, jvalue *j_args, ar
|
|||
if py_arg is None:
|
||||
j_args[index].l = NULL
|
||||
continue
|
||||
if isinstance(py_arg, basestring):
|
||||
if isinstance(py_arg, basestring) and PY_MAJOR_VERSION < 3:
|
||||
if argtype == '[B':
|
||||
py_arg = map(ord, py_arg)
|
||||
elif argtype == '[C':
|
||||
py_arg = list(py_arg)
|
||||
if isinstance(py_arg, str) and PY_MAJOR_VERSION >= 3 and argtype == '[C':
|
||||
py_arg = list(py_arg)
|
||||
if isinstance(py_arg, ByteArray) and argtype != '[B':
|
||||
raise JavaException(
|
||||
'Cannot use ByteArray for signature {}'.format(argtype))
|
||||
if not isinstance(py_arg, (list, tuple, ByteArray)):
|
||||
if not isinstance(py_arg, (list, tuple, ByteArray, bytes)):
|
||||
raise JavaException('Expecting a python list/tuple, got '
|
||||
'{0!r}'.format(py_arg))
|
||||
j_args[index].l = convert_pyarray_to_java(
|
||||
j_env, argtype[1:], py_arg)
|
||||
|
||||
|
||||
cdef convert_jobject_to_python(JNIEnv *j_env, bytes definition, jobject j_object):
|
||||
cdef convert_jobject_to_python(JNIEnv *j_env, definition, jobject j_object):
|
||||
# Convert a Java Object to a Python object, according to the definition.
|
||||
# If the definition is a java/lang/Object, then try to determine what is it
|
||||
# exactly.
|
||||
cdef char *c_str
|
||||
cdef bytes py_str
|
||||
cdef bytes r = definition[1:-1]
|
||||
r = definition[1:-1]
|
||||
cdef JavaObject ret_jobject
|
||||
cdef JavaClass ret_jc
|
||||
cdef jclass retclass
|
||||
|
@ -112,6 +121,7 @@ cdef convert_jobject_to_python(JNIEnv *j_env, bytes definition, jobject j_object
|
|||
# we got a generic object -> lookup for the real name instead.
|
||||
if r == 'java/lang/Object':
|
||||
r = definition = lookup_java_object_name(j_env, j_object)
|
||||
print('cjtp:r {0} definition {1}'.format(r, definition))
|
||||
|
||||
if definition[0] == '[':
|
||||
return convert_jarray_to_python(j_env, definition[1:], j_object)
|
||||
|
@ -122,11 +132,14 @@ cdef convert_jobject_to_python(JNIEnv *j_env, bytes definition, jobject j_object
|
|||
# Ie, B would be passed as Ljava/lang/Character;
|
||||
|
||||
# if we got a string, just convert back to Python str.
|
||||
if r == 'java/lang/String':
|
||||
if r in ('java/lang/String', 'java/lang/CharSequence'):
|
||||
c_str = <char *>j_env[0].GetStringUTFChars(j_env, j_object, NULL)
|
||||
py_str = <bytes>c_str
|
||||
j_env[0].ReleaseStringUTFChars(j_env, j_object, c_str)
|
||||
return py_str
|
||||
if PY_MAJOR_VERSION < 3:
|
||||
return py_str
|
||||
else:
|
||||
return py_str.decode('utf-8')
|
||||
|
||||
# XXX should be deactivable from configuration
|
||||
# ie, user might not want autoconvertion of lang classes.
|
||||
|
@ -171,7 +184,7 @@ cdef convert_jobject_to_python(JNIEnv *j_env, bytes definition, jobject j_object
|
|||
from .reflect import Object
|
||||
ret_jc = Object(noinstance=True)
|
||||
else:
|
||||
from reflect import autoclass
|
||||
from .reflect import autoclass
|
||||
ret_jc = autoclass(r.replace('/', '.'))(noinstance=True)
|
||||
else:
|
||||
ret_jc = jclass_register[r](noinstance=True)
|
||||
|
@ -274,6 +287,20 @@ cdef convert_jarray_to_python(JNIEnv *j_env, definition, jobject j_object):
|
|||
obj = convert_jobject_to_python(j_env, definition, j_object_item)
|
||||
ret.append(obj)
|
||||
j_env[0].DeleteLocalRef(j_env, j_object_item)
|
||||
|
||||
elif r == '[':
|
||||
r = definition[1:]
|
||||
ret = []
|
||||
for i in range(array_size):
|
||||
j_object_item = j_env[0].GetObjectArrayElement(
|
||||
j_env, j_object, i)
|
||||
if j_object_item == NULL:
|
||||
ret.append(None)
|
||||
continue
|
||||
obj = convert_jarray_to_python(j_env, r, j_object_item)
|
||||
ret.append(obj)
|
||||
j_env[0].DeleteLocalRef(j_env, j_object_item)
|
||||
|
||||
else:
|
||||
raise JavaException('Invalid return definition for array')
|
||||
|
||||
|
@ -295,9 +322,11 @@ cdef jobject convert_python_to_jobject(JNIEnv *j_env, definition, obj) except *:
|
|||
elif definition[0] == 'L':
|
||||
if obj is None:
|
||||
return NULL
|
||||
elif isinstance(obj, basestring) and \
|
||||
definition in ('Ljava/lang/String;', 'Ljava/lang/Object;'):
|
||||
elif isinstance(obj, basestring) and jstringy_arg(definition):
|
||||
return j_env[0].NewStringUTF(j_env, <char *><bytes>obj)
|
||||
elif isinstance(obj, str) and PY_MAJOR_VERSION >= 3 and jstringy_arg(definition):
|
||||
utf8 = obj.encode('utf-8')
|
||||
return j_env[0].NewStringUTF(j_env, <char *><bytes>utf8)
|
||||
elif isinstance(obj, (int, long)) and \
|
||||
definition in (
|
||||
'Ljava/lang/Integer;',
|
||||
|
@ -337,13 +366,23 @@ cdef jobject convert_python_to_jobject(JNIEnv *j_env, definition, obj) except *:
|
|||
definition[1:-1], obj))
|
||||
|
||||
elif definition[0] == '[':
|
||||
conversions = {
|
||||
int: 'I',
|
||||
bool: 'Z',
|
||||
long: 'J',
|
||||
float: 'F',
|
||||
basestring: 'Ljava/lang/String;',
|
||||
}
|
||||
if PY_MAJOR_VERSION < 3:
|
||||
conversions = {
|
||||
int: 'I',
|
||||
bool: 'Z',
|
||||
long: 'J',
|
||||
float: 'F',
|
||||
basestring: 'Ljava/lang/String;',
|
||||
}
|
||||
else:
|
||||
conversions = {
|
||||
int: 'I',
|
||||
bool: 'Z',
|
||||
long: 'J',
|
||||
float: 'F',
|
||||
str: 'Ljava/lang/String;',
|
||||
bytes: 'B'
|
||||
}
|
||||
retclass = j_env[0].FindClass(j_env, 'java/lang/Object')
|
||||
retobject = j_env[0].NewObjectArray(j_env, len(obj), retclass, NULL)
|
||||
for index, item in enumerate(obj):
|
||||
|
@ -399,6 +438,7 @@ cdef jobject convert_pyarray_to_java(JNIEnv *j_env, definition, pyarray) except
|
|||
cdef jobject ret = NULL
|
||||
cdef int array_size = len(pyarray)
|
||||
cdef int i
|
||||
cdef unsigned char c_tmp
|
||||
cdef jboolean j_boolean
|
||||
cdef jbyte j_byte
|
||||
cdef jchar j_char
|
||||
|
@ -418,13 +458,23 @@ cdef jobject convert_pyarray_to_java(JNIEnv *j_env, definition, pyarray) except
|
|||
if definition == 'Ljava/lang/Object;' and len(pyarray) > 0:
|
||||
# then the method will accept any array type as param
|
||||
# let's be as precise as we can
|
||||
conversions = {
|
||||
int: 'I',
|
||||
bool: 'Z',
|
||||
long: 'J',
|
||||
float: 'F',
|
||||
basestring: 'Ljava/lang/String;',
|
||||
}
|
||||
if PY_MAJOR_VERSION < 3:
|
||||
conversions = {
|
||||
int: 'I',
|
||||
bool: 'Z',
|
||||
long: 'J',
|
||||
float: 'F',
|
||||
basestring: 'Ljava/lang/String;',
|
||||
}
|
||||
else:
|
||||
conversions = {
|
||||
int: 'I',
|
||||
bool: 'Z',
|
||||
long: 'J',
|
||||
float: 'F',
|
||||
bytes: 'B',
|
||||
str: 'Ljava/lang/String;',
|
||||
}
|
||||
for _type, override in conversions.iteritems():
|
||||
if isinstance(pyarray[0], _type):
|
||||
definition = override
|
||||
|
@ -445,7 +495,8 @@ cdef jobject convert_pyarray_to_java(JNIEnv *j_env, definition, pyarray) except
|
|||
ret, 0, array_size, a_bytes._buf)
|
||||
else:
|
||||
for i in range(array_size):
|
||||
j_byte = pyarray[i]
|
||||
c_tmp = pyarray[i]
|
||||
j_byte = <signed char>c_tmp
|
||||
j_env[0].SetByteArrayRegion(j_env,
|
||||
ret, i, 1, &j_byte)
|
||||
|
||||
|
@ -492,8 +543,9 @@ cdef jobject convert_pyarray_to_java(JNIEnv *j_env, definition, pyarray) except
|
|||
ret, i, 1, &j_double)
|
||||
|
||||
elif definition[0] == 'L':
|
||||
defstr = str_for_c(definition[1:-1])
|
||||
j_class = j_env[0].FindClass(
|
||||
j_env, <bytes>definition[1:-1])
|
||||
j_env, <bytes>defstr)
|
||||
if j_class == NULL:
|
||||
raise JavaException('Cannot create array with a class not '
|
||||
'found {0!r}'.format(definition[1:-1]))
|
||||
|
@ -504,12 +556,19 @@ cdef jobject convert_pyarray_to_java(JNIEnv *j_env, definition, pyarray) except
|
|||
if arg is None:
|
||||
j_env[0].SetObjectArrayElement(
|
||||
j_env, <jobjectArray>ret, i, NULL)
|
||||
elif isinstance(arg, basestring) and \
|
||||
definition in ('Ljava/lang/String;', 'Ljava/lang/Object;'):
|
||||
elif isinstance(arg, basestring) and PY_MAJOR_VERSION < 3 and \
|
||||
jstringy_arg(definition):
|
||||
j_string = j_env[0].NewStringUTF(
|
||||
j_env, <bytes>arg)
|
||||
j_env[0].SetObjectArrayElement(
|
||||
j_env, <jobjectArray>ret, i, j_string)
|
||||
elif isinstance(arg, str) and PY_MAJOR_VERSION >= 3 and \
|
||||
jstringy_arg(definition):
|
||||
utf8 = arg.encode('utf-8')
|
||||
j_string = j_env[0].NewStringUTF(
|
||||
j_env, <bytes>utf8)
|
||||
j_env[0].SetObjectArrayElement(
|
||||
j_env, <jobjectArray>ret, i, j_string)
|
||||
elif isinstance(arg, JavaClass):
|
||||
jc = arg
|
||||
check_assignable_from(j_env, jc, definition[1:-1])
|
||||
|
@ -526,6 +585,17 @@ cdef jobject convert_pyarray_to_java(JNIEnv *j_env, definition, pyarray) except
|
|||
else:
|
||||
raise JavaException('Invalid variable used for L array', definition, pyarray)
|
||||
|
||||
elif definition[0] == '[':
|
||||
subdef = definition[1:]
|
||||
eproto = convert_pyarray_to_java(j_env, subdef, pyarray[0])
|
||||
ret = j_env[0].NewObjectArray(
|
||||
j_env, array_size, j_env[0].GetObjectClass(j_env, eproto), NULL)
|
||||
j_env[0].SetObjectArrayElement(
|
||||
j_env, <jobjectArray>ret, 0, eproto)
|
||||
for i in range(1, array_size):
|
||||
j_env[0].SetObjectArrayElement(
|
||||
j_env, <jobjectArray>ret, i, convert_pyarray_to_java(j_env, subdef, pyarray[i]))
|
||||
|
||||
else:
|
||||
raise JavaException('Invalid array definition', definition, pyarray)
|
||||
|
||||
|
|
|
@ -4,11 +4,13 @@ cdef JNIEnv *default_env = NULL
|
|||
cdef extern int gettid()
|
||||
cdef JavaVM *jvm = NULL
|
||||
|
||||
cdef JNIEnv *get_jnienv():
|
||||
cdef JNIEnv *get_jnienv() except NULL:
|
||||
global default_env
|
||||
# first call, init.
|
||||
if default_env == NULL:
|
||||
default_env = get_platform_jnienv()
|
||||
if default_env == NULL:
|
||||
return NULL
|
||||
default_env[0].GetJavaVM(default_env, &jvm)
|
||||
|
||||
# return the current env attached to the thread
|
||||
|
@ -17,3 +19,7 @@ cdef JNIEnv *get_jnienv():
|
|||
jvm[0].AttachCurrentThread(jvm, &env, NULL)
|
||||
return env
|
||||
|
||||
|
||||
def detach():
|
||||
jvm[0].DetachCurrentThread(jvm)
|
||||
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
|
||||
class JavaException(Exception):
|
||||
'''Can be a real java exception, or just an exception from the wrapper.
|
||||
'''
|
||||
pass
|
||||
classname = None # The classname of the exception
|
||||
innermessage = None # The message of the inner exception
|
||||
stacktrace = None # The stack trace of the inner exception
|
||||
|
||||
def __init__(self, message, classname=None, innermessage=None, stacktrace=None):
|
||||
self.classname = classname
|
||||
self.innermessage = innermessage
|
||||
self.stacktrace = stacktrace
|
||||
Exception.__init__(self, message)
|
||||
|
||||
|
||||
cdef class JavaObject(object):
|
||||
|
@ -34,7 +41,7 @@ cdef dict jclass_register = {}
|
|||
class MetaJavaClass(type):
|
||||
def __new__(meta, classname, bases, classDict):
|
||||
meta.resolve_class(classDict)
|
||||
tp = type.__new__(meta, classname, bases, classDict)
|
||||
tp = type.__new__(meta, str(classname), bases, classDict)
|
||||
jclass_register[classDict['__javaclass__']] = tp
|
||||
return tp
|
||||
|
||||
|
@ -73,19 +80,22 @@ class MetaJavaClass(type):
|
|||
|
||||
with nogil:
|
||||
classLoader = j_env[0].CallStaticObjectMethodA(
|
||||
j_env, baseclass, getClassLoader, [])
|
||||
j_env, baseclass, getClassLoader, NULL)
|
||||
jargs = <jobject *>malloc(sizeof(jobject) * 2)
|
||||
jargs[0] = <jobject *>classLoader
|
||||
jargs[1] = interfaces
|
||||
jcs.j_cls = j_env[0].CallStaticObjectMethod(
|
||||
j_env, baseclass, getProxyClass, jargs)
|
||||
|
||||
j_env[0].DeleteLocalRef(j_env, baseclass)
|
||||
|
||||
if jcs.j_cls == NULL:
|
||||
raise JavaException('Unable to create the class'
|
||||
' {0}'.format(__javaclass__))
|
||||
else:
|
||||
class_name = str_for_c(__javaclass__)
|
||||
jcs.j_cls = j_env[0].FindClass(j_env,
|
||||
<char *>__javaclass__)
|
||||
<char *>class_name)
|
||||
if jcs.j_cls == NULL:
|
||||
raise JavaException('Unable to find the class'
|
||||
' {0}'.format(__javaclass__))
|
||||
|
@ -100,29 +110,29 @@ class MetaJavaClass(type):
|
|||
# search all the static JavaMethod within our class, and resolve them
|
||||
cdef JavaMethod jm
|
||||
cdef JavaMultipleMethod jmm
|
||||
for name, value in classDict.iteritems():
|
||||
for name, value in items_compat(classDict):
|
||||
if isinstance(value, JavaMethod):
|
||||
jm = value
|
||||
if not jm.is_static:
|
||||
continue
|
||||
jm.set_resolve_info(j_env, jcs.j_cls, None,
|
||||
name, __javaclass__)
|
||||
str_for_c(name), str_for_c(__javaclass__))
|
||||
elif isinstance(value, JavaMultipleMethod):
|
||||
jmm = value
|
||||
jmm.set_resolve_info(j_env, jcs.j_cls, None,
|
||||
name, __javaclass__)
|
||||
str_for_c(name), str_for_c(__javaclass__))
|
||||
|
||||
|
||||
# search all the static JavaField within our class, and resolve them
|
||||
cdef JavaField jf
|
||||
for name, value in classDict.iteritems():
|
||||
for name, value in items_compat(classDict):
|
||||
if not isinstance(value, JavaField):
|
||||
continue
|
||||
jf = value
|
||||
if not jf.is_static:
|
||||
continue
|
||||
jf.set_resolve_info(j_env, jcs.j_cls,
|
||||
name, __javaclass__)
|
||||
str_for_c(name), str_for_c(__javaclass__))
|
||||
|
||||
|
||||
cdef class JavaClass(object):
|
||||
|
@ -209,8 +219,9 @@ cdef class JavaClass(object):
|
|||
populate_args(j_env, d_args, j_args, args_)
|
||||
|
||||
# get the java constructor
|
||||
defstr = str_for_c(definition)
|
||||
constructor = j_env[0].GetMethodID(
|
||||
j_env, self.j_cls, '<init>', <char *><bytes>definition)
|
||||
j_env, self.j_cls, '<init>', <char *><bytes>defstr)
|
||||
if constructor == NULL:
|
||||
raise JavaException('Unable to found the constructor'
|
||||
' for {0}'.format(self.__javaclass__))
|
||||
|
@ -238,23 +249,23 @@ cdef class JavaClass(object):
|
|||
cdef JavaMethod jm
|
||||
cdef JavaMultipleMethod jmm
|
||||
cdef JNIEnv *j_env = get_jnienv()
|
||||
for name, value in self.__class__.__dict__.iteritems():
|
||||
for name, value in items_compat(self.__class__.__dict__):
|
||||
if isinstance(value, JavaMethod):
|
||||
jm = value
|
||||
if jm.is_static:
|
||||
continue
|
||||
jm.set_resolve_info(j_env, self.j_cls, self.j_self,
|
||||
name, self.__javaclass__)
|
||||
str_for_c(name), str_for_c(self.__javaclass__))
|
||||
elif isinstance(value, JavaMultipleMethod):
|
||||
jmm = value
|
||||
jmm.set_resolve_info(j_env, self.j_cls, self.j_self,
|
||||
name, self.__javaclass__)
|
||||
str_for_c(name), str_for_c(self.__javaclass__))
|
||||
|
||||
cdef void resolve_fields(self) except *:
|
||||
# search all the JavaField within our class, and resolve them
|
||||
cdef JavaField jf
|
||||
cdef JNIEnv *j_env = get_jnienv()
|
||||
for name, value in self.__class__.__dict__.iteritems():
|
||||
for name, value in items_compat(self.__class__.__dict__):
|
||||
if not isinstance(value, JavaField):
|
||||
continue
|
||||
jf = value
|
||||
|
@ -275,10 +286,10 @@ cdef class JavaField(object):
|
|||
cdef jfieldID j_field
|
||||
cdef JNIEnv *j_env
|
||||
cdef jclass j_cls
|
||||
cdef bytes definition
|
||||
cdef object is_static
|
||||
cdef bytes name
|
||||
cdef bytes classname
|
||||
cdef name
|
||||
cdef classname
|
||||
cdef definition
|
||||
|
||||
def __cinit__(self, definition, **kwargs):
|
||||
self.j_field = NULL
|
||||
|
@ -290,7 +301,7 @@ cdef class JavaField(object):
|
|||
self.is_static = kwargs.get('static', False)
|
||||
|
||||
cdef void set_resolve_info(self, JNIEnv *j_env, jclass j_cls,
|
||||
bytes name, bytes classname):
|
||||
name, classname):
|
||||
j_env = get_jnienv()
|
||||
self.name = name
|
||||
self.classname = classname
|
||||
|
@ -301,13 +312,16 @@ cdef class JavaField(object):
|
|||
if self.j_field != NULL:
|
||||
return
|
||||
if self.is_static:
|
||||
defstr = str_for_c(self.definition)
|
||||
self.j_field = j_env[0].GetStaticFieldID(
|
||||
j_env, self.j_cls, <char *>self.name,
|
||||
<char *>self.definition)
|
||||
<char *>defstr)
|
||||
else:
|
||||
defstr = str_for_c(self.definition)
|
||||
namestr = str_for_c(self.name)
|
||||
self.j_field = j_env[0].GetFieldID(
|
||||
j_env, self.j_cls, <char *>self.name,
|
||||
<char *>self.definition)
|
||||
j_env, self.j_cls, <char *>namestr,
|
||||
<char *>defstr)
|
||||
if self.j_field == NULL:
|
||||
raise JavaException('Unable to found the field {0}'.format(self.name))
|
||||
|
||||
|
@ -321,6 +335,66 @@ cdef class JavaField(object):
|
|||
j_self = (<JavaClass?>obj).j_self.obj
|
||||
return self.read_field(j_self)
|
||||
|
||||
def __set__(self, obj, value):
|
||||
cdef jobject j_self
|
||||
|
||||
self.ensure_field()
|
||||
if obj is None:
|
||||
# set not implemented for static fields
|
||||
raise NotImplementedError()
|
||||
|
||||
j_self = (<JavaClass?>obj).j_self.obj
|
||||
self.write_field(j_self, value)
|
||||
|
||||
cdef write_field(self, jobject j_self, value):
|
||||
cdef jboolean j_boolean
|
||||
cdef jbyte j_byte
|
||||
cdef jchar j_char
|
||||
cdef jshort j_short
|
||||
cdef jint j_int
|
||||
cdef jlong j_long
|
||||
cdef jfloat j_float
|
||||
cdef jdouble j_double
|
||||
cdef jobject j_object
|
||||
cdef JNIEnv *j_env = get_jnienv()
|
||||
|
||||
# type of the java field
|
||||
r = self.definition[0]
|
||||
|
||||
# set the java field; implemented only for primitive types
|
||||
if r == 'Z':
|
||||
j_boolean = <jboolean>value
|
||||
j_env[0].SetBooleanField(j_env, j_self, self.j_field, j_boolean)
|
||||
elif r == 'B':
|
||||
j_byte = <jbyte>value
|
||||
j_env[0].SetByteField(j_env, j_self, self.j_field, j_byte)
|
||||
elif r == 'C':
|
||||
j_char = <jchar>value
|
||||
j_env[0].SetCharField(j_env, j_self, self.j_field, j_char)
|
||||
elif r == 'S':
|
||||
j_short = <jshort>value
|
||||
j_env[0].SetShortField(j_env, j_self, self.j_field, j_short)
|
||||
elif r == 'I':
|
||||
j_int = <jint>value
|
||||
j_env[0].SetIntField(j_env, j_self, self.j_field, j_int)
|
||||
elif r == 'J':
|
||||
j_long = <jlong>value
|
||||
j_env[0].SetLongField(j_env, j_self, self.j_field, j_long)
|
||||
elif r == 'F':
|
||||
j_float = <jfloat>value
|
||||
j_env[0].SetFloatField(j_env, j_self, self.j_field, j_float)
|
||||
elif r == 'D':
|
||||
j_double = <jdouble>value
|
||||
j_env[0].SetDoubleField(j_env, j_self, self.j_field, j_double)
|
||||
elif r == 'L':
|
||||
j_object = <jobject>convert_python_to_jobject(j_env, self.definition, value)
|
||||
j_env[0].SetObjectField(j_env, j_self, self.j_field, j_object)
|
||||
j_env[0].DeleteLocalRef(j_env, j_object)
|
||||
else:
|
||||
raise Exception('Invalid field definition')
|
||||
|
||||
check_exception(j_env)
|
||||
|
||||
cdef read_field(self, jobject j_self):
|
||||
cdef jboolean j_boolean
|
||||
cdef jbyte j_byte
|
||||
|
@ -474,9 +548,9 @@ cdef class JavaMethod(object):
|
|||
cdef jmethodID j_method
|
||||
cdef jclass j_cls
|
||||
cdef LocalRef j_self
|
||||
cdef bytes name
|
||||
cdef bytes classname
|
||||
cdef bytes definition
|
||||
cdef name
|
||||
cdef classname
|
||||
cdef definition
|
||||
cdef object is_static
|
||||
cdef bint is_varargs
|
||||
cdef object definition_return
|
||||
|
@ -489,7 +563,7 @@ cdef class JavaMethod(object):
|
|||
|
||||
def __init__(self, definition, **kwargs):
|
||||
super(JavaMethod, self).__init__()
|
||||
self.definition = <bytes>definition
|
||||
self.definition = definition
|
||||
self.definition_return, self.definition_args = \
|
||||
parse_definition(definition)
|
||||
self.is_static = kwargs.get('static', False)
|
||||
|
@ -502,20 +576,22 @@ cdef class JavaMethod(object):
|
|||
if self.name is None:
|
||||
raise JavaException('Unable to find a None method!')
|
||||
if self.is_static:
|
||||
defstr = str_for_c(self.definition)
|
||||
self.j_method = j_env[0].GetStaticMethodID(
|
||||
j_env, self.j_cls, <char *>self.name,
|
||||
<char *>self.definition)
|
||||
<char *>defstr)
|
||||
else:
|
||||
defstr = str_for_c(self.definition)
|
||||
self.j_method = j_env[0].GetMethodID(
|
||||
j_env, self.j_cls, <char *>self.name,
|
||||
<char *>self.definition)
|
||||
<char *>defstr)
|
||||
|
||||
if self.j_method == NULL:
|
||||
raise JavaException('Unable to find the method'
|
||||
' {0}({1})'.format(self.name, self.definition))
|
||||
|
||||
cdef void set_resolve_info(self, JNIEnv *j_env, jclass j_cls,
|
||||
LocalRef j_self, bytes name, bytes classname):
|
||||
LocalRef j_self, name, classname):
|
||||
self.name = name
|
||||
self.classname = classname
|
||||
self.j_cls = j_cls
|
||||
|
@ -807,7 +883,7 @@ cdef class JavaMultipleMethod(object):
|
|||
else:
|
||||
methods = self.static_methods
|
||||
|
||||
for signature, jm in methods.iteritems():
|
||||
for signature, jm in items_compat(methods):
|
||||
sign_ret, sign_args = jm.definition_return, jm.definition_args
|
||||
if jm.is_varargs:
|
||||
args_ = args[:len(sign_args) - 1] + (args[len(sign_args) - 1:],)
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
from cpython.version cimport PY_MAJOR_VERSION
|
||||
|
||||
def cast(destclass, obj):
|
||||
cdef JavaClass jc
|
||||
cdef JavaClass jobj = obj
|
||||
from reflect import autoclass
|
||||
if isinstance(destclass, basestring):
|
||||
from .reflect import autoclass
|
||||
if (PY_MAJOR_VERSION < 3 and isinstance(destclass, basestring)) or \
|
||||
(PY_MAJOR_VERSION >=3 and isinstance(destclass, str)):
|
||||
jc = autoclass(destclass)(noinstance=True)
|
||||
else:
|
||||
jc = destclass(noinstance=True)
|
||||
jc.instanciate_from(jobj.j_self)
|
||||
return jc
|
||||
|
||||
def find_javaclass(bytes name):
|
||||
def find_javaclass(namestr):
|
||||
namestr = namestr.replace('.', '/')
|
||||
cdef bytes name = str_for_c(namestr)
|
||||
from .reflect import Class
|
||||
cdef JavaClass cls
|
||||
cdef jclass jc
|
||||
cdef JNIEnv *j_env = get_jnienv()
|
||||
|
||||
name = name.replace('.', '/')
|
||||
|
||||
jc = j_env[0].FindClass(j_env, name)
|
||||
if jc == NULL:
|
||||
raise JavaException('Class not found {0!r}'.format(name))
|
||||
|
||||
cls = Class(noinstance=True)
|
||||
cls.instanciate_from(create_local_ref(j_env, jc))
|
||||
j_env[0].DeleteLocalRef(j_env, jc)
|
||||
return cls
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
from cpython.version cimport PY_MAJOR_VERSION
|
||||
|
||||
# on desktop, we need to create an env :)
|
||||
# example taken from http://www.inonit.com/cygwin/jni/invocationApi/c.html
|
||||
|
||||
cdef extern jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args)
|
||||
cdef extern jint __stdcall JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args)
|
||||
cdef extern from "jni.h":
|
||||
int JNI_VERSION_1_4
|
||||
int JNI_OK
|
||||
jboolean JNI_FALSE
|
||||
ctypedef struct JavaVMInitArgs:
|
||||
jint version
|
||||
|
@ -16,52 +19,38 @@ cdef extern from "jni.h":
|
|||
|
||||
cdef JNIEnv *_platform_default_env = NULL
|
||||
|
||||
def classpath():
|
||||
import platform
|
||||
from glob import glob
|
||||
from os import environ
|
||||
from os.path import realpath, dirname, join
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
split_char = ';'
|
||||
else:
|
||||
split_char = ':'
|
||||
|
||||
paths = [realpath('.'), join(dirname(__file__), 'src'), ]
|
||||
if 'CLASSPATH' not in environ:
|
||||
return split_char.join(paths)
|
||||
|
||||
cp = environ.get('CLASSPATH')
|
||||
pre_paths = paths + cp.split(split_char)
|
||||
# deal with wildcards
|
||||
for path in pre_paths:
|
||||
if not path.endswith('*'):
|
||||
paths.append(path)
|
||||
else:
|
||||
paths.extend(glob(path + '.jar'))
|
||||
paths.extend(glob(path + '.JAR'))
|
||||
result = split_char.join(paths)
|
||||
return result
|
||||
|
||||
cdef void create_jnienv():
|
||||
cdef void create_jnienv() except *:
|
||||
cdef JavaVM* jvm
|
||||
cdef JavaVMInitArgs args
|
||||
cdef JavaVMOption options[1]
|
||||
cdef JavaVMOption *options
|
||||
cdef int ret
|
||||
cdef bytes py_bytes
|
||||
import jnius_config
|
||||
|
||||
cp = classpath()
|
||||
py_bytes = <bytes>('-Djava.class.path={0}'.format(cp))
|
||||
options[0].optionString = py_bytes
|
||||
options[0].extraInfo = NULL
|
||||
optarr = jnius_config.options
|
||||
optarr.append("-Djava.class.path=" + jnius_config.expand_classpath())
|
||||
|
||||
options = <JavaVMOption*>malloc(sizeof(JavaVMOption) * len(optarr))
|
||||
for i, opt in enumerate(optarr):
|
||||
if PY_MAJOR_VERSION >= 3:
|
||||
opt = opt.encode('utf-8')
|
||||
options[i].optionString = <bytes>(opt)
|
||||
options[i].extraInfo = NULL
|
||||
|
||||
args.version = JNI_VERSION_1_4
|
||||
args.options = options
|
||||
args.nOptions = 1
|
||||
args.nOptions = len(optarr)
|
||||
args.ignoreUnrecognized = JNI_FALSE
|
||||
|
||||
JNI_CreateJavaVM(&jvm, <void **>&_platform_default_env, &args)
|
||||
ret = JNI_CreateJavaVM(&jvm, <void **>&_platform_default_env, &args)
|
||||
free(options)
|
||||
|
||||
cdef JNIEnv *get_platform_jnienv():
|
||||
if ret != JNI_OK:
|
||||
raise SystemError("JVM failed to start")
|
||||
|
||||
jnius_config.vm_running = True
|
||||
|
||||
cdef JNIEnv *get_platform_jnienv() except NULL:
|
||||
if _platform_default_env == NULL:
|
||||
create_jnienv()
|
||||
return _platform_default_env
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
include "config.pxi"
|
||||
import os
|
||||
|
||||
cdef extern from *:
|
||||
ctypedef char const_char "const char"
|
||||
|
||||
cdef extern from 'dlfcn.h' nogil:
|
||||
void* dlopen(const_char *filename, int flag)
|
||||
char *dlerror()
|
||||
void *dlsym(void *handle, const_char *symbol)
|
||||
int dlclose(void *handle)
|
||||
|
||||
unsigned int RTLD_LAZY
|
||||
unsigned int RTLD_NOW
|
||||
unsigned int RTLD_GLOBAL
|
||||
unsigned int RTLD_LOCAL
|
||||
unsigned int RTLD_NODELETE
|
||||
unsigned int RTLD_NOLOAD
|
||||
unsigned int RTLD_DEEPBIND
|
||||
|
||||
unsigned int RTLD_DEFAULT
|
||||
long unsigned int RTLD_NEXT
|
||||
|
||||
|
||||
cdef extern from "jni.h":
|
||||
int JNI_VERSION_1_6
|
||||
int JNI_OK
|
||||
jboolean JNI_FALSE
|
||||
ctypedef struct JavaVMInitArgs:
|
||||
jint version
|
||||
jint nOptions
|
||||
jboolean ignoreUnrecognized
|
||||
JavaVMOption *options
|
||||
ctypedef struct JavaVMOption:
|
||||
char *optionString
|
||||
void *extraInfo
|
||||
|
||||
cdef JNIEnv *_platform_default_env = NULL
|
||||
|
||||
cdef void create_jnienv() except *:
|
||||
cdef JavaVM* jvm
|
||||
cdef JavaVMInitArgs args
|
||||
cdef JavaVMOption *options
|
||||
cdef int ret
|
||||
cdef bytes py_bytes
|
||||
import jnius_config
|
||||
|
||||
JAVA_HOME = os.environ['JAVA_HOME']
|
||||
if JAVA_HOME is None or JAVA_HOME == '':
|
||||
raise SystemError("JAVA_HOME is not set.")
|
||||
IF JNIUS_PYTHON3:
|
||||
lib_path = str_for_c(os.path.join(JAVA_HOME, JNIUS_LIB_SUFFIX.decode("utf-8")))
|
||||
ELSE:
|
||||
lib_path = str_for_c(os.path.join(JAVA_HOME, JNIUS_LIB_SUFFIX))
|
||||
|
||||
cdef void *handle = dlopen(lib_path, RTLD_NOW | RTLD_GLOBAL)
|
||||
if handle == NULL:
|
||||
raise SystemError("Error calling dlopen({0}: {1}".format(lib_path, dlerror()))
|
||||
|
||||
cdef void *jniCreateJVM = dlsym(handle, b"JNI_CreateJavaVM")
|
||||
|
||||
if jniCreateJVM == NULL:
|
||||
raise SystemError("Error calling dlfcn for JNI_CreateJavaVM: {0}".format(dlerror()))
|
||||
|
||||
optarr = jnius_config.options
|
||||
optarr.append("-Djava.class.path=" + jnius_config.expand_classpath())
|
||||
|
||||
options = <JavaVMOption*>malloc(sizeof(JavaVMOption) * len(optarr))
|
||||
for i, opt in enumerate(optarr):
|
||||
optbytes = str_for_c(opt)
|
||||
options[i].optionString = <bytes>(optbytes)
|
||||
options[i].extraInfo = NULL
|
||||
|
||||
args.version = JNI_VERSION_1_6
|
||||
args.options = options
|
||||
args.nOptions = len(optarr)
|
||||
args.ignoreUnrecognized = JNI_FALSE
|
||||
|
||||
ret = (<jint (*)(JavaVM **pvm, void **penv, void *args)> jniCreateJVM)(&jvm, <void **>&_platform_default_env, &args)
|
||||
free(options)
|
||||
|
||||
if ret != JNI_OK:
|
||||
raise SystemError("JVM failed to start: {0}".format(ret))
|
||||
|
||||
jnius_config.vm_running = True
|
||||
|
||||
cdef JNIEnv *get_platform_jnienv() except NULL:
|
||||
if _platform_default_env == NULL:
|
||||
create_jnienv()
|
||||
return _platform_default_env
|
|
@ -12,6 +12,8 @@ cdef python_op(int op, object a, object b):
|
|||
elif op == 5:
|
||||
return a != b
|
||||
|
||||
|
||||
|
||||
cdef class ByteArray:
|
||||
cdef LocalRef _jobject
|
||||
cdef long _size
|
||||
|
@ -23,6 +25,8 @@ cdef class ByteArray:
|
|||
self._buf = NULL
|
||||
self._arr = None
|
||||
|
||||
|
||||
|
||||
def __dealloc__(self):
|
||||
cdef JNIEnv *j_env
|
||||
if self._buf != NULL:
|
||||
|
@ -47,8 +51,21 @@ cdef class ByteArray:
|
|||
def __len__(self):
|
||||
return self._size
|
||||
|
||||
def __getitem__(self, long index):
|
||||
return self._arr[index]
|
||||
def __getitem__(self, index):
|
||||
cdef long xx
|
||||
if isinstance(index, slice):
|
||||
val = []
|
||||
(start, stop, step) = index.indices(len(self._arr))
|
||||
for x in range(start, stop, step):
|
||||
xx = x
|
||||
val.append(self._arr[xx])
|
||||
return val
|
||||
else:
|
||||
xx = index
|
||||
return self._arr[xx]
|
||||
|
||||
def __getslice__(self, long i, long j):
|
||||
return self._arr[i:j]
|
||||
|
||||
def __richcmp__(self, other, op):
|
||||
cdef ByteArray b_other
|
||||
|
@ -60,9 +77,6 @@ cdef class ByteArray:
|
|||
else:
|
||||
return False
|
||||
|
||||
def __getslice__(self, long i, long j):
|
||||
return self._arr[i:j]
|
||||
|
||||
def tolist(self):
|
||||
return list(self[:])
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
cdef python_op(int op, object a, object b):
|
||||
if op == 0:
|
||||
return a < b
|
||||
elif op == 1:
|
||||
return a <= b
|
||||
elif op == 2:
|
||||
return a == b
|
||||
elif op == 3:
|
||||
return a >= b
|
||||
elif op == 4:
|
||||
return a > b
|
||||
elif op == 5:
|
||||
return a != b
|
||||
|
||||
cdef class ByteArray:
|
||||
cdef LocalRef _jobject
|
||||
cdef long _size
|
||||
cdef jbyte *_buf
|
||||
cdef jbyte[:] _arr
|
||||
|
||||
def __cinit__(self):
|
||||
self._size = 0
|
||||
self._buf = NULL
|
||||
self._arr = None
|
||||
|
||||
def __dealloc__(self):
|
||||
cdef JNIEnv *j_env
|
||||
if self._buf != NULL:
|
||||
j_env = get_jnienv()
|
||||
j_env[0].ReleaseByteArrayElements(j_env, self._jobject.obj, self._buf, 0)
|
||||
self._buf = NULL
|
||||
self._jobject = None
|
||||
|
||||
cdef void set_buffer(self, JNIEnv *env, jobject obj, long size, jbyte *buf):
|
||||
if self._buf != NULL:
|
||||
raise Exception('Cannot call set_buffer() twice.')
|
||||
self._jobject = LocalRef()
|
||||
self._jobject.create(env, obj)
|
||||
self._size = size
|
||||
self._buf = buf
|
||||
self._arr = <jbyte[:size]>self._buf
|
||||
|
||||
def __str__(self):
|
||||
return '<ByteArray size={} at 0x{}>'.format(
|
||||
self._size, id(self))
|
||||
|
||||
def __len__(self):
|
||||
return self._size
|
||||
|
||||
def __getitem__(self, index):
|
||||
cdef long xx
|
||||
if isinstance(index, slice):
|
||||
val = []
|
||||
(start, stop, step) = index.indices(len(self._arr))
|
||||
for x in range(start, stop, step):
|
||||
xx = x
|
||||
val.append(self._arr[xx])
|
||||
return val
|
||||
else:
|
||||
xx = index
|
||||
return self._arr[xx]
|
||||
|
||||
def __richcmp__(self, other, op):
|
||||
cdef ByteArray b_other
|
||||
if isinstance(other, (list, tuple)):
|
||||
return python_op(op, self.tolist(), other)
|
||||
elif isinstance(other, ByteArray):
|
||||
b_other = other
|
||||
return python_op(op, self.tostring(), other.tostring())
|
||||
else:
|
||||
return False
|
||||
|
||||
def tolist(self):
|
||||
return list(self[:])
|
||||
|
||||
def tostring(self):
|
||||
return self._buf[:self._size]
|
|
@ -72,6 +72,7 @@ cdef class PythonJavaClass(object):
|
|||
|
||||
return py_method(*args)
|
||||
|
||||
|
||||
cdef jobject py_invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject
|
||||
j_method, jobjectArray args) except * with gil:
|
||||
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
from cpython.version cimport PY_MAJOR_VERSION
|
||||
|
||||
cdef str_for_c(s):
|
||||
if PY_MAJOR_VERSION < 3:
|
||||
if isinstance(s, unicode):
|
||||
return s.encode('utf-8')
|
||||
else:
|
||||
return s
|
||||
else:
|
||||
return s.encode('utf-8')
|
||||
|
||||
cdef items_compat(d):
|
||||
if PY_MAJOR_VERSION >= 3:
|
||||
return d.items()
|
||||
else:
|
||||
return d.iteritems()
|
||||
|
||||
cdef parse_definition(definition):
|
||||
# not a function, just a field
|
||||
if definition[0] != '(':
|
||||
|
@ -10,10 +27,10 @@ cdef parse_definition(definition):
|
|||
while len(argdef):
|
||||
c = argdef[0]
|
||||
|
||||
# read the array char
|
||||
# read the array char(s)
|
||||
prefix = ''
|
||||
if c == '[':
|
||||
prefix = c
|
||||
while c == '[':
|
||||
prefix += c
|
||||
argdef = argdef[1:]
|
||||
c = argdef[0]
|
||||
|
||||
|
@ -27,26 +44,137 @@ cdef parse_definition(definition):
|
|||
if c == 'L':
|
||||
c, argdef = argdef.split(';', 1)
|
||||
args.append(prefix + c + ';')
|
||||
continue
|
||||
|
||||
raise Exception('Invalid "{}" character in definition "{}"'.format(
|
||||
c, definition[1:]))
|
||||
|
||||
return ret, tuple(args)
|
||||
|
||||
|
||||
cdef void check_exception(JNIEnv *j_env) except *:
|
||||
cdef jmethodID toString = NULL
|
||||
cdef jmethodID getCause = NULL
|
||||
cdef jmethodID getStackTrace = NULL
|
||||
cdef jmethodID getMessage = NULL
|
||||
cdef jstring e_msg
|
||||
cdef jboolean isCopy
|
||||
cdef jthrowable exc = j_env[0].ExceptionOccurred(j_env)
|
||||
cdef jclass cls_object = NULL
|
||||
cdef jclass cls_throwable = NULL
|
||||
if exc:
|
||||
j_env[0].ExceptionDescribe(j_env)
|
||||
# ExceptionDescribe always writes to stderr, preventing tidy exception
|
||||
# handling, so should only be for debugging
|
||||
# j_env[0].ExceptionDescribe(j_env)
|
||||
j_env[0].ExceptionClear(j_env)
|
||||
raise JavaException('JVM exception occured')
|
||||
|
||||
cls_object = j_env[0].FindClass(j_env, "java/lang/Object")
|
||||
cls_throwable = j_env[0].FindClass(j_env, "java/lang/Throwable")
|
||||
|
||||
toString = j_env[0].GetMethodID(j_env, cls_object, "toString", "()Ljava/lang/String;");
|
||||
getMessage = j_env[0].GetMethodID(j_env, cls_throwable, "getMessage", "()Ljava/lang/String;");
|
||||
getCause = j_env[0].GetMethodID(j_env, cls_throwable, "getCause", "()Ljava/lang/Throwable;");
|
||||
getStackTrace = j_env[0].GetMethodID(j_env, cls_throwable, "getStackTrace", "()[Ljava/lang/StackTraceElement;");
|
||||
|
||||
e_msg = j_env[0].CallObjectMethod(j_env, exc, getMessage);
|
||||
pymsg = None if e_msg == NULL else convert_jobject_to_python(j_env, <bytes> 'Ljava/lang/String;', e_msg)
|
||||
|
||||
pystack = []
|
||||
_append_exception_trace_messages(j_env, pystack, exc, getCause, getStackTrace, toString)
|
||||
|
||||
pyexcclass = lookup_java_object_name(j_env, exc).replace('/', '.')
|
||||
|
||||
j_env[0].DeleteLocalRef(j_env, cls_object)
|
||||
j_env[0].DeleteLocalRef(j_env, cls_throwable)
|
||||
if e_msg != NULL:
|
||||
j_env[0].DeleteLocalRef(j_env, e_msg)
|
||||
j_env[0].DeleteLocalRef(j_env, exc)
|
||||
|
||||
raise JavaException('JVM exception occurred: %s' % (pymsg if pymsg is not None else pyexcclass), pyexcclass, pymsg, pystack)
|
||||
|
||||
|
||||
cdef void _append_exception_trace_messages(
|
||||
JNIEnv* j_env,
|
||||
list pystack,
|
||||
jthrowable exc,
|
||||
jmethodID mid_getCause,
|
||||
jmethodID mid_getStackTrace,
|
||||
jmethodID mid_toString):
|
||||
|
||||
# Get the array of StackTraceElements.
|
||||
cdef jobjectArray frames = j_env[0].CallObjectMethod(j_env, exc, mid_getStackTrace)
|
||||
cdef jsize frames_length = j_env[0].GetArrayLength(j_env, frames)
|
||||
cdef jstring msg_obj
|
||||
cdef jobject frame
|
||||
cdef jthrowable cause
|
||||
|
||||
# Add Throwable.toString() before descending stack trace messages.
|
||||
if frames != NULL:
|
||||
msg_obj = j_env[0].CallObjectMethod(j_env, exc, mid_toString)
|
||||
pystr = None if msg_obj == NULL else convert_jobject_to_python(j_env, <bytes> 'Ljava/lang/String;', msg_obj)
|
||||
# If this is not the top-of-the-trace then this is a cause.
|
||||
if len(pystack) > 0:
|
||||
pystack.append("Caused by:")
|
||||
pystack.append(pystr)
|
||||
if msg_obj != NULL:
|
||||
j_env[0].DeleteLocalRef(j_env, msg_obj)
|
||||
|
||||
# Append stack trace messages if there are any.
|
||||
if frames_length > 0:
|
||||
for i in range(frames_length):
|
||||
# Get the string returned from the 'toString()' method of the next frame and append it to the error message.
|
||||
frame = j_env[0].GetObjectArrayElement(j_env, frames, i)
|
||||
msg_obj = j_env[0].CallObjectMethod(j_env, frame, mid_toString)
|
||||
pystr = None if msg_obj == NULL else convert_jobject_to_python(j_env, <bytes> 'Ljava/lang/String;', msg_obj)
|
||||
pystack.append(pystr)
|
||||
if msg_obj != NULL:
|
||||
j_env[0].DeleteLocalRef(j_env, msg_obj)
|
||||
j_env[0].DeleteLocalRef(j_env, frame)
|
||||
|
||||
# If 'exc' has a cause then append the stack trace messages from the cause.
|
||||
if frames != NULL:
|
||||
cause = j_env[0].CallObjectMethod(j_env, exc, mid_getCause)
|
||||
if cause != NULL:
|
||||
_append_exception_trace_messages(j_env, pystack, cause,
|
||||
mid_getCause, mid_getStackTrace, mid_toString)
|
||||
j_env[0].DeleteLocalRef(j_env, cause)
|
||||
|
||||
j_env[0].DeleteLocalRef(j_env, frames)
|
||||
|
||||
|
||||
cdef dict assignable_from = {}
|
||||
cdef void check_assignable_from(JNIEnv *env, JavaClass jc, bytes signature) except *:
|
||||
cdef jclass cls
|
||||
cdef int assignable_from_order = 0
|
||||
cdef void check_assignable_from(JNIEnv *env, JavaClass jc, signature) except *:
|
||||
global assignable_from_order
|
||||
cdef jclass cls, clsA, clsB
|
||||
cdef jthrowable exc
|
||||
|
||||
# first call, we need to get over the libart issue, which implemented
|
||||
# IsAssignableFrom the wrong way.
|
||||
# Ref: https://github.com/kivy/pyjnius/issues/92
|
||||
# Google Bug: https://android.googlesource.com/platform/art/+/1268b74%5E!/
|
||||
if assignable_from_order == 0:
|
||||
clsA = env[0].FindClass(env, "java/lang/String")
|
||||
clsB = env[0].FindClass(env, "java/lang/Object")
|
||||
if env[0].IsAssignableFrom(env, clsB, clsA):
|
||||
# Bug triggered, IsAssignableFrom said we can do things like:
|
||||
# String a = Object()
|
||||
assignable_from_order = -1
|
||||
else:
|
||||
assignable_from_order = 1
|
||||
|
||||
# if we have a JavaObject, it's always ok.
|
||||
if signature == 'java/lang/Object':
|
||||
return
|
||||
|
||||
# FIXME Android/libART specific check
|
||||
# check_jni.cc crash when calling the IsAssignableFrom with
|
||||
# org/jnius/NativeInvocationHandler java/lang/reflect/InvocationHandler
|
||||
# Because we know it's ok, just return here.
|
||||
if signature == 'java/lang/reflect/InvocationHandler' and \
|
||||
jc.__javaclass__ == 'org/jnius/NativeInvocationHandler':
|
||||
return
|
||||
|
||||
# if the signature is a direct match, it's ok too :)
|
||||
if jc.__javaclass__ == signature:
|
||||
return
|
||||
|
@ -57,13 +185,22 @@ cdef void check_assignable_from(JNIEnv *env, JavaClass jc, bytes signature) exce
|
|||
|
||||
# we got an object that doesn't match with the signature
|
||||
# check if we can use it.
|
||||
cls = env[0].FindClass(env, signature)
|
||||
s = str_for_c(signature)
|
||||
cls = env[0].FindClass(env, s)
|
||||
if cls == NULL:
|
||||
raise JavaException('Unable to found the class for {0!r}'.format(
|
||||
signature))
|
||||
|
||||
result = bool(env[0].IsAssignableFrom(env, jc.j_cls, cls))
|
||||
env[0].ExceptionClear(env)
|
||||
if assignable_from_order == 1:
|
||||
result = bool(env[0].IsAssignableFrom(env, jc.j_cls, cls))
|
||||
else:
|
||||
result = bool(env[0].IsAssignableFrom(env, cls, jc.j_cls))
|
||||
|
||||
exc = env[0].ExceptionOccurred(env)
|
||||
if exc:
|
||||
env[0].ExceptionDescribe(env)
|
||||
env[0].ExceptionClear(env)
|
||||
|
||||
assignable_from[(jc.__javaclass__, signature)] = bool(result)
|
||||
|
||||
if result is False:
|
||||
|
@ -71,12 +208,12 @@ cdef void check_assignable_from(JNIEnv *env, JavaClass jc, bytes signature) exce
|
|||
jc.__javaclass__, signature))
|
||||
|
||||
|
||||
cdef bytes lookup_java_object_name(JNIEnv *j_env, jobject j_obj):
|
||||
cdef lookup_java_object_name(JNIEnv *j_env, jobject j_obj):
|
||||
cdef jclass jcls = j_env[0].GetObjectClass(j_env, j_obj)
|
||||
cdef jclass jcls2 = j_env[0].GetObjectClass(j_env, jcls)
|
||||
cdef jmethodID jmeth = j_env[0].GetMethodID(j_env, jcls2, 'getName', '()Ljava/lang/String;')
|
||||
cdef jobject js = j_env[0].CallObjectMethod(j_env, jcls, jmeth)
|
||||
name = convert_jobject_to_python(j_env, b'Ljava/lang/String;', js)
|
||||
name = convert_jobject_to_python(j_env, 'Ljava/lang/String;', js)
|
||||
j_env[0].DeleteLocalRef(j_env, js)
|
||||
j_env[0].DeleteLocalRef(j_env, jcls)
|
||||
j_env[0].DeleteLocalRef(j_env, jcls2)
|
||||
|
@ -86,7 +223,6 @@ cdef bytes lookup_java_object_name(JNIEnv *j_env, jobject j_obj):
|
|||
cdef int calculate_score(sign_args, args, is_varargs=False) except *:
|
||||
cdef int index
|
||||
cdef int score = 0
|
||||
cdef bytes r
|
||||
cdef JavaClass jc
|
||||
|
||||
if len(args) != len(sign_args) and not is_varargs:
|
||||
|
@ -157,7 +293,11 @@ cdef int calculate_score(sign_args, args, is_varargs=False) except *:
|
|||
continue
|
||||
|
||||
# if it's a string, accept any python string
|
||||
if r == 'java/lang/String' and isinstance(arg, basestring):
|
||||
if r == 'java/lang/String' and isinstance(arg, basestring) and PY_MAJOR_VERSION < 3:
|
||||
score += 10
|
||||
continue
|
||||
|
||||
if r == 'java/lang/String' and isinstance(arg, str) and PY_MAJOR_VERSION >= 3:
|
||||
score += 10
|
||||
continue
|
||||
|
||||
|
@ -172,6 +312,11 @@ cdef int calculate_score(sign_args, args, is_varargs=False) except *:
|
|||
continue
|
||||
return -1
|
||||
|
||||
# accept an autoclass class for java/lang/Class.
|
||||
if hasattr(arg, '__javaclass__') and r == 'java/lang/Class':
|
||||
score += 10
|
||||
continue
|
||||
|
||||
# if we pass a JavaClass, ensure the definition is matching
|
||||
# XXX FIXME what if we use a subclass or something ?
|
||||
if isinstance(arg, JavaClass):
|
||||
|
@ -204,7 +349,15 @@ cdef int calculate_score(sign_args, args, is_varargs=False) except *:
|
|||
score += 10
|
||||
continue
|
||||
|
||||
if (r == '[B' or r == '[C') and isinstance(arg, basestring):
|
||||
if (r == '[B' or r == '[C') and isinstance(arg, basestring) and PY_MAJOR_VERSION < 3:
|
||||
score += 10
|
||||
continue
|
||||
|
||||
if (r == '[B') and isinstance(arg, bytes) and PY_MAJOR_VERSION >= 3:
|
||||
score += 10
|
||||
continue
|
||||
|
||||
if (r == '[C') and isinstance(arg, str) and PY_MAJOR_VERSION >= 3:
|
||||
score += 10
|
||||
continue
|
||||
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
__all__ = ('autoclass', 'ensureclass')
|
||||
from six import with_metaclass
|
||||
|
||||
from jnius import (
|
||||
from .jnius import (
|
||||
JavaClass, MetaJavaClass, JavaMethod, JavaStaticMethod,
|
||||
JavaField, JavaStaticField, JavaMultipleMethod, find_javaclass
|
||||
)
|
||||
|
||||
|
||||
class Class(JavaClass):
|
||||
__metaclass__ = MetaJavaClass
|
||||
class Class(with_metaclass(MetaJavaClass, JavaClass)):
|
||||
__javaclass__ = 'java/lang/Class'
|
||||
|
||||
desiredAssertionStatus = JavaMethod('()Z;')
|
||||
desiredAssertionStatus = JavaMethod('()Z')
|
||||
forName = JavaMultipleMethod([
|
||||
('(Ljava/lang/String,Z,Ljava/lang/ClassLoader;)Ljava/langClass;', True, False),
|
||||
('(Ljava/lang/String;)Ljava/lang/Class;', True, False), ])
|
||||
|
@ -32,7 +36,7 @@ class Class(JavaClass):
|
|||
getInterfaces = JavaMethod('()[Ljava/lang/Class;')
|
||||
getMethod = JavaMethod('(Ljava/lang/String,[Ljava/lang/Class;)Ljava/lang/reflect/Method;')
|
||||
getMethods = JavaMethod('()[Ljava/lang/reflect/Method;')
|
||||
getModifiers = JavaMethod('()[I;')
|
||||
getModifiers = JavaMethod('()[I')
|
||||
getName = JavaMethod('()Ljava/lang/String;')
|
||||
getPackage = JavaMethod('()Ljava/lang/Package;')
|
||||
getProtectionDomain = JavaMethod('()Ljava/security/ProtectionDomain;')
|
||||
|
@ -40,25 +44,23 @@ class Class(JavaClass):
|
|||
getResourceAsStream = JavaMethod('(Ljava/lang/String;)Ljava/io/InputStream;')
|
||||
getSigners = JavaMethod('()[Ljava/lang/Object;')
|
||||
getSuperclass = JavaMethod('()Ljava/lang/reflect/Class;')
|
||||
isArray = JavaMethod('()Z;')
|
||||
isAssignableFrom = JavaMethod('(Ljava/lang/reflect/Class;)Z;')
|
||||
isInstance = JavaMethod('(Ljava/lang/Object;)Z;')
|
||||
isInterface = JavaMethod('()Z;')
|
||||
isPrimitive = JavaMethod('()Z;')
|
||||
isArray = JavaMethod('()Z')
|
||||
isAssignableFrom = JavaMethod('(Ljava/lang/reflect/Class;)Z')
|
||||
isInstance = JavaMethod('(Ljava/lang/Object;)Z')
|
||||
isInterface = JavaMethod('()Z')
|
||||
isPrimitive = JavaMethod('()Z')
|
||||
newInstance = JavaMethod('()Ljava/lang/Object;')
|
||||
toString = JavaMethod('()Ljava/lang/String;')
|
||||
|
||||
|
||||
class Object(JavaClass):
|
||||
__metaclass__ = MetaJavaClass
|
||||
class Object(with_metaclass(MetaJavaClass, JavaClass)):
|
||||
__javaclass__ = 'java/lang/Object'
|
||||
|
||||
getClass = JavaMethod('()Ljava/lang/Class;')
|
||||
hashCode = JavaMethod('()I')
|
||||
|
||||
|
||||
class Modifier(JavaClass):
|
||||
__metaclass__ = MetaJavaClass
|
||||
class Modifier(with_metaclass(MetaJavaClass, JavaClass)):
|
||||
__javaclass__ = 'java/lang/reflect/Modifier'
|
||||
|
||||
isAbstract = JavaStaticMethod('(I)Z')
|
||||
|
@ -75,8 +77,7 @@ class Modifier(JavaClass):
|
|||
isVolatile = JavaStaticMethod('(I)Z')
|
||||
|
||||
|
||||
class Method(JavaClass):
|
||||
__metaclass__ = MetaJavaClass
|
||||
class Method(with_metaclass(MetaJavaClass, JavaClass)):
|
||||
__javaclass__ = 'java/lang/reflect/Method'
|
||||
|
||||
getName = JavaMethod('()Ljava/lang/String;')
|
||||
|
@ -87,8 +88,7 @@ class Method(JavaClass):
|
|||
isVarArgs = JavaMethod('()Z')
|
||||
|
||||
|
||||
class Field(JavaClass):
|
||||
__metaclass__ = MetaJavaClass
|
||||
class Field(with_metaclass(MetaJavaClass, JavaClass)):
|
||||
__javaclass__ = 'java/lang/reflect/Field'
|
||||
|
||||
getName = JavaMethod('()Ljava/lang/String;')
|
||||
|
@ -97,8 +97,7 @@ class Field(JavaClass):
|
|||
getModifiers = JavaMethod('()I')
|
||||
|
||||
|
||||
class Constructor(JavaClass):
|
||||
__metaclass__ = MetaJavaClass
|
||||
class Constructor(with_metaclass(MetaJavaClass, JavaClass)):
|
||||
__javaclass__ = 'java/lang/reflect/Constructor'
|
||||
|
||||
toString = JavaMethod('()Ljava/lang/String;')
|
||||
|
@ -137,6 +136,11 @@ def ensureclass(clsname):
|
|||
registers.append(clsname)
|
||||
autoclass(clsname)
|
||||
|
||||
def lower_name(s):
|
||||
return s[:1].lower() + s[1:] if s else ''
|
||||
|
||||
def bean_getter(s):
|
||||
return (s.startswith('get') and len(s) > 3 and s[3].isupper()) or (s.startswith('is') and len(s) > 2 and s[2].isupper())
|
||||
|
||||
def autoclass(clsname):
|
||||
jniname = clsname.replace('.', '/')
|
||||
|
@ -176,9 +180,12 @@ def autoclass(clsname):
|
|||
get_signature(method.getReturnType()))
|
||||
cls = JavaStaticMethod if static else JavaMethod
|
||||
classDict[name] = cls(sig, varargs=varargs)
|
||||
if name != 'getClass' and bean_getter(name) and len(method.getParameterTypes()) == 0:
|
||||
lowername = lower_name(name[3:])
|
||||
classDict[lowername] = (lambda n: property(lambda self: getattr(self, n)()))(name)
|
||||
continue
|
||||
|
||||
# multpile signatures
|
||||
# multiple signatures
|
||||
signatures = []
|
||||
for index, subname in enumerate(methods_name):
|
||||
if subname != name:
|
||||
|
@ -207,6 +214,12 @@ def autoclass(clsname):
|
|||
|
||||
classDict[name] = JavaMultipleMethod(signatures)
|
||||
|
||||
for iclass in c.getInterfaces():
|
||||
if iclass.getName() == 'java.util.List':
|
||||
classDict['__getitem__'] = lambda self, index: self.get(index)
|
||||
classDict['__len__'] = lambda self: self.size()
|
||||
break
|
||||
|
||||
for field in c.getFields():
|
||||
static = Modifier.isStatic(field.getModifiers())
|
||||
sig = get_signature(field.getType())
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
'''
|
||||
signatures.py
|
||||
=============
|
||||
|
||||
A handy API for writing JNI signatures easily
|
||||
|
||||
Author: chrisjrn
|
||||
|
||||
This module aims to provide a more human-friendly API for
|
||||
wiring up Java proxy methods in PyJnius.
|
||||
|
||||
You can use the signature function to produce JNI method
|
||||
signautures for methods; passing PyJnius JavaClass classes
|
||||
as return or argument types; provided here are annotations
|
||||
representing Java's primitive and array times.
|
||||
|
||||
Methods can return just a standard primitive type:
|
||||
|
||||
>>> signature(jint, ())
|
||||
'()I'
|
||||
|
||||
>>> s.signature(jvoid, [jint])
|
||||
'(I)V'
|
||||
|
||||
Or you can use autoclass proxies to specify Java classes
|
||||
for return types.
|
||||
|
||||
>>> from jnius import autoclass
|
||||
>>> String = autoclass("java.lang.String")
|
||||
>>> signature(String, ())
|
||||
'()Ljava/lang/String;'
|
||||
|
||||
'''
|
||||
|
||||
__version__ = '0.0.1'
|
||||
|
||||
from . import JavaClass
|
||||
from . import java_method
|
||||
|
||||
|
||||
''' Type specifiers for primitives '''
|
||||
|
||||
class _JavaSignaturePrimitive(object):
|
||||
_spec = ""
|
||||
|
||||
def _MakeSignaturePrimitive(name, spec):
|
||||
class __Primitive(_JavaSignaturePrimitive):
|
||||
''' PyJnius signature for Java %s type ''' % name
|
||||
_name = name
|
||||
_spec = spec
|
||||
__Primitive.__name__ = "j" + name
|
||||
|
||||
return __Primitive
|
||||
|
||||
jboolean = _MakeSignaturePrimitive("boolean", "Z")
|
||||
jbyte = _MakeSignaturePrimitive("byte", "B")
|
||||
jchar = _MakeSignaturePrimitive("char", "C")
|
||||
jdouble = _MakeSignaturePrimitive("double", "D")
|
||||
jfloat = _MakeSignaturePrimitive("float", "F")
|
||||
jint = _MakeSignaturePrimitive("int", "I")
|
||||
jlong = _MakeSignaturePrimitive("long", "J")
|
||||
jshort = _MakeSignaturePrimitive("short", "S")
|
||||
jvoid = _MakeSignaturePrimitive("void", "V")
|
||||
|
||||
def JArray(of_type):
|
||||
''' Signature helper for identifying arrays of a given object or
|
||||
primitive type. '''
|
||||
|
||||
spec = "[" + _jni_type_spec(of_type)
|
||||
return _MakeSignaturePrimitive("array", spec)
|
||||
|
||||
def with_signature(returns, takes):
|
||||
''' Alternative version of @java_method that takes JavaClass
|
||||
objects to produce the method signature. '''
|
||||
|
||||
sig = signature(returns, takes)
|
||||
return java_method(sig)
|
||||
|
||||
def signature(returns, takes):
|
||||
''' Produces a JNI method signature, taking the provided arguments
|
||||
and returning the given return type. '''
|
||||
|
||||
out_takes = []
|
||||
for arg in takes:
|
||||
out_takes.append(_jni_type_spec(arg))
|
||||
|
||||
return "(" + "".join(out_takes) + ")" + _jni_type_spec(returns)
|
||||
|
||||
def _jni_type_spec(jclass):
|
||||
''' Produces a JNI type specification string for the given argument.
|
||||
If the argument is a jnius.JavaClass, it produces the JNI type spec
|
||||
for the class. Signature primitives return their stored type spec.
|
||||
'''
|
||||
|
||||
if issubclass(jclass, JavaClass):
|
||||
return "L" + jclass.__javaclass__ + ";"
|
||||
elif issubclass(jclass, _JavaSignaturePrimitive):
|
||||
return jclass._spec
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
__all__ = ('set_options', 'add_options', 'get_options',
|
||||
'set_classpath', 'add_classpath', 'get_classpath',
|
||||
'expand_classpath')
|
||||
|
||||
import platform
|
||||
if platform.system() == 'Windows':
|
||||
split_char = ';'
|
||||
else:
|
||||
split_char = ':'
|
||||
|
||||
vm_running = False
|
||||
options = []
|
||||
classpath = None
|
||||
|
||||
def set_options(*opts):
|
||||
"Sets the list of options to the JVM. Removes any previously set options."
|
||||
if vm_running:
|
||||
raise ValueError("VM is already running, can't set options")
|
||||
globals()['options'] = opts
|
||||
|
||||
def add_options(*opts):
|
||||
"Appends options to the list of VM options."
|
||||
if vm_running:
|
||||
raise ValueError("VM is already running, can't set options")
|
||||
global options
|
||||
options.extend(opts)
|
||||
|
||||
def get_options():
|
||||
"Retrieves the current list of VM options."
|
||||
global options
|
||||
return list(options)
|
||||
|
||||
|
||||
def set_classpath(*path):
|
||||
"""
|
||||
Sets the classpath for the JVM to use. Replaces any existing classpath, overriding the CLASSPATH environment variable.
|
||||
"""
|
||||
if vm_running:
|
||||
raise ValueError("VM is already running, can't set classpath")
|
||||
global classpath
|
||||
classpath = path
|
||||
|
||||
def add_classpath(*path):
|
||||
"""
|
||||
Appends items to the classpath for the JVM to use.
|
||||
Replaces any existing classpath, overriding the CLASSPATH environment variable.
|
||||
"""
|
||||
if vm_running:
|
||||
raise ValueError("VM is already running, can't set classpath")
|
||||
global classpath
|
||||
if classpath is None:
|
||||
classpath = list(path)
|
||||
else:
|
||||
classpath.extend(path)
|
||||
|
||||
def get_classpath():
|
||||
"Retrieves the classpath the JVM will use."
|
||||
from os import environ
|
||||
from os.path import realpath
|
||||
global classpath
|
||||
|
||||
if classpath is not None:
|
||||
return list(classpath)
|
||||
|
||||
if 'CLASSPATH' in environ:
|
||||
return environ['CLASSPATH'].split(split_char)
|
||||
|
||||
return [realpath('.')]
|
||||
|
||||
def expand_classpath():
|
||||
from glob import glob
|
||||
paths = []
|
||||
# deal with wildcards
|
||||
for path in get_classpath():
|
||||
if not path.endswith('*'):
|
||||
paths.append(path)
|
||||
else:
|
||||
paths.extend(glob(path + '.[Jj][Aa][Rr]'))
|
||||
return split_char.join(paths)
|
114
setup.py
114
setup.py
|
@ -1,7 +1,24 @@
|
|||
from distutils.core import setup, Extension
|
||||
from __future__ import print_function
|
||||
try:
|
||||
from setuptools import setup, Extension
|
||||
except ImportError:
|
||||
from distutils.core import setup, Extension
|
||||
from os import environ
|
||||
from os.path import dirname, join, exists
|
||||
import sys
|
||||
from platform import architecture
|
||||
|
||||
PY3 = sys.version_info >= (3,0,0)
|
||||
|
||||
def getenv(key):
|
||||
val = environ.get(key)
|
||||
if val is not None:
|
||||
if PY3:
|
||||
return val.decode()
|
||||
else:
|
||||
return val
|
||||
else:
|
||||
return val
|
||||
|
||||
files = [
|
||||
'jni.pxi',
|
||||
|
@ -10,6 +27,7 @@ files = [
|
|||
'jnius_export_func.pxi',
|
||||
'jnius_jvm_android.pxi',
|
||||
'jnius_jvm_desktop.pxi',
|
||||
'jnius_jvm_dlopen.pxi',
|
||||
'jnius_localref.pxi',
|
||||
'jnius.pyx',
|
||||
'jnius_utils.pxi',
|
||||
|
@ -17,14 +35,15 @@ files = [
|
|||
|
||||
libraries = []
|
||||
library_dirs = []
|
||||
lib_location = None
|
||||
extra_link_args = []
|
||||
include_dirs = []
|
||||
install_requires = []
|
||||
install_requires = ['six']
|
||||
|
||||
# detect Python for android
|
||||
platform = sys.platform
|
||||
ndkplatform = environ.get('NDKPLATFORM')
|
||||
if ndkplatform is not None and environ.get('LIBLINK'):
|
||||
ndkplatform = getenv('NDKPLATFORM')
|
||||
if ndkplatform is not None and getenv('LIBLINK'):
|
||||
platform = 'android'
|
||||
|
||||
# detect cython
|
||||
|
@ -32,34 +51,58 @@ try:
|
|||
from Cython.Distutils import build_ext
|
||||
install_requires.append('cython')
|
||||
except ImportError:
|
||||
from distutils.command.build_ext import build_ext
|
||||
try:
|
||||
from setuptools.command.build_ext import build_ext
|
||||
except ImportError:
|
||||
from distutils.command.build_ext import build_ext
|
||||
if platform != 'android':
|
||||
print '\n\nYou need Cython to compile Pyjnius.\n\n'
|
||||
print('\n\nYou need Cython to compile Pyjnius.\n\n')
|
||||
raise
|
||||
# On Android we expect to see 'c' files lying about.
|
||||
# and we go ahead with the 'desktop' file? Odd.
|
||||
files = [fn[:-3] + 'c' for fn in files if fn.endswith('pyx')]
|
||||
|
||||
if platform == 'android':
|
||||
# for android, we use SDL...
|
||||
libraries = ['sdl', 'log']
|
||||
library_dirs = ['libs/' + environ['ARCH']]
|
||||
library_dirs = ['libs/' + getenv('ARCH')]
|
||||
elif platform == 'darwin':
|
||||
import objc
|
||||
framework = objc.pathForFramework('JavaVM.framework')
|
||||
import subprocess
|
||||
framework = subprocess.Popen('/usr/libexec/java_home',
|
||||
shell=True, stdout=subprocess.PIPE).communicate()[0]
|
||||
if PY3:
|
||||
framework = framework.decode();
|
||||
framework = framework.strip()
|
||||
print('java_home: {0}\n'.format(framework));
|
||||
if not framework:
|
||||
raise Exception('You must install Java on your Mac OS X distro')
|
||||
extra_link_args = ['-framework', 'JavaVM']
|
||||
include_dirs = [join(framework, 'Versions/A/Headers')]
|
||||
if '1.6' in framework:
|
||||
lib_location = '../Libraries/libjvm.dylib'
|
||||
include_dirs = [join(framework, 'System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers')]
|
||||
else:
|
||||
lib_location = 'jre/lib/server/libjvm.dylib'
|
||||
include_dirs = ['{0}/include'.format(framework), '{0}/include/darwin'.format(framework)]
|
||||
else:
|
||||
import subprocess
|
||||
# otherwise, we need to search the JDK_HOME
|
||||
jdk_home = environ.get('JDK_HOME')
|
||||
if not jdk_home:
|
||||
jdk_home = subprocess.Popen('readlink -f `which javac` | sed "s:bin/javac::"',
|
||||
shell=True, stdout=subprocess.PIPE).communicate()[0].strip()
|
||||
jdk_home = getenv('JDK_HOME')
|
||||
if not jdk_home:
|
||||
if platform == 'win32':
|
||||
env_var = getenv('JAVA_HOME')
|
||||
if env_var and 'jdk' in env_var:
|
||||
jdk_home = env_var
|
||||
|
||||
# Remove /bin if it's appended to JAVA_HOME
|
||||
if jdk_home[-3:] == 'bin':
|
||||
jdk_home = jdk_home[:-4]
|
||||
else:
|
||||
jdk_home = subprocess.Popen('readlink -f `which javac` | sed "s:bin/javac::"',
|
||||
shell=True, stdout=subprocess.PIPE).communicate()[0].strip()
|
||||
if jdk_home is not None and PY3:
|
||||
jdk_home = jdk_home.decode()
|
||||
if not jdk_home or not exists(jdk_home):
|
||||
raise Exception('Unable to determine JDK_HOME')
|
||||
|
||||
jre_home = environ.get('JRE_HOME')
|
||||
if exists(join(jdk_home, 'jre')):
|
||||
jre_home = join(jdk_home, 'jre')
|
||||
if not jre_home:
|
||||
|
@ -67,17 +110,33 @@ else:
|
|||
shell=True, stdout=subprocess.PIPE).communicate()[0].strip()
|
||||
if not jre_home:
|
||||
raise Exception('Unable to determine JRE_HOME')
|
||||
cpu = 'i386' if sys.maxint == 2147483647 else 'amd64'
|
||||
cpu = 'amd64' if architecture()[0] == '64bit' else 'i386'
|
||||
|
||||
if platform == 'win32':
|
||||
incl_dir = join(jdk_home, 'include', 'win32')
|
||||
libraries = ['jvm']
|
||||
else:
|
||||
incl_dir = join(jdk_home, 'include', 'linux')
|
||||
lib_location = 'jre/lib/amd64/server/libjvm.so'
|
||||
|
||||
include_dirs = [
|
||||
join(jdk_home, 'include'),
|
||||
join(jdk_home, 'include', 'linux')]
|
||||
library_dirs = [join(jre_home, 'lib', cpu, 'server')]
|
||||
extra_link_args = ['-Wl,-rpath', library_dirs[0]]
|
||||
libraries = ['jvm']
|
||||
incl_dir]
|
||||
|
||||
if platform == 'win32':
|
||||
library_dirs = [
|
||||
join(jdk_home, 'lib'),
|
||||
join(jre_home, 'bin', 'server')]
|
||||
|
||||
# generate the config.pxi
|
||||
with open(join(dirname(__file__), 'jnius', 'config.pxi'), 'w') as fd:
|
||||
fd.write('DEF JNIUS_PLATFORM = {0!r}'.format(platform))
|
||||
fd.write('DEF JNIUS_PLATFORM = {0!r}\n\n'.format(platform))
|
||||
if PY3:
|
||||
fd.write('DEF JNIUS_PYTHON3 = True\n\n')
|
||||
else:
|
||||
fd.write('DEF JNIUS_PYTHON3 = False\n\n')
|
||||
if lib_location is not None:
|
||||
fd.write('DEF JNIUS_LIB_SUFFIX = {0!r}\n\n'.format(lib_location))
|
||||
|
||||
with open(join('jnius', '__init__.py')) as fd:
|
||||
versionline = [x for x in fd.readlines() if x.startswith('__version__')]
|
||||
|
@ -88,10 +147,11 @@ setup(name='jnius',
|
|||
version=version,
|
||||
cmdclass={'build_ext': build_ext},
|
||||
packages=['jnius'],
|
||||
py_modules=['jnius_config'],
|
||||
url='http://pyjnius.readthedocs.org/',
|
||||
author='Mathieu Virbel and Gabriel Pettier',
|
||||
author_email='mat@kivy.org,gabriel@kivy.org',
|
||||
license='LGPL',
|
||||
license='MIT',
|
||||
description='Python library to access Java classes',
|
||||
install_requires=install_requires,
|
||||
ext_package='jnius',
|
||||
|
@ -106,12 +166,14 @@ setup(name='jnius',
|
|||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: GNU Library or Lesser '
|
||||
'General Public License (LGPL)',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Natural Language :: English',
|
||||
'Operating System :: MacOS :: MacOS X',
|
||||
'Operating System :: MacOS :: OS X',
|
||||
'Operating System :: Microsoft :: Windows',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Topic :: Software Development :: Libraries :: Application Frameworks'])
|
||||
|
|
|
@ -22,6 +22,17 @@ public class BasicsTest {
|
|||
public float methodF() { return 1.23456789f; };
|
||||
public double methodD() { return 1.23456789; };
|
||||
public String methodString() { return new String("helloworld"); }
|
||||
public void methodException(int depth) throws IllegalArgumentException {
|
||||
if (depth == 0) throw new IllegalArgumentException("helloworld");
|
||||
else methodException(depth -1);
|
||||
}
|
||||
public void methodExceptionChained() throws IllegalArgumentException {
|
||||
try {
|
||||
methodException(5);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("helloworld2", e);
|
||||
}
|
||||
}
|
||||
|
||||
static public boolean fieldStaticZ = true;
|
||||
static public byte fieldStaticB = 127;
|
||||
|
@ -43,6 +54,19 @@ public class BasicsTest {
|
|||
public double fieldD = 1.23456789;
|
||||
public String fieldString = new String("helloworld");
|
||||
|
||||
public boolean fieldSetZ;
|
||||
public byte fieldSetB;
|
||||
public char fieldSetC;
|
||||
public short fieldSetS;
|
||||
public int fieldSetI;
|
||||
public long fieldSetJ;
|
||||
public float fieldSetF;
|
||||
public double fieldSetD;
|
||||
public String fieldSetString;
|
||||
|
||||
// Floating-point comparison epsilon
|
||||
private final static double EPSILON = 1E-6;
|
||||
|
||||
public BasicsTest() {}
|
||||
public BasicsTest(byte fieldBVal) {
|
||||
fieldB = fieldBVal;
|
||||
|
@ -97,9 +121,10 @@ public class BasicsTest {
|
|||
|
||||
public boolean methodParamsZBCSIJFD(boolean x1, byte x2, char x3, short x4,
|
||||
int x5, long x6, float x7, double x8) {
|
||||
// ADD float / double, but dunno how to do with approx
|
||||
return (x1 == true && x2 == 127 && x3 == 'k' && x4 == 32767 &&
|
||||
x5 == 2147483467 && x6 == 2147483467);
|
||||
x5 == 2147483467 && x6 == 2147483467 &&
|
||||
(Math.abs(x7 - 1.23456789f) < EPSILON) &&
|
||||
(Math.abs(x8 - 1.23456789) < EPSILON));
|
||||
}
|
||||
|
||||
public boolean methodParamsString(String s) {
|
||||
|
@ -141,4 +166,44 @@ public class BasicsTest {
|
|||
return false;
|
||||
return (x[0] == 127 && x[1] == 127 && x[2] == 127);
|
||||
}
|
||||
|
||||
public void fillByteArray(byte[] x) {
|
||||
if (x.length != 3)
|
||||
return;
|
||||
x[0] = 127;
|
||||
x[1] = 1;
|
||||
x[2] = -127;
|
||||
}
|
||||
|
||||
public boolean testFieldSetZ() {
|
||||
return (fieldSetZ == true);
|
||||
}
|
||||
|
||||
public boolean testFieldSetB() {
|
||||
return (fieldSetB == 127);
|
||||
}
|
||||
|
||||
public boolean testFieldSetC() {
|
||||
return (fieldSetC == 'k');
|
||||
}
|
||||
|
||||
public boolean testFieldSetS() {
|
||||
return (fieldSetS == 32767);
|
||||
}
|
||||
|
||||
public boolean testFieldSetI() {
|
||||
return (fieldSetI == 2147483467);
|
||||
}
|
||||
|
||||
public boolean testFieldSetJ() {
|
||||
return (fieldSetJ == 2147483467);
|
||||
}
|
||||
|
||||
public boolean testFieldSetF() {
|
||||
return (Math.abs(fieldSetF - 1.23456789f) < EPSILON);
|
||||
}
|
||||
|
||||
public boolean testFieldSetD() {
|
||||
return (Math.abs(fieldSetD - 1.23456789) < EPSILON);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.jnius;
|
||||
|
||||
public class MultipleDimensions {
|
||||
public static boolean methodParamsMatrixI(int[][] x) {
|
||||
if (x.length != 3 || x[0].length != 3)
|
||||
return false;
|
||||
return (x[0][0] == 1 && x[0][1] == 2 && x[1][2] == 6);
|
||||
}
|
||||
public static int[][] methodReturnMatrixI() {
|
||||
int[][] matrix = {{1,2,3},
|
||||
{4,5,6},
|
||||
{7,8,9}};
|
||||
return matrix;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius import autoclass, JavaException
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius import JavaException, JavaClass
|
||||
from jnius.reflect import autoclass
|
||||
|
@ -21,3 +24,31 @@ class BadDeclarationTest(unittest.TestCase):
|
|||
Stack = autoclass('java.util.Stack')
|
||||
stack = Stack()
|
||||
self.assertRaises(JavaException, stack.push, 'hello', 'world', 123)
|
||||
|
||||
def test_java_exception_handling(self):
|
||||
Stack = autoclass('java.util.Stack')
|
||||
stack = Stack()
|
||||
try:
|
||||
stack.pop()
|
||||
self.fail("Expected exception to be thrown")
|
||||
except JavaException as je:
|
||||
# print "Got JavaException: " + str(je)
|
||||
# print "Got Exception Class: " + je.classname
|
||||
# print "Got stacktrace: \n" + '\n'.join(je.stacktrace)
|
||||
self.assertEquals("java.util.EmptyStackException", je.classname)
|
||||
|
||||
def test_java_exception_chaining(self):
|
||||
BasicsTest = autoclass('org.jnius.BasicsTest')
|
||||
basics = BasicsTest()
|
||||
try:
|
||||
basics.methodExceptionChained()
|
||||
self.fail("Expected exception to be thrown")
|
||||
except JavaException as je:
|
||||
# print "Got JavaException: " + str(je)
|
||||
# print "Got Exception Class: " + je.classname
|
||||
# print "Got Exception Message: " + je.innermessage
|
||||
# print "Got stacktrace: \n" + '\n'.join(je.stacktrace)
|
||||
self.assertEquals("java.lang.IllegalArgumentException", je.classname)
|
||||
self.assertEquals("helloworld2", je.innermessage)
|
||||
self.assertIn("Caused by:", je.stacktrace)
|
||||
self.assertEquals(11, len(je.stacktrace))
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius.reflect import autoclass
|
||||
|
||||
|
@ -55,6 +58,26 @@ class BasicsTest(unittest.TestCase):
|
|||
self.assertEquals(test.fieldB, 127)
|
||||
self.assertEquals(test2.fieldB, 10)
|
||||
|
||||
def test_instance_set_fields(self):
|
||||
test = autoclass('org.jnius.BasicsTest')()
|
||||
test.fieldSetZ = True
|
||||
test.fieldSetB = 127
|
||||
test.fieldSetC = ord('k')
|
||||
test.fieldSetS = 32767
|
||||
test.fieldSetI = 2147483467
|
||||
test.fieldSetJ = 2147483467
|
||||
test.fieldSetF = 1.23456789
|
||||
test.fieldSetD = 1.23456789
|
||||
|
||||
self.assertTrue(test.testFieldSetZ())
|
||||
self.assertTrue(test.testFieldSetB())
|
||||
self.assertTrue(test.testFieldSetC())
|
||||
self.assertTrue(test.testFieldSetS())
|
||||
self.assertTrue(test.testFieldSetI())
|
||||
self.assertTrue(test.testFieldSetJ())
|
||||
self.assertTrue(test.testFieldSetF())
|
||||
self.assertTrue(test.testFieldSetD())
|
||||
|
||||
def test_instances_methods_array(self):
|
||||
test = autoclass('org.jnius.BasicsTest')()
|
||||
self.assertEquals(test.methodArrayZ(), [True] * 3)
|
||||
|
@ -98,7 +121,7 @@ class BasicsTest(unittest.TestCase):
|
|||
|
||||
def test_instances_methods_params_object_list_long(self):
|
||||
test = autoclass('org.jnius.BasicsTest')()
|
||||
self.assertEquals(test.methodParamsObject([1L, 2L]), True)
|
||||
self.assertEquals(test.methodParamsObject([1, 2]), True)
|
||||
|
||||
def test_instances_methods_params_array_byte(self):
|
||||
test = autoclass('org.jnius.BasicsTest')()
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius import autoclass
|
||||
|
||||
|
@ -6,4 +9,16 @@ class StringArgumentForByteArrayTest(unittest.TestCase):
|
|||
def test_string_arg_for_byte_array(self):
|
||||
# the ByteBuffer.wrap() accept only byte[].
|
||||
ByteBuffer = autoclass('java.nio.ByteBuffer')
|
||||
self.assertIsNotNone(ByteBuffer.wrap('hello world'))
|
||||
self.assertIsNotNone(ByteBuffer.wrap(b'hello world'))
|
||||
|
||||
def test_string_arg_with_signed_char(self):
|
||||
ByteBuffer = autoclass('java.nio.ByteBuffer')
|
||||
self.assertIsNotNone(ByteBuffer.wrap(b'\x00\xffHello World\x7f'))
|
||||
|
||||
def test_fill_byte_array(self):
|
||||
arr = [0, 0, 0]
|
||||
Test = autoclass('org.jnius.BasicsTest')()
|
||||
Test.fillByteArray(arr)
|
||||
self.assertEquals(
|
||||
arr,
|
||||
[127, 1, -127])
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius.reflect import autoclass
|
||||
from jnius import cast
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius.reflect import autoclass
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
|
||||
from jnius.reflect import autoclass
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius.reflect import autoclass
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
|
||||
from jnius import autoclass, JavaException
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
# run it, and check with Java VisualVM if we are eating too much memory or not!
|
||||
if __name__ == '__main__':
|
||||
from jnius import autoclass
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius.reflect import autoclass
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius.reflect import autoclass
|
||||
|
||||
class MultipleDimensionsTest(unittest.TestCase):
|
||||
|
||||
def test_multiple_dimensions(self):
|
||||
MultipleDims = autoclass('org.jnius.MultipleDimensions')
|
||||
matrix = [[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9]]
|
||||
self.assertEquals(MultipleDims.methodParamsMatrixI(matrix), True)
|
||||
self.assertEquals(MultipleDims.methodReturnMatrixI(), matrix)
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius import autoclass
|
||||
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
from jnius import autoclass, java_method, PythonJavaClass, cast
|
||||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
from six.moves import range
|
||||
|
||||
print '1: declare a TestImplem that implement Collection'
|
||||
from jnius import autoclass, java_method, PythonJavaClass, cast
|
||||
from nose.tools import *
|
||||
|
||||
print('1: declare a TestImplem that implement Collection')
|
||||
|
||||
|
||||
class TestImplemIterator(PythonJavaClass):
|
||||
|
@ -96,47 +102,65 @@ class TestImplem(PythonJavaClass):
|
|||
return it
|
||||
|
||||
|
||||
print '2: instanciate the class, with some data'
|
||||
a = TestImplem(*range(10))
|
||||
print a
|
||||
print dir(a)
|
||||
class TestBadSignature(PythonJavaClass):
|
||||
__javainterfaces__ = ['java/util/List']
|
||||
|
||||
print 'tries to get a ListIterator'
|
||||
@java_method('(Landroid/bluetooth/BluetoothDevice;IB[])V')
|
||||
def bad_signature(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
print('2: instantiate the class, with some data')
|
||||
a = TestImplem(*list(range(10)))
|
||||
print(a)
|
||||
print(dir(a))
|
||||
|
||||
print('tries to get a ListIterator')
|
||||
iterator = a.listIterator()
|
||||
print 'iterator is', iterator
|
||||
print('iterator is', iterator)
|
||||
while iterator.hasNext():
|
||||
print 'at index', iterator.index, 'value is', iterator.next()
|
||||
print('at index', iterator.index, 'value is', iterator.next())
|
||||
|
||||
print '3: Do cast to a collection'
|
||||
print('3: Do cast to a collection')
|
||||
a2 = cast('java/util/Collection', a.j_self)
|
||||
print a2
|
||||
print(a2)
|
||||
|
||||
print '4: Try few method on the collection'
|
||||
print('4: Try few method on the collection')
|
||||
Collections = autoclass('java.util.Collections')
|
||||
#print Collections.enumeration(a)
|
||||
#print Collections.enumeration(a)
|
||||
ret = Collections.max(a)
|
||||
|
||||
print "reverse"
|
||||
print Collections.reverse(a)
|
||||
print a.data
|
||||
print("reverse")
|
||||
print(Collections.reverse(a))
|
||||
print(a.data)
|
||||
|
||||
print "before swap"
|
||||
print Collections.swap(a, 2, 3)
|
||||
print "after swap"
|
||||
print a.data
|
||||
print("before swap")
|
||||
print(Collections.swap(a, 2, 3))
|
||||
print("after swap")
|
||||
print(a.data)
|
||||
|
||||
print "rotate"
|
||||
print Collections.rotate(a, 5)
|
||||
print a.data
|
||||
print("rotate")
|
||||
print(Collections.rotate(a, 5))
|
||||
print(a.data)
|
||||
|
||||
print 'Order of data before shuffle()', a.data
|
||||
print Collections.shuffle(a)
|
||||
print 'Order of data after shuffle()', a.data
|
||||
print('Order of data before shuffle()', a.data)
|
||||
print(Collections.shuffle(a))
|
||||
print('Order of data after shuffle()', a.data)
|
||||
|
||||
|
||||
# XXX We have issues for methosd with multiple signature
|
||||
print '-> Collections.max(a)'
|
||||
print Collections.max(a2)
|
||||
print('-> Collections.max(a)')
|
||||
print(Collections.max(a2))
|
||||
#print '-> Collections.shuffle(a)'
|
||||
#print Collections.shuffle(a2)
|
||||
|
||||
# test bad signature
|
||||
threw = False
|
||||
try:
|
||||
TestBadSignature()
|
||||
except Exception:
|
||||
threw = True
|
||||
|
||||
if not threw:
|
||||
raise Exception("Failed to throw for bad signature")
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius.reflect import autoclass
|
||||
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
import unittest
|
||||
|
||||
from jnius import autoclass, java_method, PythonJavaClass, cast
|
||||
|
||||
from jnius.signatures import *
|
||||
|
||||
JObject = autoclass('java/lang/Object')
|
||||
JString = autoclass('java/lang/String')
|
||||
JListIterator = autoclass("java.util.ListIterator")
|
||||
|
||||
class TestImplemIterator(PythonJavaClass):
|
||||
__javainterfaces__ = [
|
||||
'java/util/ListIterator', ]
|
||||
|
||||
def __init__(self, collection, index=0):
|
||||
super(TestImplemIterator, self).__init__()
|
||||
self.collection = collection
|
||||
self.index = index
|
||||
|
||||
@with_signature(jboolean, [])
|
||||
def hasNext(self):
|
||||
return self.index < len(self.collection.data) - 1
|
||||
|
||||
@with_signature(JObject, [])
|
||||
def next(self):
|
||||
obj = self.collection.data[self.index]
|
||||
self.index += 1
|
||||
return obj
|
||||
|
||||
@with_signature(jboolean, [])
|
||||
def hasPrevious(self):
|
||||
return self.index >= 0
|
||||
|
||||
@with_signature(JObject, [])
|
||||
def previous(self):
|
||||
self.index -= 1
|
||||
obj = self.collection.data[self.index]
|
||||
return obj
|
||||
|
||||
@with_signature(jint, [])
|
||||
def previousIndex(self):
|
||||
return self.index - 1
|
||||
|
||||
@with_signature(JString, [])
|
||||
def toString(self):
|
||||
return repr(self)
|
||||
|
||||
@with_signature(JObject, [jint])
|
||||
def get(self, index):
|
||||
return self.collection.data[index - 1]
|
||||
|
||||
@with_signature(jvoid, [JObject])
|
||||
def set(self, obj):
|
||||
self.collection.data[self.index - 1] = obj
|
||||
|
||||
|
||||
class TestImplem(PythonJavaClass):
|
||||
__javainterfaces__ = ['java/util/List']
|
||||
|
||||
def __init__(self, *args):
|
||||
super(TestImplem, self).__init__(*args)
|
||||
self.data = list(args)
|
||||
|
||||
@with_signature(autoclass("java.util.Iterator"), [])
|
||||
def iterator(self):
|
||||
it = TestImplemIterator(self)
|
||||
return it
|
||||
|
||||
@with_signature(JString, [])
|
||||
def toString(self):
|
||||
return repr(self)
|
||||
|
||||
@with_signature(jint, [])
|
||||
def size(self):
|
||||
return len(self.data)
|
||||
|
||||
@with_signature(JObject, [jint])
|
||||
def get(self, index):
|
||||
return self.data[index]
|
||||
|
||||
@with_signature(JObject, [jint, JObject])
|
||||
def set(self, index, obj):
|
||||
old_object = self.data[index]
|
||||
self.data[index] = obj
|
||||
return old_object
|
||||
|
||||
@with_signature(JArray(JObject), [])
|
||||
def toArray(self):
|
||||
return self.data
|
||||
|
||||
@with_signature(JListIterator, [])
|
||||
def listIterator(self):
|
||||
it = TestImplemIterator(self)
|
||||
return it
|
||||
|
||||
# TODO cover this case of listIterator.
|
||||
@java_method(signature(JListIterator, [jint]),
|
||||
name='ListIterator')
|
||||
def listIteratorI(self, index):
|
||||
it = TestImplemIterator(self, index)
|
||||
return it
|
||||
|
||||
|
||||
from jnius.reflect import autoclass
|
||||
|
||||
class SignaturesTest(unittest.TestCase):
|
||||
|
||||
def test_construct_stack_from_testimplem(self):
|
||||
Stack = autoclass("java.util.Stack")
|
||||
pyjlist = TestImplem(1, 2, 3, 4, 5, 6, 7)
|
||||
stack = Stack()
|
||||
stack.addAll(pyjlist)
|
||||
self.assertEquals(7, pyjlist.size())
|
||||
self.assertEquals(stack.size(), pyjlist.size())
|
||||
array = pyjlist.toArray()
|
||||
|
||||
def test_return_types(self):
|
||||
|
||||
# Void
|
||||
sig = signature(jvoid, [])
|
||||
self.assertEquals(sig, "()V")
|
||||
|
||||
# Boolean
|
||||
sig = signature(jboolean, [])
|
||||
self.assertEquals(sig, "()Z")
|
||||
|
||||
# Byte
|
||||
sig = signature(jbyte, [])
|
||||
self.assertEquals(sig, "()B")
|
||||
|
||||
# Char
|
||||
sig = signature(jchar, [])
|
||||
self.assertEquals(sig, "()C")
|
||||
|
||||
# Double
|
||||
sig = signature(jdouble, [])
|
||||
self.assertEquals(sig, "()D")
|
||||
|
||||
# Float
|
||||
sig = signature(jfloat, [])
|
||||
self.assertEquals(sig, "()F")
|
||||
|
||||
# Int
|
||||
sig = signature(jint, [])
|
||||
self.assertEquals(sig, "()I")
|
||||
|
||||
# Long
|
||||
sig = signature(jlong, [])
|
||||
self.assertEquals(sig, "()J")
|
||||
|
||||
# Short
|
||||
sig = signature(jshort, [])
|
||||
self.assertEquals(sig, "()S")
|
||||
|
||||
# Object return method
|
||||
String = autoclass("java.lang.String")
|
||||
sig = signature(String, [])
|
||||
self.assertEquals(sig, "()Ljava/lang/String;")
|
||||
|
||||
# Array return
|
||||
sig = signature(JArray(jint), [])
|
||||
self.assertEquals(sig, "()[I")
|
||||
|
||||
def test_params(self):
|
||||
String = autoclass("java.lang.String")
|
||||
|
||||
# Return void, takes objects as parameters
|
||||
sig = signature(jvoid, [String, String])
|
||||
self.assertEquals(sig, "(Ljava/lang/String;Ljava/lang/String;)V")
|
||||
|
||||
# Multiple array parameter types
|
||||
sig = signature(jvoid, [JArray(jint), JArray(jboolean)])
|
||||
self.assertEquals(sig, "([I[Z)V")
|
||||
|
|
@ -1,12 +1,15 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
import unittest
|
||||
from jnius import JavaClass, MetaJavaClass, JavaMethod
|
||||
from six import with_metaclass
|
||||
|
||||
class HelloWorldTest(unittest.TestCase):
|
||||
|
||||
def test_helloworld(self):
|
||||
|
||||
class HelloWorld(JavaClass):
|
||||
__metaclass__ = MetaJavaClass
|
||||
class HelloWorld(with_metaclass(MetaJavaClass, JavaClass)):
|
||||
__javaclass__ = 'org/jnius/HelloWorld'
|
||||
hello = JavaMethod('()Ljava/lang/String;')
|
||||
|
||||
|
|
Loading…
Reference in New Issue