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

Improvement: autoclass() when class not in boot classpath #534

Open
cmacdonald opened this issue May 6, 2020 · 5 comments
Open

Improvement: autoclass() when class not in boot classpath #534

cmacdonald opened this issue May 6, 2020 · 5 comments

Comments

@cmacdonald
Copy link
Contributor

I have a slight problem: I'm trying to instantiate a class that is have a java.lang.Class reference to. This was provided by a ClassLoader accessing a classpath different from "boot time". Traceback attached below.

However, JNI's FindClass() only provides jclass for classes in the boot classpath, i.e. using ClassLoader.getSystemClassLoader().

I dont think we need FindClass(), as we already have access to the Class object. We just need to instantiate it from that Class object.

  1. A possible workaround is adding an optional parameter to autoclass() providing the Class object directly, i.e.
other_class = bla._class.getClassLoader().loadClass("my.other.Class")
other_classInstance = autoclass(None, cls=other_class)()
  1. Or being able to pass a ClassLoader to autoclass? Dont think this would work in the generic case.

  2. Or detecting when a Class object is being instantiated into Python, add that to jclass_register

Traceback.

Traceback (most recent call last):
  File "tests/test_rewrite.py", line 97, in test_rm3
    qe = pt.rewrite.RM3(indexref)
  File "/Users/craigm/git/Pyterrier/pyterrier/rewrite.py", line 139, in __init__
    rm = pt.ApplicationSetup.getClass("org.terrier.querying.RM3").newInstance()
  File "jnius/jnius_export_class.pxi", line 857, in jnius.JavaMethod.__call__
  File "jnius/jnius_export_class.pxi", line 939, in jnius.JavaMethod.call_method
  File "jnius/jnius_conversion.pxi", line 212, in jnius.convert_jobject_to_python
  File "/Users/craigm/anaconda3/envs/pyterrier/lib/python3.6/site-packages/jnius/reflect.py", line 229, in autoclass
    c = find_javaclass(clsname)
  File "jnius/jnius_export_func.pxi", line 26, in jnius.find_javaclass
  File "jnius/jnius_jvm_dlopen.pxi", line 91, in jnius.create_jnienv
jnius.JavaException: JVM exception occurred: org/terrier/querying/RM3 java.lang.NoClassDefFoundError
@tshirtman
Copy link
Member

I think you mean
"a class that all i have is have a java.lang.Class reference" (emphasis on missing words).

So, you'd want to do everything autoclass does, but using a class reference instead of the fqn of the class. Maybe autoclass could be refactored to do the name lookup part (https://github.com/kivy/pyjnius/blob/master/jnius/reflect.py#L220-L233), and delegate the reflection part to another function, that you could call with your class object directly if you wish so?

@cmacdonald
Copy link
Contributor Author

"I'm trying to instantiate a class that I have a java.lang.Class reference to."

Yes, your proposal may work - a variant of (1). Will give a try in due course. Thanks.

@tshirtman
Copy link
Member

Cool, autoclass is quite big, so splitting it a bit won't hurt.

@cmacdonald
Copy link
Contributor Author

I have committed my WIP to https://github.com/cmacdonald/pyjnius/tree/reflect_class_issue534

This:

  • splits autoclass() into autoclass() and reflect_class(). The former is called with a string, the latter using a Class instance.
  • convert_jobject_to_python() uses reflect_class() instead of autoclass(). This doesnt work, exhibiting a RecursionError. I cant see why, feedback appreciated. It may have something to do with the addition of getClass = JavaMethod('()Ljava/lang/Class;') to the Object impl.

For cases where the returned object is not part of the boot classpath, convert_jobject_to_python() will have to be altered to get the actual Class object, rather than JNI's FindClass. I /think/ that this could be obtained from the jobject itself - i.e. instantiate it as a Object, call getClass() then reinstantiate it using that object.

@tshirtman
Copy link
Member

took the liberty to open #539 from it to review more easily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants