Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to JProxy #470

Merged
merged 6 commits into from Jun 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions jpype/_jarray.py
Expand Up @@ -14,8 +14,12 @@
# limitations under the License.
#
# *****************************************************************************
import collections
import sys as _sys
try:
from collections.abc import Sequence
except ImportError:
from collections import Sequence


import _jpype
from . import _jclass
Expand Down Expand Up @@ -245,7 +249,7 @@ def _JArrayNewClass(cls, ndims=1):
# Cannot be Mutable because java arrays are fixed in length

def _isIterable(obj):
if isinstance(obj, collections.Sequence):
if isinstance(obj, Sequence):
return True
if hasattr(obj, '__len__') and hasattr(obj, '__iter__'):
return True
Expand Down
7 changes: 5 additions & 2 deletions jpype/_jcollection.py
Expand Up @@ -14,7 +14,10 @@
# limitations under the License.
#
# *****************************************************************************
import collections
try:
from collections.abc import Sequence
except ImportError:
from collections import Sequence

from . import _jclass
from . import _jcustomizer
Expand All @@ -24,7 +27,7 @@


def isPythonSequence(v):
if isinstance(v, collections.Sequence):
if isinstance(v, Sequence):
if not hasattr(v.__class__, '__metaclass__') \
or v.__class__.__metaclass__ is _jclass._JavaClass:
return True
Expand Down
73 changes: 44 additions & 29 deletions jpype/_jproxy.py
Expand Up @@ -30,7 +30,7 @@
# so we can properly handle name mangling on the override.


def _createJProxy(cls, intf, **kwargs):
def _createJProxy(cls, *intf, **kwargs):
""" (internal) Create a proxy from a python class with
@JOverride notation on methods.
"""
Expand All @@ -52,7 +52,7 @@ def _createJProxy(cls, intf, **kwargs):
if method.getModifiers() & 1024 == 0:
continue
if not str(method.getName()) in overrides:
raise NotImplementedError("Interface %s requires method %s to be implemented." % (
raise NotImplementedError("Interface '%s' requires method '%s' to be implemented." % (
interface.class_.getName(), method.getName()))

# Define a lookup interface
Expand Down Expand Up @@ -90,52 +90,64 @@ def JImplements(*args, **kwargs):
should have a @JOverride annotation.

Args:
interfaces (str): Strings for each Java interface this proxy is to
implement.
interfaces (str*,JClass*): Strings or JClasses for each Java interface
this proxy is to implement.

Example:

.. code-block:: python

@JImplement("org.my.Interface")
@JImplement("java.lang.Runnable")
class MyImpl(object):
@JOverride
def run(self, arg):
pass

@JImplement("org.my.Interface1", "org.my.Interface2")
class MyImpl(object):
@JOverride
def method(self, arg):
pass

"""
def f(cls):
return _createJProxy(cls, args, **kwargs)
return f
def JProxyCreator(cls):
return _createJProxy(cls, *args, **kwargs)
return JProxyCreator


def _convertInterfaces(intf):
""" (internal) Convert a list of interface names into
a list of interfaces suitable for a proxy.
"""
# We operate on lists of interfaces, so a single element is promoted
# to a list
if not isinstance(intf, collections.Sequence):
intf = [intf]

# Verify that the list contains the required types
actualIntf = []
for i in intf:
if isinstance(i, str) or isinstance(i, unicode):
actualIntf.append(_jclass.JClass(i))
elif isinstance(i, _jclass.JClass):
actualIntf.append(i)
# Flatten the list
intflist = []
for item in intf:
if isinstance(item, (str, unicode)) or not hasattr(item, '__iter__'):
intflist.append(item)
else:
raise TypeError("JProxy requires java interface classes "
"or the names of java interfaces classes: {0}".format(i.__name))
intflist.extend(item)

# Look up the classes if given as a string
actualIntf = set()
for item in intflist:
if isinstance(item, (str, unicode)):
actualIntf.add(_jclass.JClass(item))
else:
actualIntf.add(item)

# Check that all are interfaces
for i in actualIntf:
if not issubclass(i, _jclass.JInterface):
raise TypeError("JProxy requires java interface classes "
"or the names of java interfaces classes: {0}"
.format(i.__name__))
if not actualIntf:
raise TypeError("At least one Java interface must be specified")

for cls in actualIntf:
# If it isn't a JClass, then it cannot be a Java interface
if not isinstance(cls, _jclass.JClass):
raise TypeError("'%s' is not a Java interface"%type(cls).__name__)
# Java concrete and abstract classes cannot be proxied
if not issubclass(cls, _jclass.JInterface):
raise TypeError("'%s' is not a Java interface"%cls.__name__)

return actualIntf
return tuple(actualIntf)


class JProxy(object):
Expand Down Expand Up @@ -165,7 +177,7 @@ class JProxy(object):

def __init__(self, intf, dict=None, inst=None):
# Convert the interfaces
actualIntf = _convertInterfaces(intf)
actualIntf = _convertInterfaces([intf])

# Verify that one of the options has been selected
if dict is not None and inst is not None:
Expand All @@ -177,10 +189,13 @@ def lookup(d, name):
return d[name]
# create a proxy
self.__javaproxy__ = _jpype.PyJPProxy(dict, lookup, actualIntf)
return

if inst is not None:
# Define the lookup function based for a object instance
def lookup(d, name):
return getattr(d, name)
# create a proxy
self.__javaproxy__ = _jpype.PyJPProxy(inst, lookup, actualIntf)
return
raise TypeError("a dict or inst must be specified")
14 changes: 7 additions & 7 deletions native/common/include/jp_methodoverload.h
Expand Up @@ -12,7 +12,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*****************************************************************************/
#ifndef _JPMETHODOVERLOAD_H_
#define _JPMETHODOVERLOAD_H_
Expand Down Expand Up @@ -62,10 +62,10 @@ class JPMethodOverload
*
* @param isInstance is true if the first argument is an instance object.
* @param args is a list of arguments including the instance.
*
*
*/
JPMatch matches(bool isInstance, JPPyObjectVector& args) ;
JPPyObject invoke(JPMatch& match, JPPyObjectVector& arg);
JPPyObject invoke(JPMatch& match, JPPyObjectVector& arg, bool instance);
JPValue invokeConstructor(JPMatch& match, JPPyObjectVector& arg);

bool isStatic() const
Expand Down Expand Up @@ -111,14 +111,14 @@ class JPMethodOverload
bool checkMoreSpecificThan(JPMethodOverload* other) const;

/** Used to determine if a bean get property should be added to the class.
*
* FIXME This does not check for begins with "get"
*
* FIXME This does not check for begins with "get"
*/
bool isBeanAccessor();

/** Used to determine if a bean set property should be added to the class.
*
* FIXME This does not check for begins with "set" or "is"
*
* FIXME This does not check for begins with "set" or "is"
*/
bool isBeanMutator();

Expand Down
2 changes: 1 addition & 1 deletion native/common/jp_method.cpp
Expand Up @@ -254,7 +254,7 @@ JPPyObject JPMethod::invoke(JPPyObjectVector& args, bool instance)
{
JP_TRACE_IN("JPMethod::invoke");
JPMatch match = findOverload(args, instance);
return match.overload->invoke(match, args);
return match.overload->invoke(match, args, instance);
JP_TRACE_OUT;
}

Expand Down
6 changes: 3 additions & 3 deletions native/common/jp_methodoverload.cpp
Expand Up @@ -12,7 +12,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*****************************************************************************/
#include <jpype.h>

Expand Down Expand Up @@ -244,7 +244,7 @@ void JPMethodOverload::packArgs(JPMatch& match, vector<jvalue>& v, JPPyObjectVec
JP_TRACE_OUT;
}

JPPyObject JPMethodOverload::invoke(JPMatch& match, JPPyObjectVector& arg)
JPPyObject JPMethodOverload::invoke(JPMatch& match, JPPyObjectVector& arg, bool instance)
{
JP_TRACE_IN("JPMethodOverload::invoke");
ensureTypeCache();
Expand All @@ -268,7 +268,7 @@ JPPyObject JPMethodOverload::invoke(JPMatch& match, JPPyObjectVector& arg)
JPValue* selfObj = JPPythonEnv::getJavaValue(arg[0]);
jobject c = selfObj->getJavaObject();
jclass clazz = NULL;
if (!m_IsAbstract)
if (!m_IsAbstract && !instance)
clazz = m_Class->getJavaClass();
return retType->invoke(frame, c, clazz, m_MethodID, &v[0]);
}
Expand Down
5 changes: 4 additions & 1 deletion native/python/include/pyjp_method.h
Expand Up @@ -12,7 +12,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*****************************************************************************/
#ifndef _PYMETHOD_H_
#define _PYMETHOD_H_
Expand All @@ -30,6 +30,9 @@ struct PyJPMethod

static PyObject* __new__(PyTypeObject* self, PyObject* args, PyObject* kwargs);
static void __dealloc__(PyJPMethod* o);
static int traverse(PyJPMethod *self, visitproc visit, void *arg);
static int clear(PyJPMethod *self);

static PyObject* __get__(PyJPMethod* self, PyObject* obj, PyObject* type);
static PyObject* __str__(PyJPMethod* o);
static PyObject* __call__(PyJPMethod* self, PyObject* args, PyObject* kwargs);
Expand Down
4 changes: 3 additions & 1 deletion native/python/include/pyjp_proxy.h
Expand Up @@ -13,7 +13,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*****************************************************************************/
#ifndef _PYJPPROXY_H_
#define _PYJPPROXY_H_
Expand All @@ -29,6 +29,8 @@ struct PyJPProxy
static PyObject* __new__(PyTypeObject* self, PyObject* args, PyObject* kwargs);
static int __init__(PyJPProxy* self, PyObject* args, PyObject* kwargs);
static void __dealloc__(PyJPProxy* self);
static int traverse(PyJPProxy *self, visitproc visit, void *arg);
static int clear(PyJPProxy *self);
static PyObject* __str__(PyJPProxy* self);

JPProxy* m_Proxy;
Expand Down
5 changes: 4 additions & 1 deletion native/python/include/pyjp_value.h
Expand Up @@ -12,7 +12,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*****************************************************************************/
#ifndef _PYJP_VALUE_H_
#define _PYJP_VALUE_H_
Expand All @@ -32,6 +32,9 @@ struct PyJPValue
static PyObject* __new__(PyTypeObject* self, PyObject* args, PyObject* kwargs);
static int __init__(PyJPValue* self, PyObject* args, PyObject* kwargs);
static void __dealloc__(PyJPValue* self);
static int traverse(PyJPValue *self, visitproc visit, void *arg);
static int clear(PyJPValue *self);

static PyObject* __str__(PyJPValue* self);
static PyObject* toString(PyJPValue* self);
static PyObject* toUnicode(PyJPValue* self);
Expand Down
8 changes: 4 additions & 4 deletions native/python/pyjp_array.cpp
Expand Up @@ -12,10 +12,10 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*****************************************************************************/

// FIXME PyJPArray should inherit from PyJPValue so that arrays are
// FIXME PyJPArray should inherit from PyJPValue so that arrays are
// properly specializations of value types.

#include <pyjp.h>
Expand Down Expand Up @@ -88,7 +88,7 @@ JPPyObject PyJPArray::alloc(JPArray* obj)
{
JPJavaFrame fame;
JP_TRACE_IN("PyJPArray::alloc");
PyJPArray* res = PyObject_New(PyJPArray, &PyJPArray::Type);
PyJPArray* res = (PyJPArray*) PyJPArray::Type.tp_alloc(&PyJPArray::Type, 0);
JP_PY_CHECK();
res->m_Array = obj;
return JPPyObject(JPPyRef::_claim, (PyObject*) res);
Expand All @@ -98,7 +98,7 @@ JPPyObject PyJPArray::alloc(JPArray* obj)
PyObject* PyJPArray::__new__(PyTypeObject* type, PyObject* args, PyObject* kwargs)
{
PyJPArray* self = (PyJPArray*) type->tp_alloc(type, 0);
self->m_Array = 0;
self->m_Array = NULL;
return (PyObject*) self;
}

Expand Down
8 changes: 4 additions & 4 deletions native/python/pyjp_class.cpp
Expand Up @@ -12,7 +12,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*****************************************************************************/

#include <pyjp.h>
Expand Down Expand Up @@ -99,7 +99,7 @@ bool PyJPClass::check(PyObject* o)

JPPyObject PyJPClass::alloc(JPClass* cls)
{
PyJPClass* res = PyObject_New(PyJPClass, &PyJPClass::Type);
PyJPClass* res = (PyJPClass*) PyJPClass::Type.tp_alloc(&PyJPClass::Type, 0);
JP_PY_CHECK();
res->m_Class = cls;
return JPPyObject(JPPyRef::_claim, (PyObject*) res);
Expand All @@ -108,7 +108,7 @@ JPPyObject PyJPClass::alloc(JPClass* cls)
PyObject* PyJPClass::__new__(PyTypeObject* type, PyObject* args, PyObject* kwargs)
{
PyJPClass* self = (PyJPClass*) type->tp_alloc(type, 0);
self->m_Class = 0;
self->m_Class = NULL;
return (PyObject*) self;
}

Expand Down Expand Up @@ -310,7 +310,7 @@ PyObject* PyJPClass::isAssignableFrom(PyJPClass* self, PyObject* arg)
ASSERT_JVM_RUNNING("PyJPClass::isSubClass");
JPJavaFrame frame;

// We have to lookup the name by string here because the
// We have to lookup the name by string here because the
// class wrapper may not exist. This is used by the
// customizers.
PyObject* other;
Expand Down