Ответ 1
Решение сложное, но все объясняется здесь.
Как добавить JDBC-драйверы во время выполнения в Jython? Использование CLASSPATH работает, но использование sys.path не работает с zxJDBC, даже если класс импортирован в порядке и может быть обработан из приглашения интерпретатора Jython.
Почему это работает:
$ CLASSPATH=/tmp/jtds\-1.2.5.jar ./jython
*sys-package-mgr*: processing new jar, '/private/tmp/jtds-1.2.5.jar'
Jython 2.5.1 (Release_2_5_1:6813, Sep 26 2009, 13:47:54)
[Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_20
Type "help", "copyright", "credits" or "license" for more information.
>>> from java.lang import Class
>>> Class.forName('net.sourceforge.jtds.jdbc.Driver')
<type 'net.sourceforge.jtds.jdbc.Driver'>
Но это не так?
$ ./jython
Jython 2.5.1 (Release_2_5_1:6813, Sep 26 2009, 13:47:54)
[Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_20
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path.extend(['/tmp/jtds-1.2.5.jar'])
>>> from java.lang import Class
>>> Class.forName('net.sourceforge.jtds.jdbc.Driver')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
java.lang.ClassNotFoundException: java.lang.ClassNotFoundException: net.sourceforge.jtds.jdbc.Driver
>>> sys.path
['', '/home/me/pkg/jython2.5.1/Lib/site-packages/distribute-0.6.13-py2.5.egg', '/home/me/pkg/jython2.5.1/Lib', '__classpath__', '__pyclasspath__/', '/home/me/pkg/jython2.5.1/Lib/site-packages', '/home/me/pkg/jython2.5.1/Lib/site-packages/setuptools-0.6c11-py2.5.egg-info', '/tmp/jtds-1.2.5.jar']
>>> import net.sourceforge.jtds.jdbc.Driver as Driver
>>> drv = Driver()
>>> drv
jTDS 1.2.5
Имеет ли это отношение к загрузчику классов?
Решение сложное, но все объясняется здесь.
Похоже, что даже обновленная ссылка больше не работает (по крайней мере, с jython-2.5.3b3).
Здесь рабочая версия:
def importJar(jarFile):
'''
import a jar at runtime (needed for JDBC [Class.forName])
adapted from http://forum.java.sun.com/thread.jspa?threadID=300557
Author: SG Langer Jan 2007 translated the above Java to Jython
Author: [email protected] simplified and updated for jython-2.5.3b3
>>> importJar('jars/jtds-1.2.5.jar')
>>> import java.lang.Class
>>> java.lang.Class.forName('net.sourceforge.jtds.jdbc.Driver')
<type 'net.sourceforge.jtds.jdbc.Driver'>
'''
from java.net import URL, URLClassLoader
from java.lang import ClassLoader
from java.io import File
m = URLClassLoader.getDeclaredMethod("addURL", [URL])
m.accessible = 1
m.invoke(ClassLoader.getSystemClassLoader(), [File(jarFile).toURL()])
if __name__ == '__main__':
import doctest
doctest.testmod()
Я сохраняю этот Gist, обновленный моей производственной версией.