def find_spec(self, name, path, target=None): # If jvm is not started then we just check against the TLDs if not _jpype.isStarted(): base = name.partition('.')[0] if not base in _JDOMAINS: return None raise ImportError( "Attempt to create Java package '%s' without jvm" % name) # Check for aliases if name in _JDOMAINS: jname = _JDOMAINS[name] if not _jpype.isPackage(jname): raise ImportError( "Java package '%s' not found, requested by alias '%s'" % (jname, name)) ms = _ModuleSpec(name, self) ms._jname = jname return ms # Check if it is a TLD parts = name.rpartition('.') # Use the parent module to simplify name mangling if not parts[1] and _jpype.isPackage(parts[2]): ms = _ModuleSpec(name, self) ms._jname = jname return ms if not parts[1] and not _jpype.isPackage(parts[0]): return None base = sys.modules.get(parts[0], None) if not base or not isinstance(base, _jpype._JPackage): return None # Support for external modules in java tree name = unwrap(name) for customizer in _CUSTOMIZERS: if customizer.canCustomize(name): return customizer.getSpec(name) # Using isPackage eliminates need for registering tlds if not hasattr(base, parts[2]): # If the base is a Java package and it wasn't found in the # package using getAttr, then we need to emit an error # so we produce a meaningful diagnositic. try: # Use forname because it give better diagnostics cls = _jpype.JClass("java.lang.Class").forName(name) return _jpype.JClass(cls) # Not found is acceptable except Exception as ex: raise ImportError("Failed to import '%s'" % name) from ex # Import the java module return _ModuleSpec(name, self)
def __init__(self, dispatch): cl = _jpype.JClass( 'org.jpype.classloader.JPypeClassLoader').getInstance() self._encoder = _jpype.JClass( cl.loadClass('org.jpype.pickle.Encoder'))() self._builder = JUnserializer() self._dispatch = dispatch # Extension dispatch table holds reduce method self._call = self.reduce
def stacktrace(self): """ Get a string listing the stack frame. Returns: A string with the classic Java ``printStackTrace`` result. """ StringWriter = _jpype.JClass("java.io.StringWriter") PrintWriter = _jpype.JClass("java.io.PrintWriter") sw = StringWriter() pw = PrintWriter(sw) self.printStackTrace(pw) pw.flush() r = sw.toString() sw.close() return r
def _JExceptionClassFactory(tp): if isinstance(tp, str): return _jpype.JClass(tp) if isinstance(tp, _jpype.JClass): return tp raise TypeError( "JException requires a string or java throwable type, got %s." % tp)
def __init__(self, dispatch): self._encoder = _jpype.JClass('org.jpype.pickle.Encoder')() self._builder = JUnserializer() self._dispatch = dispatch # Extension dispatch table holds reduce method self._call = self.reduce
def _convertInterfaces(intf): """ (internal) Convert a list of interface names into a list of interfaces suitable for a proxy. """ # Flatten the list intflist = [] for item in intf: if isinstance(item, str) or not hasattr(item, '__iter__'): intflist.append(item) else: intflist.extend(item) # Look up the classes if given as a string actualIntf = set() for item in intflist: if isinstance(item, str): actualIntf.add(_jpype.JClass(item)) else: actualIntf.add(item) # Check that all are interfaces if not actualIntf: raise TypeError("At least one Java interface must be specified") for cls in actualIntf: # If it isn't a JClass, then it cannot be a Java interface if not isinstance(cls, _jpype.JClass): raise TypeError("'%s' is not a Java interface" % type(cls).__name__) # Java concrete and abstract classes cannot be proxied if not issubclass(cls, _jpype.JInterface): raise TypeError("'%s' is not a Java interface" % cls.__name__) return tuple(actualIntf)
def registerClassImplementation(self, classname, proto): """ (internal) Add an implementation for a class Use @JImplementationFor(cls) to access this. """ self.implementations.append(proto) # If we have already created a class, apply it retroactively. if self.instantiated: _applyCustomizerPost(_jpype.JClass(classname), proto)
def _getJavaClass(javaname): """ This produces diagnostics on failing to find a Java class """ global _java_lang_Class global _java_lang_NoClassDefFoundError global _java_lang_ClassNotFoundException global _java_lang_UnsupportedClassVersionError if not _java_lang_Class: _java_lang_Class = _jpype.JClass("java.lang.Class") _java_lang_ClassNotFoundException = _jpype.JClass( "java.lang.ClassNotFoundException") _java_lang_NoClassDefFoundError = _jpype.JClass( "java.lang.NoClassDefFoundError") _java_lang_UnsupportedClassVersionError = _jpype.JClass( "java.lang.UnsupportedClassVersionError") err = None try: # Use forname because it give better diagnostics cls = _java_lang_Class.forName(javaname) return _jpype.JClass(cls) # Not found is acceptable except _java_lang_ClassNotFoundException: p = javaname.rpartition('.') err = "'%s' not found in '%s'" % (p[2], p[0]) # Missing dependency except _java_lang_NoClassDefFoundError as ex: missing = str(ex).replace('/', '.') err = "Unable to import '%s' due to missing dependency '%s'" % ( javaname, missing) # Wrong Java version except _java_lang_UnsupportedClassVersionError as ex: err = "Unable to import '%s' due to incorrect Java version" % ( javaname) # Otherwise!? except Exception as ex: err = "Unable to import '%s' due to unexpected exception, '%s'" % ( javaname, ex) raise ImportError(err)
def addClassPath(path1): """ Add a path to the Java class path Classpath items can be a java, a directory, or a glob pattern. Relative paths are relative to the caller location. Arguments: path(str): """ # We are deferring these imports until here as we only need them # if this function is used. from pathlib import Path import inspect global _CLASSPATHS # Convert to an absolute path. Note that # relative paths will be resolve based on the location # of the caller rather than the JPype directory. path1 = Path(path1) if not path1.is_absolute(): path2 = Path(inspect.stack(1)[1].filename).parent.resolve() path1 = path2.joinpath(path1) # If the JVM is already started then we will have to load the paths # immediately into the DynamicClassLoader if _jpype.isStarted(): Paths = _jpype.JClass('java.nio.file.Paths') JContext = _jpype.JClass('org.jpype.JPypeContext') classLoader = JContext.getInstance().getClassLoader() if path1.name == "*": paths = list(path1.parent.glob("*.jar")) if len(paths) == 0: return for path in paths: classLoader.addFile(Paths.get(str(path))) else: classLoader.addFile(Paths.get(str(path1))) _CLASSPATHS.append(path1)
def _JClassPost(res, *args): # Post customizers _jcustomizer._applyInitializer(res) # Attach public inner classes we find # Due to bootstrapping, we must wait until java.lang.Class is defined # before we can access the class structures. if _jpype._java_lang_Class: jcls = res.class_ for cls in jcls.getDeclaredClasses(): if cls.getModifiers() & 1 == 0: continue wrapper = _jpype.JClass(cls) type.__setattr__(res, str(cls.getSimpleName()), wrapper)
def _jclassPost(res, *args): # Post customizers hints = _jcustomizer.getClassHints(res.__name__) res._hints = hints hints.applyInitializer(res) # Attach public inner classes we find # Due to bootstrapping, we must wait until java.lang.Class is defined # before we can access the class structures. if _jpype._java_lang_Class: for cls in res.class_.getDeclaredClasses(): if cls.getModifiers() & 1 == 0: continue wrapper = _jpype.JClass(cls) res._customize(str(cls.getSimpleName()), wrapper)
def clone(self): """ Clone the Java array. Create a "shallow" copy of a Java array. For a single dimensional array of primitives, the cloned array is complete independent copy of the original. For objects or multidimensional arrays, the new array is a copy which points to the same members as the original. To obtain a deep copy of a Java array, use Java serialize and deserialize operations to duplicate the entire array and contents. In order to deep copy, the objects must be Serializable. Returns: A shallow copy of the array. """ return _jpype.JClass("java.util.Arrays").copyOf(self, len(self))
def _JObjectFactory(v=None, tp=None): """ Creates a Java object. If not specified type is determined based on the object. If type type is specified then then it tried to box it. """ if tp is None: # Automatically determine based on the value tp = _getDefaultJavaObject(v) elif isinstance(tp, str): tp = _jpype.JClass(tp) if tp in _jpype._object_classes: tp = _jpype._object_classes[tp] # Given a Java class if isinstance(tp, _jpype._JClass): return tp._cast(v) raise TypeError("Invalid type conversion to %s requested." % tp)
def getJVMVersion(): """ Get the JVM version if the JVM is started. This function can be used to determine the version of the JVM. It is useful to help determine why a Jar has failed to load. Returns: A typle with the (major, minor, revison) of the JVM if running. """ if not _jpype.isStarted(): return (0, 0, 0) import re runtime = _jpype.JClass('java.lang.Runtime') version = runtime.class_.getPackage().getImplementationVersion() # Java 9+ has a version method if not version: version = runtime.version() version = (re.match("([0-9.]+)", str(version)).group(1)) return tuple([int(i) for i in version.split('.')])
def _JObjectFactory(v=None, tp=None): """ Creates a Java object. If not specified type is determined based on the object. If type type is specified then then it tried to box it. """ if tp is None: # Automatically determine based on the value tp = _getDefaultJavaObject(v) elif isinstance(tp, str): tp = _jpype.JClass(tp) if tp in _jpype._object_classes: if not isinstance(tp, _jpype.JClass): import warnings warnings.warn("Using JObject with a Python type is deprecated.", category=DeprecationWarning, stacklevel=3) tp = _jpype._object_classes[tp] # Given a Java class if isinstance(tp, _jpype._JClass): return tp._cast(v) raise TypeError("Invalid type conversion to %s requested." % tp)
def initializeResources(): global _JVM_started _jpype._java_lang_Class = None _jpype._java_lang_Object = _jpype.JClass("java.lang.Object") _jpype._java_lang_Throwable = _jpype.JClass("java.lang.Throwable") _jpype._java_lang_Exception = _jpype.JClass("java.lang.Exception") _jpype._java_lang_Class = _jpype.JClass("java.lang.Class") _jpype._java_lang_String = _jpype.JClass("java.lang.String") _jpype._java_lang_RuntimeException = _jpype.JClass( "java.lang.RuntimeException") # Preload needed classes _jpype._java_lang_Boolean = _jpype.JClass("java.lang.Boolean") _jpype._java_lang_Byte = _jpype.JClass("java.lang.Byte") _jpype._java_lang_Character = _jpype.JClass("java.lang.Character") _jpype._java_lang_Short = _jpype.JClass("java.lang.Short") _jpype._java_lang_Integer = _jpype.JClass("java.lang.Integer") _jpype._java_lang_Long = _jpype.JClass("java.lang.Long") _jpype._java_lang_Float = _jpype.JClass("java.lang.Float") _jpype._java_lang_Double = _jpype.JClass("java.lang.Double") # Bind types _jpype.JString.class_ = _jpype._java_lang_String _jpype.JObject.class_ = _jpype._java_lang_Object _jtypes.JBoolean.class_ = _jpype._java_lang_Boolean.TYPE _jtypes.JByte.class_ = _jpype._java_lang_Byte.TYPE _jtypes.JChar.class_ = _jpype._java_lang_Character.TYPE _jtypes.JShort.class_ = _jpype._java_lang_Short.TYPE _jtypes.JInt.class_ = _jpype._java_lang_Integer.TYPE _jtypes.JLong.class_ = _jpype._java_lang_Long.TYPE _jtypes.JFloat.class_ = _jpype._java_lang_Float.TYPE _jtypes.JDouble.class_ = _jpype._java_lang_Double.TYPE _jtypes.JBoolean._hints = _jcustomizer.getClassHints("boolean") _jtypes.JByte._hints = _jcustomizer.getClassHints("byte") _jtypes.JChar._hints = _jcustomizer.getClassHints("char") _jtypes.JShort._hints = _jcustomizer.getClassHints("short") _jtypes.JInt._hints = _jcustomizer.getClassHints("int") _jtypes.JLong._hints = _jcustomizer.getClassHints("long") _jtypes.JFloat._hints = _jcustomizer.getClassHints("float") _jtypes.JDouble._hints = _jcustomizer.getClassHints("double") # Table for automatic conversion to objects "JObject(value, type)" _jpype._object_classes = {} # These need to be deprecated so that we can support casting Python objects _jpype._object_classes[bool] = _jpype._java_lang_Boolean _jpype._object_classes[int] = _jpype._java_lang_Long _jpype._object_classes[float] = _jpype._java_lang_Double _jpype._object_classes[str] = _jpype._java_lang_String _jpype._object_classes[type] = _jpype._java_lang_Class _jpype._object_classes[object] = _jpype._java_lang_Object _jpype._object_classes[_jpype._JClass] = _jpype._java_lang_Class _jpype._object_classes[_jtypes.JBoolean] = _jpype._java_lang_Boolean _jpype._object_classes[_jtypes.JByte] = _jpype._java_lang_Byte _jpype._object_classes[_jtypes.JChar] = _jpype._java_lang_Character _jpype._object_classes[_jtypes.JShort] = _jpype._java_lang_Short _jpype._object_classes[_jtypes.JInt] = _jpype._java_lang_Integer _jpype._object_classes[_jtypes.JLong] = _jpype._java_lang_Long _jpype._object_classes[_jtypes.JFloat] = _jpype._java_lang_Float _jpype._object_classes[_jtypes.JDouble] = _jpype._java_lang_Double _jpype._object_classes[type(None)] = _jpype._java_lang_Object _jpype._object_classes[_jpype.JString] = _jpype._java_lang_String # Set up table of automatic conversions of Python primitives # this table supports "JArray(type)" _jpype._type_classes = {} _jpype._type_classes[bool] = _jtypes.JBoolean _jpype._type_classes[int] = _jtypes.JLong _jpype._type_classes[float] = _jtypes.JDouble _jpype._type_classes[str] = _jpype._java_lang_String _jpype._type_classes[type] = _jpype._java_lang_Class _jpype._type_classes[object] = _jpype._java_lang_Object _jpype._type_classes[_jpype.JString] = _jpype._java_lang_String _jpype._type_classes[_jpype.JObject] = _jpype._java_lang_Object _jinit.runJVMInitializers() _jpype.JClass('org.jpype.JPypeKeywords').setKeywords( list(_pykeywords._KEYWORDS)) _jpype.JPypeContext = _jpype.JClass('org.jpype.JPypeContext').getInstance() _jpype.JPypeClassLoader = _jpype.JPypeContext.getClassLoader() # Everything successed so started is now true. _JVM_started = True
def _JPathConvert(jcls, obj): Paths = _jpype.JClass("java.nio.file.Paths") return Paths.get(obj.__fspath__())
def reverse(self): _jpype.JClass("java.util.Collections").reverse(self)
def startJVM(*args, **kwargs): """ Starts a Java Virtual Machine. Without options it will start the JVM with the default classpath and jvmpath. The default classpath is determined by ``jpype.getClassPath()``. The default jvmpath is determined by ``jpype.getDefaultJVMPath()``. Parameters: *args (Optional, str[]): Arguments to give to the JVM. The first argument may be the path the JVM. Keyword Arguments: jvmpath (str): Path to the jvm library file, Typically one of (``libjvm.so``, ``jvm.dll``, ...) Using None will apply the default jvmpath. classpath (str,[str]): Set the classpath for the JVM. This will override any classpath supplied in the arguments list. A value of None will give no classpath to JVM. ignoreUnrecognized (bool): Option to ignore invalid JVM arguments. Default is False. convertStrings (bool): Option to force Java strings to cast to Python strings. This option is to support legacy code for which conversion of Python strings was the default. This will globally change the behavior of all calls using strings, and a value of True is NOT recommended for newly developed code. The default value for this option during 0.7 series is True. The option will be False starting in 0.8. A warning will be issued if this option is not specified during the transition period. Raises: OSError: if the JVM cannot be started or is already running. TypeError: if an invalid keyword argument is supplied or a keyword argument conflicts with the arguments. """ if _jpype.isStarted(): raise OSError('JVM is already started') global _JVM_started if _JVM_started: raise OSError('JVM cannot be restarted') args = list(args) # JVM path jvmpath = None if args: # jvm is the first argument the first argument is a path or None if not args[0] or not args[0].startswith('-'): jvmpath = args.pop(0) if 'jvmpath' in kwargs: if jvmpath: raise TypeError('jvmpath specified twice') jvmpath = kwargs.pop('jvmpath') if not jvmpath: jvmpath = getDefaultJVMPath() # Classpath handling if _hasClassPath(args): # Old style, specified in the arguments if 'classpath' in kwargs: # Cannot apply both styles, conflict raise TypeError('classpath specified twice') classpath = None elif 'classpath' in kwargs: # New style, as a keywork classpath = kwargs.pop('classpath') else: # Not speficied at all, use the default classpath classpath = _classpath.getClassPath() # Handle strings and list of strings. if classpath: if isinstance(classpath, str): args.append('-Djava.class.path=%s' % _handleClassPath([classpath])) elif hasattr(classpath, '__iter__'): args.append('-Djava.class.path=%s' % _handleClassPath(classpath)) else: raise TypeError("Unknown class path element") ignoreUnrecognized = kwargs.pop('ignoreUnrecognized', False) convertStrings = kwargs.pop('convertStrings', False) if kwargs: raise TypeError("startJVM() got an unexpected keyword argument '%s'" % (','.join([str(i) for i in kwargs]))) try: _jpype.startup(jvmpath, tuple(args), ignoreUnrecognized, convertStrings) _JVM_started = True except RuntimeError as ex: source = str(ex) if "UnsupportedClassVersion" in source: import re match = re.search(r"([0-9]+)\.[0-9]+", source) if match: version = int(match.group(1)) - 44 raise RuntimeError( "%s is older than required Java version %d" % (jvmpath, version)) from ex raise _jpype._java_lang_Class = None _jpype._java_lang_Object = _jpype.JClass("java.lang.Object") _jpype._java_lang_Throwable = _jpype.JClass("java.lang.Throwable") _jpype._java_lang_Exception = _jpype.JClass("java.lang.Exception") _jpype._java_lang_Class = _jpype.JClass("java.lang.Class") _jpype._java_lang_String = _jpype.JClass("java.lang.String") _jpype._java_lang_RuntimeException = _jpype.JClass( "java.lang.RuntimeException") # Preload needed classes _jpype._java_lang_Boolean = _jpype.JClass("java.lang.Boolean") _jpype._java_lang_Byte = _jpype.JClass("java.lang.Byte") _jpype._java_lang_Character = _jpype.JClass("java.lang.Character") _jpype._java_lang_Short = _jpype.JClass("java.lang.Short") _jpype._java_lang_Integer = _jpype.JClass("java.lang.Integer") _jpype._java_lang_Long = _jpype.JClass("java.lang.Long") _jpype._java_lang_Float = _jpype.JClass("java.lang.Float") _jpype._java_lang_Double = _jpype.JClass("java.lang.Double") # Bind types _jpype.JString.class_ = _jpype._java_lang_String _jpype.JObject.class_ = _jpype._java_lang_Object _jtypes.JBoolean.class_ = _jpype._java_lang_Boolean.TYPE _jtypes.JByte.class_ = _jpype._java_lang_Byte.TYPE _jtypes.JChar.class_ = _jpype._java_lang_Character.TYPE _jtypes.JShort.class_ = _jpype._java_lang_Short.TYPE _jtypes.JInt.class_ = _jpype._java_lang_Integer.TYPE _jtypes.JLong.class_ = _jpype._java_lang_Long.TYPE _jtypes.JFloat.class_ = _jpype._java_lang_Float.TYPE _jtypes.JDouble.class_ = _jpype._java_lang_Double.TYPE _jtypes.JBoolean._hints = _jcustomizer.getClassHints("boolean") _jtypes.JByte._hints = _jcustomizer.getClassHints("byte") _jtypes.JChar._hints = _jcustomizer.getClassHints("char") _jtypes.JShort._hints = _jcustomizer.getClassHints("short") _jtypes.JInt._hints = _jcustomizer.getClassHints("int") _jtypes.JLong._hints = _jcustomizer.getClassHints("long") _jtypes.JFloat._hints = _jcustomizer.getClassHints("float") _jtypes.JDouble._hints = _jcustomizer.getClassHints("double") # Table for automatic conversion to objects "JObject(value, type)" _jpype._object_classes = {} # These need to be deprecated so that we can support casting Python objects _jpype._object_classes[bool] = _jpype._java_lang_Boolean _jpype._object_classes[int] = _jpype._java_lang_Long _jpype._object_classes[float] = _jpype._java_lang_Double _jpype._object_classes[str] = _jpype._java_lang_String _jpype._object_classes[type] = _jpype._java_lang_Class _jpype._object_classes[object] = _jpype._java_lang_Object _jpype._object_classes[_jpype._JClass] = _jpype._java_lang_Class _jpype._object_classes[_jtypes.JBoolean] = _jpype._java_lang_Boolean _jpype._object_classes[_jtypes.JByte] = _jpype._java_lang_Byte _jpype._object_classes[_jtypes.JChar] = _jpype._java_lang_Character _jpype._object_classes[_jtypes.JShort] = _jpype._java_lang_Short _jpype._object_classes[_jtypes.JInt] = _jpype._java_lang_Integer _jpype._object_classes[_jtypes.JLong] = _jpype._java_lang_Long _jpype._object_classes[_jtypes.JFloat] = _jpype._java_lang_Float _jpype._object_classes[_jtypes.JDouble] = _jpype._java_lang_Double _jpype._object_classes[type(None)] = _jpype._java_lang_Object _jpype._object_classes[_jpype.JString] = _jpype._java_lang_String # Set up table of automatic conversions of Python primitives # this table supports "JArray(type)" _jpype._type_classes = {} _jpype._type_classes[bool] = _jtypes.JBoolean _jpype._type_classes[int] = _jtypes.JLong _jpype._type_classes[float] = _jtypes.JDouble _jpype._type_classes[str] = _jpype._java_lang_String _jpype._type_classes[type] = _jpype._java_lang_Class _jpype._type_classes[object] = _jpype._java_lang_Object _jpype._type_classes[_jpype.JString] = _jpype._java_lang_String _jpype._type_classes[_jpype.JObject] = _jpype._java_lang_Object _jinit.runJVMInitializers() _jpype.JClass('org.jpype.JPypeKeywords').setKeywords( list(_pykeywords._KEYWORDS))
def _JPathConvert(jcls, obj): Paths = _jpype.JClass("java.nio.file.Paths") return Paths.get(str(obj))
def __init__(self, file, *args, **kwargs): self._decoder = _jpype.JClass('org.jpype.pickle.Decoder')() pickle.Unpickler.__init__(self, file, *args, **kwargs)
def __init__(self, file, *args, **kwargs): cl = _jpype.JClass( 'org.jpype.classloader.JPypeClassLoader').getInstance() self._decoder = _jpype.JClass( cl.loadClass('org.jpype.pickle.Decoder'))() pickle.Unpickler.__init__(self, file, *args, **kwargs)
def _jmethodGetDoc(method, cls, overloads): """Generator for _JMethod.__doc__ property Parameters: method (_JMethod): method to generate doc string for. cls (java.lang.Class): Class holding this method dispatch. overloads (java.lang.reflect.Method[]): tuple holding all the methods that are served by this method dispatch. Returns: The doc string for the method dispatch. """ jcls = _jpype.JClass(cls) if not hasattr(jcls, "__javadoc__"): jcls.__doc__ jd = getattr(jcls, "__javadoc__") if jd is not None: md = jd.methods.get(method.__name__) if md is not None: return str(md) from textwrap import TextWrapper out = [] out.append("Java method dispatch '%s' for '%s'" % (method.__name__, cls.getName())) out.append("") exceptions = [] returns = [] methods = [] classmethods = [] for ov in overloads: modifiers = ov.getModifiers() exceptions.extend(ov.getExceptionTypes()) returnName = ov.getReturnType().getCanonicalName() params = ", ".join( [str(i.getCanonicalName()) for i in ov.getParameterTypes()]) if returnName != "void": returns.append(returnName) if modifiers & 8: classmethods.append(" * %s %s(%s)" % (returnName, ov.getName(), params)) else: methods.append(" * %s %s(%s)" % (returnName, ov.getName(), params)) if classmethods: out.append(" Static Methods:") out.extend(classmethods) out.append("") if methods: out.append(" Virtual Methods:") out.extend(methods) out.append("") if exceptions: out.append(" Raises:") for exc in set(exceptions): out.append(" %s: from java" % exc.getCanonicalName()) out.append("") if returns: out.append(" Returns:") words = ", ".join([str(i) for i in set(returns)]) wrapper = TextWrapper(initial_indent=' ', subsequent_indent=' ') out.extend(wrapper.wrap(words)) out.append("") return "\n".join(out)
def __new__(cls, *args, **kwargs): if cls != JString: raise TypeError("JString factory cannot be used as base class") cls = _jpype.JClass("java.lang.String") return cls(*args)
def removeShutdownHook(self, thread): return _jpype.JClass( "org.jpype.JPypeContext").getInstance().removeShutdownHook(thread)