|
From: John G. <jgo...@co...> - 2001-11-07 20:22:09
|
Hi,
I am accessing some python code from Java. When I try to use
interp.get() (where inter is a PythonInterpreter object), I get an
error saying it can't convert my object to the appropriate Java one.
However!
My object is a python subclass of the Java object I want it to be.
IE, in Java I'm saying:
ListBO newobj = (ListBO) interp.get("cl", this.getClass());
("this" is a ListBO instance)
In Python, cl is a variable that holds an instance of a ListBOFoo
class, which is defined:
class ListBOFoo(quovix.business.util.ListBO):
...
The code seems to work (quovix is imported properly, etc). It's just
that calling "get" on it returns the conversion problem.
I'm not sure where to go to fix this. Ideas?
-- John
--
John Goerzen <jgo...@co...> GPG: 0x8A1D9A1F www.complete.org
|
|
From: John G. <jgo...@co...> - 2001-11-07 20:51:28
|
And as an additional data point:
If I request an object of type java.lang.Object from get(), get()
works. What's more, newobj.getClass().getSuperclass().getName()
returns quovix.business.util.ListBO! However, casting newobj from
Object to ListBO fails with a java.lang.ClassCastException on
ListBOFoo$ListBOFoo$0! I'm rather mystified now.
John Goerzen <jgo...@co...> writes:
> Hi,
>
> I am accessing some python code from Java. When I try to use
> interp.get() (where inter is a PythonInterpreter object), I get an
> error saying it can't convert my object to the appropriate Java one.
>
> However!
>
> My object is a python subclass of the Java object I want it to be.
>
> IE, in Java I'm saying:
>
> ListBO newobj = (ListBO) interp.get("cl", this.getClass());
>
> ("this" is a ListBO instance)
>
> In Python, cl is a variable that holds an instance of a ListBOFoo
> class, which is defined:
>
> class ListBOFoo(quovix.business.util.ListBO):
> ...
>
> The code seems to work (quovix is imported properly, etc). It's just
> that calling "get" on it returns the conversion problem.
>
> I'm not sure where to go to fix this. Ideas?
>
> -- John
>
> --
> John Goerzen <jgo...@co...> GPG: 0x8A1D9A1F www.complete.org
>
> _______________________________________________
> Jython-users mailing list
> Jyt...@li...
> https://lists.sourceforge.net/lists/listinfo/jython-users
--
John Goerzen <jgo...@co...> GPG: 0x8A1D9A1F www.complete.org
|
|
From: Jeff E. <je...@ad...> - 2001-11-08 16:23:52
|
This seems a little more familiar since you are loading the java
class with a custom class loader. When this has worked for me
before, I have always used the system default class loader.
Try finding the classloader for the superclass, as jython sees it.
Something like this:
interp.exec("super=mod.ListBO");
Object pySuperClass = interp.get("super",Object.class);
System.out.println(pySuperClass);
System.out.println(
((Class)pySuperClass).getClassLoader().getClass().getName());
I suspect that the jython super is not loaded by the same classloader and
that is the root of your problems. I'm not sure if there is a way to
tell the jython interpreter to use your custom classloader without
having to rewrite your scripts. Samuele Pedroni would probably be able
to answer that right off.
You might be able to set your custom classloader in the interpreter's
name space and rewrite your scripts to use that. Something like this:
In Java:
interp.set("classloader",this.getClass().getClassLoader());
In Python:
# Replace normal Python import syntax with this:
ListBO=classloader.loadClass("quovix.business.util.ListBO")
class ListBOFoo(ListBO): # The rest as usual
It certainly would be preferable to hook into the jython import mechanism
instead. I don't know how to do that.
John Goerzen wrote:
> OK. I did:
>
> System.out.println(this.getClass().getClassLoader().getClass().getName());
> System.out.println(newobj.getClass().getClassLoader().getClass().getName());
>
> Resulting in:
>
> com.lutris.classloader.MultiClassLoader
> org.python.core.BytecodeLoader1
>
> MultiClassLoader is a subclass of java.lang.ClassLoader adding in
> functionality such as loading classes from URLs, ZIPs, etc. (This is
> an Enhydra servlet).
>
> Interestingly, this is JDK 2 but it's using Jython's JDK 1
> BytecodeLoader.
>
> Let me show you exactly what I'm trying to do:
>
> In Java: (before adding the printlns and other debug stuff)
>
> PythonInterpreter interp = new PythonInterpreter();
> interp.exec("mod = __import__('" + brob + "')");
> interp.exec("cl = mod." + brob + "()");
> Object newobj = interp.get("cl", Object.class);
> return (ListBO) newobj;
>
> In this case, 'brob' is ListBOFoo, and it's loading this Python code:
>
> from quovix.business.util import *
>
> class ListBOFoo(ListBO):
> def getDescription(self):
> desc = ListBO.getDescription(self) # Superclass call
> return "Foo_" + desc
>
> Very simple stuff. I have it working with jythonc but I'm trying to
> eliminate jythonc from the picture so it can be loaded 100%
> dynamically.
>
> Thanks for your assistance!
>
> -- John
>
>
> Jeff Emanuel <je...@ad...> writes:
>
>
>>The java class Class has a method to return its ClassLoader.
>>You can do something like this:
>>
>> System.out.println(this.getClass().getClassLoader());
>> System.out.println(newobj.getClass().getClassLoader());
>>
>>If they are different, the classes are in effect not equal.
>>I'm not sure why that would be or how to work around it. I've
>>done things as you are trying and it worked. If we know
>>what the classloaders are, perhaps we can discover why they
>>are different, or what action to take.
>>
>>You can also try newobj.getClass().isAssignableFrom(this.getClass())
>>
>>That is likely to be false since you know you can't do the cast.
>>
>>
>>
>>John Goerzen wrote:
>>
>>
>>>Jeff Emanuel <je...@ad...> writes:
>>>
>>>
>>>>It is likely that your ListBO class was loaded by two different class
>>>>loaders. Try printing out the classloaders for your Java this instance
>>>>and your newobj. Even if the classes are the same, if they were loaded
>>>>by different loaders, then they really aren't equal.
>>>>
>>>>
>>>OK this is unfamiliar territory for me. I don't know what a class
>>>
>>>loader is or how to print it. If the loaders are different, how would
>>>I go about resolving the problem? One is the regular static stuff
>>>loaded as usual with classes generated by javac; the other, Python.
>>>Ideas?
>>>Thanks!
>>>
>>>-- John
>>>
>>
>>
>
|
|
From: John G. <jgo...@co...> - 2001-11-08 17:17:53
|
Jeff Emanuel <je...@ad...> writes:
> This seems a little more familiar since you are loading the java
> class with a custom class loader. When this has worked for me
> before, I have always used the system default class loader.
Oddly enough, I didn't even realize that class loaders even existed
until your message yesterday, and certainly not that a non-default
loader was already being used. Alas, I fear that I have no control
over what loader is being used at the moment.
> Try finding the classloader for the superclass, as jython sees it.
> Something like this:
I tried this, just from Python at the top of the module:
print "Superclass loader: " + ListBO.getClassLoader().getClass().getName()
Prior to your suggested hack below, this printed out
org.python.core.SyspathJavaLoader.
> I suspect that the jython super is not loaded by the same classloader and
This is true...
> that is the root of your problems. I'm not sure if there is a way to
... but it doesn't seem to be the root of my problems.
> You might be able to set your custom classloader in the interpreter's
> name space and rewrite your scripts to use that. Something like this:
[ snip ]
I had to hack it to get the variable into the module, but I got it to
do that.
> ListBO=classloader.loadClass("quovix.business.util.ListBO")
Now, the above print displays com.lutris.classloader.MultiClassLoader
-- the same as for my code in static Java. But -- I still get the
same ClassCastException in Java as before -- probably because the
ListBOFoo object is still being loaded by Python's loader (ByteLoader1).
-- John
|
|
From: Jeff E. <je...@ad...> - 2001-11-08 21:40:52
|
I tried replicating what you are doing with a little stand-alone
java program, but I can't seem to get the conversion to fail.
Here's another hack you could try. Instead of passing the
classloader to the script, pass the superclass.
Java:
interp.set("ListBO", this.getClass());
Python:
# Omit import, ListBO is in namespace from above.
class ListBOFoo(ListBO): # etc...
John Goerzen wrote:
> Jeff Emanuel <je...@ad...> writes:
>
>
>>This seems a little more familiar since you are loading the java
>>class with a custom class loader. When this has worked for me
>>before, I have always used the system default class loader.
>>
>
> Oddly enough, I didn't even realize that class loaders even existed
> until your message yesterday, and certainly not that a non-default
> loader was already being used. Alas, I fear that I have no control
> over what loader is being used at the moment.
>
>
>>Try finding the classloader for the superclass, as jython sees it.
>>Something like this:
>>
>
> I tried this, just from Python at the top of the module:
>
> print "Superclass loader: " + ListBO.getClassLoader().getClass().getName()
>
> Prior to your suggested hack below, this printed out
> org.python.core.SyspathJavaLoader.
>
>
>>I suspect that the jython super is not loaded by the same classloader and
>>
>
> This is true...
>
>
>>that is the root of your problems. I'm not sure if there is a way to
>>
>
> ... but it doesn't seem to be the root of my problems.
>
>
>>You might be able to set your custom classloader in the interpreter's
>>name space and rewrite your scripts to use that. Something like this:
>>
>
> [ snip ]
>
> I had to hack it to get the variable into the module, but I got it to
> do that.
>
>
>> ListBO=classloader.loadClass("quovix.business.util.ListBO")
>>
>
> Now, the above print displays com.lutris.classloader.MultiClassLoader
> -- the same as for my code in static Java. But -- I still get the
> same ClassCastException in Java as before -- probably because the
> ListBOFoo object is still being loaded by Python's loader (ByteLoader1).
>
>
> -- John
>
> _______________________________________________
> Jython-users mailing list
> Jyt...@li...
> https://lists.sourceforge.net/lists/listinfo/jython-users
>
|
|
From: John G. <jgo...@co...> - 2001-11-08 21:54:32
|
Tried, still didn't help..
Of note: when I print the loader of ListBO from within Python, it says
com.lutris.classloader.MultiClassLoader. When I print the loader of
the superclass of ListBOFoo from within Java (that superclass is the
same ListBO), it says sun.misc.Launcher$AppClassLoader! More and more
puzzling. I feel that I'm SO CLOSE!
Also: I'm now pulling the *class* from python to Java, not an instance of it.
That seems to help, maybe...
-- John
Jeff Emanuel <je...@ad...> writes:
> I tried replicating what you are doing with a little stand-alone
> java program, but I can't seem to get the conversion to fail.
>
> Here's another hack you could try. Instead of passing the
> classloader to the script, pass the superclass.
>
>
> Java:I p
> interp.set("ListBO", this.getClass());
>
> Python:
>
> # Omit import, ListBO is in namespace from above.
>
> class ListBOFoo(ListBO): # etc...
>
>
> John Goerzen wrote:
>
> > Jeff Emanuel <je...@ad...> writes:
> >
>
> >>This seems a little more familiar since you are loading the java
> >>class with a custom class loader. When this has worked for me
> >>before, I have always used the system default class loader.
> >>
> > Oddly enough, I didn't even realize that class loaders even existed
>
> > until your message yesterday, and certainly not that a non-default
> > loader was already being used. Alas, I fear that I have no control
> > over what loader is being used at the moment.
> >
>
> >>Try finding the classloader for the superclass, as jython sees it.
> >>Something like this:
> >>
> > I tried this, just from Python at the top of the module:
>
> > print "Superclass loader: " +
> > ListBO.getClassLoader().getClass().getName()
>
> > Prior to your suggested hack below, this printed out
>
> > org.python.core.SyspathJavaLoader.
> >
>
> >>I suspect that the jython super is not loaded by the same classloader and
> >>
> > This is true...
>
> >
>
> >>that is the root of your problems. I'm not sure if there is a way to
> >>
> > ... but it doesn't seem to be the root of my problems.
>
> >
>
> >>You might be able to set your custom classloader in the interpreter's
> >>name space and rewrite your scripts to use that. Something like this:
> >>
> > [ snip ]
>
> > I had to hack it to get the variable into the module, but I got it to
>
> > do that.
> >
>
> >> ListBO=classloader.loadClass("quovix.business.util.ListBO")
> >>
> > Now, the above print displays com.lutris.classloader.MultiClassLoader
>
> > -- the same as for my code in static Java. But -- I still get the
> > same ClassCastException in Java as before -- probably because the
> > ListBOFoo object is still being loaded by Python's loader (ByteLoader1).
> > -- John
>
> > _______________________________________________
>
> > Jython-users mailing list
> > Jyt...@li...
> > https://lists.sourceforge.net/lists/listinfo/jython-users
> >
>
>
>
--
John Goerzen <jgo...@co...> GPG: 0x8A1D9A1F www.complete.org
|
|
From: <bc...@wo...> - 2001-11-08 22:28:53
|
[John Goerzen] >Tried, still didn't help.. > >Of note: when I print the loader of ListBO from within Python, it says >com.lutris.classloader.MultiClassLoader. When I print the loader of >the superclass of ListBOFoo from within Java (that superclass is the >same ListBO), it says sun.misc.Launcher$AppClassLoader! More and more >puzzling. That is because the BytecodeLoaders happens to search the SyspathJavaLoader before searching the referent class loaders. It's a bug. > I feel that I'm SO CLOSE! Try calling Py.getSystemState().setClassLoader(this.getClass().getClassLoader()); It will effectively disable attempts to import java classes from sys.path and instead only try to load them from the MultiClassLoader. >Also: I'm now pulling the *class* from python to Java, not an instance of it. >That seems to help, maybe... Nah. regards, finn |
|
From: John G. <jgo...@co...> - 2001-11-09 14:16:11
|
bc...@wo... (Finn Bock) writes: > That is because the BytecodeLoaders happens to search the > SyspathJavaLoader before searching the referent class loaders. It's a > bug. [snip] > Try calling > > Py.getSystemState().setClassLoader(this.getClass().getClassLoader()); > > It will effectively disable attempts to import java classes from > sys.path and instead only try to load them from the MultiClassLoader. Hmm. It didn't work. (I tried setting it both before and after instantiating my PythonInterpreter object in Java; didn't work either way). Interesting data points: * In Python, I printed: print Py.getSystemState().getClassLoader().getClass().getName() result: com.lutris.classloader.MultiClassLoader which is correct. * Java still claims that the loader for the base class of my Python class is sun.misc.Launcher$AppClassLoader. I at least have it -- through MANY hacks -- showing the correct loader. * I just noticed that, somewhere along the line, Java shows the superclass of my ListBOFoo as being PyFunctionTable. Eep! I don't quite know where that changed from ListBO. Somewhere in my testing I guess. Sigh. Also: Is it possible to tell Jython where to create the .class files that it generates on the fly? -- John > > >Also: I'm now pulling the *class* from python to Java, not an instance of it. > >That seems to help, maybe... > > Nah. > > regards, > finn -- John Goerzen <jgo...@co...> GPG: 0x8A1D9A1F www.complete.org |
|
From: <bc...@wo...> - 2001-11-09 14:35:38
|
[John Goerzen] >Is it possible to tell Jython where to create the .class files that it >generates on the fly? Try the option python.options.proxyDebugDirectory=d:\\temp\\myproxies Added to your ~/.jython file or the registry file or specified in the properties to the PythonInterpreter.initialize(...) method or specified as system properties on the commandline when starting java. Which to use depends on your environment. When embedding, I suggest the initialize(..) argument way, as in >http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jython/jython/org/python/util/PyServlet.java?annotate=1.11#73 regards, finn |
|
From: John G. <jgo...@co...> - 2001-11-09 14:44:53
|
bc...@wo... (Finn Bock) writes:
> Try calling
>
> Py.getSystemState().setClassLoader(this.getClass().getClassLoader());
>
> It will effectively disable attempts to import java classes from
> sys.path and instead only try to load them from the MultiClassLoader.
Almost there!!
(Thanks to you and Jeff Emanuel for all your help).
I have thinks WORKING! but only if I use Jeff's trick of:
interp.set("ListBO", this.getClass()). If I try to
"import quovix" or "from quovix.business.util import ListBO" from
Python after setting the classloader per your instructions, Python
gives an "ImportError: no module named quovix". Oddly, it can import
things like java.util.Date. I'm unsure why it can't find my own
classes -- obviously the MultiClassLoader can because all this stuff
is being called from ListBO itself. So it's a bit strange. But I can
work around that certainly.
Also I'm curious why this works:
interp.exec("import ListBOFoo");
Class pclass = (Class) interp.eval("ListBOFoo.ListBOFoo").__tojava__(Class.class);
But this doesn't:
interp.exec("mod = __import__('ListBOFoo')");
Class pclass = (Class) interp.eval("mod.ListBOFoo").__tojava__(Class.class);
The second dies on the eval claiming that there is no such symbol in
Python. Not a biggie but a weird thing anyway.
Thanks for all your help!
-- John
|
|
From: <bc...@wo...> - 2001-11-09 15:11:19
|
[John Goerzen]
>bc...@wo... (Finn Bock) writes:
>
>> Try calling
>>
>> Py.getSystemState().setClassLoader(this.getClass().getClassLoader());
>>
>> It will effectively disable attempts to import java classes from
>> sys.path and instead only try to load them from the MultiClassLoader.
>
>Almost there!!
>
>(Thanks to you and Jeff Emanuel for all your help).
>
>I have thinks WORKING! but only if I use Jeff's trick of:
>interp.set("ListBO", this.getClass()). If I try to
>"import quovix" or "from quovix.business.util import ListBO" from
>Python after setting the classloader per your instructions, Python
>gives an "ImportError: no module named quovix".
That is because java have no solid way of querying a classloader about
which java packages it can serve.
To load a java package from from sys.path, we have to do a directory
listning to discover the available java directories. When disabling java
loading from sys.path (by setting the classloader) we also disable this
method of java package discovery.
Take another look at the PyServlet example:
> http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jython/jython/org/python/util/PyServlet.java?annotate=1.11#73
and notice the calls to sys.add_package(..) and sys.add_classdir(..).
These calls will give some hints to the package manager that one of the
custom classloaders in the environment is able to serve additional java
packages.
It is important to know that the sys.add_XXX() methods does not enable
loading of java classes from these sources. The methods only allow
loading of java packages.
>Oddly, it can import things like java.util.Date.
Not odd at all. Jython scans the rt.jar file for all java classes and
build a list of available java package from this list.
>I'm unsure why it can't find my own
>classes -- obviously the MultiClassLoader can because all this stuff
>is being called from ListBO itself. So it's a bit strange. But I can
>work around that certainly.
>
>Also I'm curious why this works:
>
>interp.exec("import ListBOFoo");
>Class pclass = (Class) interp.eval("ListBOFoo.ListBOFoo").__tojava__(Class.class);
>
>But this doesn't:
>
>interp.exec("mod = __import__('ListBOFoo')");
>Class pclass = (Class) interp.eval("mod.ListBOFoo").__tojava__(Class.class);
>
>The second dies on the eval claiming that there is no such symbol in
>Python. Not a biggie but a weird thing anyway.
Which symbol? Do you have a stacktrace?
>Thanks for all your help!
You's welcome.
regards,
finn
|
|
From: Samuele P. <ped...@bl...> - 2001-11-10 17:06:58
|
> [John Goerzen] > > >Tried, still didn't help.. > > > >Of note: when I print the loader of ListBO from within Python, it says > >com.lutris.classloader.MultiClassLoader. When I print the loader of > >the superclass of ListBOFoo from within Java (that superclass is the > >same ListBO), it says sun.misc.Launcher$AppClassLoader! More and more > >puzzling. > > That is because the BytecodeLoaders happens to search the > SyspathJavaLoader before searching the referent class loaders. It's a > bug. No, I would'nt say it is a bug. The problem is that the guilty class is loadable both by MultiClassLoader and probably from classpath. In those cases it is better if the user dis-entangle that, because , yes we can with good-will, change the order, but the only safe solution is to avoid that at all. Without knowing the specific up to the details, I will not change the actual order. regards. |
|
From: <bc...@wo...> - 2001-11-08 19:10:19
|
[John Goerzen]
>And as an additional data point:
>
>If I request an object of type java.lang.Object from get(), get()
>works. What's more, newobj.getClass().getSuperclass().getName()
>returns quovix.business.util.ListBO! However, casting newobj from
>Object to ListBO fails with a java.lang.ClassCastException on
>ListBOFoo$ListBOFoo$0! I'm rather mystified now.
The return value from PythonInterpreter.get() is always a PyObject
instance. You need to explicit convert the returned PyObject instance to
an instance of your java class like this:
Object tmp = interp.get("cl").__tojava__(ListBO.class);
if (tmp != Py.NoConversion) {
ListBO newobj = (ListBO) tmp;
}
If the "cl" variable can't be converted to a ListBO, the constant value
of Py.NoConversion is returned.
regards,
finn
|
|
From: John G. <jgo...@co...> - 2001-11-08 19:19:28
|
bc...@wo... (Finn Bock) writes:
> The return value from PythonInterpreter.get() is always a PyObject
> instance. You need to explicit convert the returned PyObject instance to
> an instance of your java class like this:
There are two PythonInterpeter.get() methods; one of which takes two
parameters (the second the Java class to convert to) and returns a
java.lang.Object. It is my understanding that this is equivolent to
the code you showed. I was using this one, and got the mentioned error.
>
> Object tmp = interp.get("cl").__tojava__(ListBO.class);
> if (tmp != Py.NoConversion) {
> ListBO newobj = (ListBO) tmp;
> }
>
> If the "cl" variable can't be converted to a ListBO, the constant value
> of Py.NoConversion is returned.
>
> regards,
> finn
--
John Goerzen <jgo...@co...> GPG: 0x8A1D9A1F www.complete.org
|