From fdf05eab7a139559a73c24d52c4ebb446c4a0036 Mon Sep 17 00:00:00 2001 From: Philipp Hanslovsky Date: Fri, 5 Jan 2018 09:58:50 -0500 Subject: [PATCH 1/2] Try to load class at runtime --- scyjava/__init__.py | 16 +++++- scyjava/wrap_java_class | 101 ++++++++++++++++++++++++++++++++++ scyjava/wrap_java_class.py | 109 +++++++++++++++++++++++++++++++++++++ test_scyjava.py | 20 +++++++ 4 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 scyjava/wrap_java_class create mode 100644 scyjava/wrap_java_class.py create mode 100644 test_scyjava.py diff --git a/scyjava/__init__.py b/scyjava/__init__.py index 2da32bb7..a1fdcdbb 100644 --- a/scyjava/__init__.py +++ b/scyjava/__init__.py @@ -29,7 +29,13 @@ def _init_jvm(): config, _jnius, _scijava = _init_jvm() -from jnius import autoclass as _autoclass, cast as _cast +from jnius import ( + autoclass as _autoclass, + cast as _cast, + JavaException ) + +from .wrap_java_class import _wrap_java_class + # for now, use grape directly: _HashMap = _autoclass('java.util.HashMap') @@ -54,7 +60,6 @@ def repository(url, name=None, **grape_options): repository('http://maven.imagej.net/content/groups/public', 'imagej') - def dependency(groupId, artifactId, version=None, **grape_options): m = _default_map(**grape_options) m.put('artifactId', artifactId) @@ -63,7 +68,12 @@ def dependency(groupId, artifactId, version=None, **grape_options): return _grapeIvy.grab(m) def import_class(clazz): - return _autoclass( clazz ) + loaded_class = _classLoader.loadClass(clazz) + # clz = Class(noinstance=True) + # clz.instanciate_from(create_local_ref(j_env, jc)) + # return _autoclass(clazz) + print( "CONSTRS ", loaded_class) + return _wrap_java_class(clazz, loaded_class) def list_grapes(): grapes = _grapeIvy.enumerateGrapes() diff --git a/scyjava/wrap_java_class b/scyjava/wrap_java_class new file mode 100644 index 00000000..dbd5136e --- /dev/null +++ b/scyjava/wrap_java_class @@ -0,0 +1,101 @@ +def _wrap_java_class(clsname, c): + jniname = clsname.replace('.', '/') + clz = MetaJavaClass.get_javaclass(jniname) + if clz: + return clz + classDict = {} + constructors = [] + for constructor in c.getConstructors(): + sig = '({0})V'.format( + ''.join([get_signature(x) for x in constructor.getParameterTypes()])) + constructors.append((sig, constructor.isVarArgs())) + classDict['__javaconstructor__'] = constructors + + methods = c.getMethods() + methods_name = [x.getName() for x in methods] + for index, method in enumerate(methods): + name = methods_name[index] + if name in classDict: + continue + count = methods_name.count(name) + + # only one method available + if count == 1: + static = Modifier.isStatic(method.getModifiers()) + varargs = method.isVarArgs() + sig = '({0}){1}'.format( + ''.join([get_signature(x) for x in method.getParameterTypes()]), + get_signature(method.getReturnType())) + clz = JavaStaticMethod if static else JavaMethod + classDict[name] = clz(sig, varargs=varargs) + if name != 'getClass' and bean_getter(name) and len(method.getParameterTypes()) == 0: + lowername = lower_name(name[3:]) + classDict[lowername] = (lambda n: property(lambda self: getattr(self, n)()))(name) + continue + + # multiple signatures + signatures = [] + for index, subname in enumerate(methods_name): + if subname != name: + continue + method = methods[index] + sig = '({0}){1}'.format( + ''.join([get_signature(x) for x in method.getParameterTypes()]), + get_signature(method.getReturnType())) + ''' + print 'm', name, sig, method.getModifiers() + m = method.getModifiers() + print 'Public', Modifier.isPublic(m) + print 'Private', Modifier.isPrivate(m) + print 'Protected', Modifier.isProtected(m) + print 'Static', Modifier.isStatic(m) + print 'Final', Modifier.isFinal(m) + print 'Synchronized', Modifier.isSynchronized(m) + print 'Volatile', Modifier.isVolatile(m) + print 'Transient', Modifier.isTransient(m) + print 'Native', Modifier.isNative(m) + print 'Interface', Modifier.isInterface(m) + print 'Abstract', Modifier.isAbstract(m) + print 'Strict', Modifier.isStrict(m) + ''' + signatures.append((sig, Modifier.isStatic(method.getModifiers()), method.isVarArgs())) + + classDict[name] = JavaMultipleMethod(signatures) + + def _getitem(self, index): + try: + return self.get(index) + except JavaException as e: + # initialize the subclass before getting the Class.forName + # otherwise isInstance does not know of the subclass + mock_exception_object = autoclass(e.classname)() + if Class.forName("java.lang.IndexOutOfBoundsException").isInstance(mock_exception_object): + # python for...in iteration checks for end of list by waiting for IndexError + raise IndexError() + else: + raise + + for iclass in c.getInterfaces(): + if iclass.getName() == 'java.util.List': + classDict['__getitem__'] = _getitem + classDict['__len__'] = lambda self: self.size() + break + + for field in c.getFields(): + static = Modifier.isStatic(field.getModifiers()) + sig = get_signature(field.getType()) + clz = JavaStaticField if static else JavaField + classDict[field.getName()] = clz(sig) + + classDict['__javaclass__'] = clsname.replace('.', '/') + print() + print('classDict') + print(classDict) + print(clsname) + print() + + return MetaJavaClass.__new__( + MetaJavaClass, + clsname, # .replace('.', '_'), + (JavaClass, ), + classDict) diff --git a/scyjava/wrap_java_class.py b/scyjava/wrap_java_class.py new file mode 100644 index 00000000..18829aac --- /dev/null +++ b/scyjava/wrap_java_class.py @@ -0,0 +1,109 @@ +from jnius.reflect import ( + bean_getter, lower_name, Class, + Modifier, Field, Object, Method, + Field, Constructor, get_signature, + JavaClass, MetaJavaClass, JavaMethod, + JavaStaticMethod, JavaField, JavaStaticField, + JavaMultipleMethod, find_javaclass ) + +def _wrap_java_class(clsname, c): + jniname = clsname.replace('.', '/') + clz = MetaJavaClass.get_javaclass(jniname) + if clz: + return clz + classDict = {} + constructors = [] + for constructor in c.getConstructors(): + sig = '({0})V'.format( + ''.join([get_signature(x) for x in constructor.getParameterTypes()])) + constructors.append((sig, constructor.isVarArgs())) + classDict['__javaconstructor__'] = constructors + + methods = c.getMethods() + methods_name = [x.getName() for x in methods] + for index, method in enumerate(methods): + name = methods_name[index] + if name in classDict: + continue + count = methods_name.count(name) + + # only one method available + if count == 1: + static = Modifier.isStatic(method.getModifiers()) + varargs = method.isVarArgs() + sig = '({0}){1}'.format( + ''.join([get_signature(x) for x in method.getParameterTypes()]), + get_signature(method.getReturnType())) + clz = JavaStaticMethod if static else JavaMethod + classDict[name] = clz(sig, varargs=varargs) + if name != 'getClass' and bean_getter(name) and len(method.getParameterTypes()) == 0: + lowername = lower_name(name[3:]) + classDict[lowername] = (lambda n: property(lambda self: getattr(self, n)()))(name) + continue + + # multiple signatures + signatures = [] + for index, subname in enumerate(methods_name): + if subname != name: + continue + method = methods[index] + sig = '({0}){1}'.format( + ''.join([get_signature(x) for x in method.getParameterTypes()]), + get_signature(method.getReturnType())) + ''' + print 'm', name, sig, method.getModifiers() + m = method.getModifiers() + print 'Public', Modifier.isPublic(m) + print 'Private', Modifier.isPrivate(m) + print 'Protected', Modifier.isProtected(m) + print 'Static', Modifier.isStatic(m) + print 'Final', Modifier.isFinal(m) + print 'Synchronized', Modifier.isSynchronized(m) + print 'Volatile', Modifier.isVolatile(m) + print 'Transient', Modifier.isTransient(m) + print 'Native', Modifier.isNative(m) + print 'Interface', Modifier.isInterface(m) + print 'Abstract', Modifier.isAbstract(m) + print 'Strict', Modifier.isStrict(m) + ''' + signatures.append((sig, Modifier.isStatic(method.getModifiers()), method.isVarArgs())) + + classDict[name] = JavaMultipleMethod(signatures) + + def _getitem(self, index): + try: + return self.get(index) + except JavaException as e: + # initialize the subclass before getting the Class.forName + # otherwise isInstance does not know of the subclass + mock_exception_object = autoclass(e.classname)() + if Class.forName("java.lang.IndexOutOfBoundsException").isInstance(mock_exception_object): + # python for...in iteration checks for end of list by waiting for IndexError + raise IndexError() + else: + raise + + for iclass in c.getInterfaces(): + if iclass.getName() == 'java.util.List': + classDict['__getitem__'] = _getitem + classDict['__len__'] = lambda self: self.size() + break + + for field in c.getFields(): + static = Modifier.isStatic(field.getModifiers()) + sig = get_signature(field.getType()) + clz = JavaStaticField if static else JavaField + classDict[field.getName()] = clz(sig) + + classDict['__javaclass__'] = clsname.replace('.', '/') + print() + print('classDict') + print(classDict) + print(clsname) + print() + + return MetaJavaClass.__new__( + MetaJavaClass, + clsname, # .replace('.', '_'), + (JavaClass, ), + classDict) diff --git a/test_scyjava.py b/test_scyjava.py new file mode 100644 index 00000000..91b7154b --- /dev/null +++ b/test_scyjava.py @@ -0,0 +1,20 @@ +import scyjava +from jnius.reflect import Modifier +print(Modifier) + +scyjava.dependency(groupId='net.imglib2', artifactId='imglib2', version='4.6.0') +# scyjava.dependency(groupId='net.imglib2', artifactId='imglib2-algorithm', version='0.5.0') +# scyjava.dependency(groupId='net.imglib2', artifactId='imglib2-realtransform') +scyjava.dependency(groupId='HTTPClient', artifactId='HTTPClient', version='0.3-3') + +System = scyjava.import_class('java.lang.System') +grapes = scyjava.list_grapes() + +for grape in grapes.items(): + print(grape) + + +ArrayList = scyjava._autoclass('java.util.ArrayList') +Interval = scyjava.import_class('net.imglib2.Interval') +print(Interval) +print(ArrayList) From f7be7376d4e6a359d6248e01cf5f4b682ba9930a Mon Sep 17 00:00:00 2001 From: Philipp Hanslovsky Date: Thu, 14 Jun 2018 20:18:05 -0400 Subject: [PATCH 2/2] Try to set system class loader -- not successful --- scyjava/__init__.py | 75 ++++++++++++++++++++++++++++++++++++++++++--- test_scyjava.py | 4 +++ 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/scyjava/__init__.py b/scyjava/__init__.py index a1fdcdbb..a8b22d08 100644 --- a/scyjava/__init__.py +++ b/scyjava/__init__.py @@ -1,3 +1,12 @@ +import os +import pathlib +import subprocess +import tempfile +tmp_dir = tempfile.mkdtemp() + +import jnius_config +jnius_config.add_classpath(tmp_dir) + def _get_logger(name): import logging return logging.getLogger(name) @@ -42,6 +51,54 @@ def _init_jvm(): _GrapeIvy = _autoclass('groovy.grape.GrapeIvy') _grapeIvy = _GrapeIvy() _classLoader = _autoclass('groovy.lang.GroovyClassLoader')() +_Thread = _autoclass('java.lang.Thread') +_ClassLoader = _autoclass('java.lang.ClassLoader') +get_class_loader_code=""" +import java.lang.Class; +import java.lang.ClassLoader; +import java.lang.reflect.Field; + +public class GetClassLoaderClass +{ + public static Class getClassLoaderClass() + { + return ClassLoader.class; + } + + public static void setSystemClassLoader( ClassLoader classLoader ) throws IllegalAccessException, NoSuchFieldException + { + Field scl = getClassLoaderClass().getDeclaredField( "scl" ); + scl.setAccessible( true ); + scl.set( null, classLoader ); + } +} +""" +fp = pathlib.Path( tmp_dir ) / 'GetClassLoaderClass.java' +print( tmp_dir ) +with open( fp, 'w' ) as f: + f.write( get_class_loader_code ) + + +javac = pathlib.Path( os.environ[ 'JAVA_HOME' ] ) / 'bin' / 'javac' +proc = subprocess.run( + [ javac, '-cp', jnius_config.split_char.join( jnius_config.get_classpath() ), fp ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) +if proc.returncode != 0: + print("Failed!") + print ( proc.stderr ) + +_GetClassLoaderClass = _autoclass('GetClassLoaderClass') +_GetClassLoaderClass.setSystemClassLoader( _classLoader ); +print("System classloader", _ClassLoader.getSystemClassLoader().getClass().getName()) + +# try: +# _scl = _GetClassLoaderClass.getClassLoaderClass().getDeclaredField('scl') +# print(_scl) +# _scl.setAccessible(True) +# _scl.set(None, _classLoader) +# except JavaException as e: +# print(e) def _default_map(**extra_options): m = _HashMap() @@ -68,12 +125,22 @@ def dependency(groupId, artifactId, version=None, **grape_options): return _grapeIvy.grab(m) def import_class(clazz): - loaded_class = _classLoader.loadClass(clazz) + try: + print("SETTING CLASSLOADER", _classLoader) + # _Thread.currentThread().setContextClassLoader(_cast('java.lang.ClassLoader',_classLoader)) + _Thread.currentThread().setContextClassLoader(_classLoader) + except JavaException as e: + print( "e.classname -- {}".format( e.classname ) ) + print( "e.innermessage -- {}".format( e.innermessage ) ) + # for st in e.stacktrace: + # print( st ) + # loaded_class = _classLoader.loadClass(clazz) # clz = Class(noinstance=True) # clz.instanciate_from(create_local_ref(j_env, jc)) - # return _autoclass(clazz) - print( "CONSTRS ", loaded_class) - return _wrap_java_class(clazz, loaded_class) + print("classloader", _Thread.currentThread().getContextClassLoader().getClass().getName()) + return _autoclass(clazz) + # print( "CONSTRS ", loaded_class) + # return _wrap_java_class(clazz, loaded_class) def list_grapes(): grapes = _grapeIvy.enumerateGrapes() diff --git a/test_scyjava.py b/test_scyjava.py index 91b7154b..6e624c88 100644 --- a/test_scyjava.py +++ b/test_scyjava.py @@ -1,3 +1,7 @@ +import jnius_config +jnius_config.add_classpath('/home/phil/git/scyjava2/groovy-3.0.0-alpha-2.jar') +jnius_config.add_classpath('/home/phil/git/scyjava2/ivy-2.5.0-rc1.jar') + import scyjava from jnius.reflect import Modifier print(Modifier)