Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions native/common/include/jp_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@
return JPModifier::isThrowable(m_Modifiers);
}

bool isGeneric() const

Check warning on line 81 in native/common/include/jp_class.h

View check run for this annotation

Codecov / codecov/patch

native/common/include/jp_class.h#L81

Added line #L81 was not covered by tests
{
return JPModifier::isGeneric(m_Modifiers);

Check warning on line 83 in native/common/include/jp_class.h

View check run for this annotation

Codecov / codecov/patch

native/common/include/jp_class.h#L83

Added line #L83 was not covered by tests
}

bool isInterface() const
{
return JPModifier::isInterface(m_Modifiers);
Expand Down
5 changes: 5 additions & 0 deletions native/common/include/jp_modifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@
return (modifier & 0x01000000) == 0x01000000;
}

inline bool isGeneric(jlong modifier)

Check warning on line 169 in native/common/include/jp_modifier.h

View check run for this annotation

Codecov / codecov/patch

native/common/include/jp_modifier.h#L169

Added line #L169 was not covered by tests
{
return (modifier & 0x02000000) == 0x02000000;

Check warning on line 171 in native/common/include/jp_modifier.h

View check run for this annotation

Codecov / codecov/patch

native/common/include/jp_modifier.h#L171

Added line #L171 was not covered by tests
}

inline bool isConstructor(jlong modifier)
{
return (modifier & 0x10000000) == 0x10000000;
Expand Down
1 change: 1 addition & 0 deletions native/java/org/jpype/manager/ModifierCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public enum ModifierCode
PRIMITIVE_ARRAY(0x00400000),
COMPARABLE(0x00800000),
BUFFER(0x01000000),
GENERIC(0x02000000),
CTOR(0x10000000),
BEAN_ACCESSOR(0x20000000),
BEAN_MUTATOR(0x40000000);
Expand Down
4 changes: 3 additions & 1 deletion native/java/org/jpype/manager/TypeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,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.

See NOTICE file for details.
**************************************************************************** */
package org.jpype.manager;
Expand Down Expand Up @@ -412,6 +412,8 @@ private ClassDescriptor createClass(Class<?> cls, boolean special)
if (this.functionalAnnotation != null
&& cls.getAnnotation(this.functionalAnnotation) != null)
modifiers |= ModifierCode.FUNCTIONAL.value | ModifierCode.SPECIAL.value;
if (cls.getTypeParameters().length > 0)
modifiers |= ModifierCode.GENERIC.value;

// FIXME watch out for anonyous and lambda here.
String name = cls.getCanonicalName();
Expand Down
1 change: 1 addition & 0 deletions native/python/include/pyjp.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ extern PyTypeObject *PyJPChar_Type;


// JPype resources
extern PyObject *PyJClass_Generics;
extern PyObject *PyJPModule;
extern PyObject *_JArray;
extern PyObject *_JChar;
Expand Down
91 changes: 85 additions & 6 deletions native/python/pyjp_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -700,12 +700,72 @@
#endif
}

static PyObject *handleGeneric(JPJavaFrame &frame, PyJPClass *self, PyObject *item)

Check warning on line 703 in native/python/pyjp_class.cpp

View check run for this annotation

Codecov / codecov/patch

native/python/pyjp_class.cpp#L703

Added line #L703 was not covered by tests
{
if (!self->m_Class->isGeneric())
{
PyErr_Format(PyExc_TypeError, "Type is not generic");
return 0;

Check warning on line 708 in native/python/pyjp_class.cpp

View check run for this annotation

Codecov / codecov/patch

native/python/pyjp_class.cpp#L708

Added line #L708 was not covered by tests
}

Py_ssize_t dims = PyTuple_Size(item);
Py_ssize_t i = 0;

Check warning on line 712 in native/python/pyjp_class.cpp

View check run for this annotation

Codecov / codecov/patch

native/python/pyjp_class.cpp#L712

Added line #L712 was not covered by tests

stringstream name;
for (; i < dims; ++i)
{
PyObject* t = PyTuple_GetItem(item, i);
if (!PyJPClass_Check(t))
break;

Check warning on line 719 in native/python/pyjp_class.cpp

View check run for this annotation

Codecov / codecov/patch

native/python/pyjp_class.cpp#L719

Added line #L719 was not covered by tests

if (i > 0)
name << ',';
name << ((PyTypeObject*) item)->tp_name;
}

if (i != dims)
{
PyErr_Format(PyExc_TypeError, "Generic parameters must be Java");
return 0;

Check warning on line 729 in native/python/pyjp_class.cpp

View check run for this annotation

Codecov / codecov/patch

native/python/pyjp_class.cpp#L729

Added line #L729 was not covered by tests
}

// Return a generic type wrapper.
JPPyObject key = JPPyObject::call(PyUnicode_FromFormat("%s<%s>",
((PyTypeObject*) self)->tp_name,
name.str().c_str()));
PyObject *cache = PyDict_GetItem(PyJClass_Generics, key.get());
if (cache != NULL)
{
Py_INCREF(cache);
return cache;

Check warning on line 740 in native/python/pyjp_class.cpp

View check run for this annotation

Codecov / codecov/patch

native/python/pyjp_class.cpp#L739-L740

Added lines #L739 - L740 were not covered by tests
}

// Allocate a new type
JPPyObject bases = JPPyObject::call(PyTuple_Pack(1, self));
JPPyObject members = JPPyObject::call(PyDict_New());
JPPyObject args = JPPyObject::call(PyTuple_Pack(3, key.get(), bases.get(), members.get()));
JPPyObject generic = JPPyObject::call(PyObject_Call((PyObject*) PyJPClass_Type, args.get(), classMagic));
PyObject_SetAttrString(generic.get(), "_generics", item);
PyDict_SetItem(PyJClass_Generics, key.get(), generic.get());
PyJPClass *cls2 = (PyJPClass*) generic.get();
cls2->m_Class = self->m_Class;
PyJPValue_assignJavaSlot(frame, (PyObject*) cls2, JPValue(frame.getContext()->_java_lang_Class,

Check warning on line 752 in native/python/pyjp_class.cpp

View check run for this annotation

Codecov / codecov/patch

native/python/pyjp_class.cpp#L750-L752

Added lines #L750 - L752 were not covered by tests
(jobject) self->m_Class->getJavaClass()));
return generic.keep();
}

static PyObject *PyJPClass_array(PyJPClass *self, PyObject *item)
{
JP_PY_TRY("PyJPClass_array");
JPContext *context = PyJPModule_getContext();
JPJavaFrame frame = JPJavaFrame::outer(context);

if (PyType_Check(item))
{
JPPyObject types = JPPyObject::call(PyTuple_Pack(1, item));
return handleGeneric(frame, self, types.get());
}

if (PyIndex_Check(item))
{
long sz = PyLong_AsLong(item);
Expand All @@ -728,6 +788,25 @@
Py_ssize_t defined = 0;
Py_ssize_t undefined = 0;

//Check if it is a generic specification
{
bool generic = true;
for (; i < dims; ++i)
{
PyObject* t = PyTuple_GetItem(item, i);
if (!PyType_Check(t))
{
generic = false;
break;
}
}

if (generic)
{
return handleGeneric(frame, self, item);
}
}

std::vector<int> sz;
for (; i < dims; ++i)
{
Expand Down Expand Up @@ -778,7 +857,7 @@
JP_PY_CATCH(NULL);
}

static PyObject *PyJPClass_cast(PyJPClass *self, PyObject *other)
static PyObject * PyJPClass_cast(PyJPClass *self, PyObject * other)
{
JP_PY_TRY("PyJPClass_cast");
JPContext *context = PyJPModule_getContext();
Expand Down Expand Up @@ -850,15 +929,15 @@
JP_PY_CATCH(NULL);
}

static PyObject *PyJPClass_castEq(PyJPClass *self, PyObject *other)
static PyObject * PyJPClass_castEq(PyJPClass *self, PyObject * other)
{
PyErr_Format(PyExc_TypeError, "Invalid operation");
return NULL;
}

// Added for auditing

static PyObject *PyJPClass_convertToJava(PyJPClass *self, PyObject *other)
static PyObject * PyJPClass_convertToJava(PyJPClass *self, PyObject * other)
{
JP_PY_TRY("PyJPClass_convertToJava");
JPContext *context = PyJPModule_getContext();
Expand All @@ -883,15 +962,15 @@
JP_PY_CATCH(NULL);
}

static PyObject *PyJPClass_repr(PyJPClass *self)
static PyObject * PyJPClass_repr(PyJPClass * self)
{
JP_PY_TRY("PyJPClass_repr");
string name = ((PyTypeObject*) self)->tp_name;
return PyUnicode_FromFormat("<java class '%s'>", name.c_str());
JP_PY_CATCH(0); // GCOVR_EXCL_LINE
}

static PyObject *PyJPClass_getDoc(PyJPClass *self, void *ctxt)
static PyObject * PyJPClass_getDoc(PyJPClass *self, void *ctxt)
{
JP_PY_TRY("PyJPMethod_getDoc");
JPContext *context = PyJPModule_getContext();
Expand Down Expand Up @@ -924,7 +1003,7 @@
JP_PY_CATCH(-1);
}

PyObject* PyJPClass_customize(PyJPClass *self, PyObject *args, PyObject *kwargs)
PyObject * PyJPClass_customize(PyJPClass *self, PyObject *args, PyObject * kwargs)
{
JP_PY_TRY("PyJPClass_customize");
PyObject *name = NULL;
Expand Down
5 changes: 5 additions & 0 deletions native/python/pyjp_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ PyObject* _JMethodAnnotations = NULL;
PyObject* _JMethodCode = NULL;
PyObject* _JObjectKey = NULL;
PyObject* _JVMNotRunning = NULL;
PyObject *PyJClass_Generics = NULL;

static void PyJPModule_loadResources(PyObject* module)
{
Expand Down Expand Up @@ -139,6 +140,7 @@ extern "C"

// GCOVR_EXCL_START
// This is used exclusively during startup

void Py_SetStringWithCause(PyObject *exception,
const char *str)
{
Expand Down Expand Up @@ -700,6 +702,9 @@ PyMODINIT_FUNC PyInit__jpype()
PyJPPackage_initType(module);
PyJPChar_initType(module);

PyJClass_Generics = PyDict_New();
PyModule_AddObject(module, "_generics", PyJClass_Generics);

_PyJPModule_trace = true;
return module;
JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE
Expand Down