_jclass.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #*****************************************************************************
  2. # Copyright 2004-2008 Steve Menard
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. #*****************************************************************************
  17. import _jpype
  18. from ._pykeywords import KEYWORDS
  19. _CLASSES = {}
  20. _SPECIAL_CONSTRUCTOR_KEY = "This is the special constructor key"
  21. _JAVAOBJECT = None
  22. _JAVATHROWABLE = None
  23. _COMPARABLE = None
  24. _RUNTIMEEXCEPTION = None
  25. _CUSTOMIZERS = []
  26. _COMPARABLE_METHODS = {
  27. "__cmp__": lambda self, o: self.compareTo(o)
  28. }
  29. def _initialize():
  30. global _COMPARABLE, _JAVAOBJECT, _JAVATHROWABLE, _RUNTIMEEXCEPTION
  31. _JAVAOBJECT = JClass("java.lang.Object")
  32. _JAVATHROWABLE = JClass("java.lang.Throwable")
  33. _RUNTIMEEXCEPTION = JClass("java.lang.RuntimeException")
  34. _jpype.setJavaLangObjectClass(_JAVAOBJECT)
  35. _jpype.setGetClassMethod(_getClassFor)
  36. _jpype.setSpecialConstructorKey(_SPECIAL_CONSTRUCTOR_KEY)
  37. def registerClassCustomizer(c):
  38. _CUSTOMIZERS.append(c)
  39. def JClass(name):
  40. jc = _jpype.findClass(name)
  41. if jc is None:
  42. raise _RUNTIMEEXCEPTION.PYEXC("Class %s not found" % name)
  43. return _getClassFor(jc)
  44. def _getClassFor(javaClass):
  45. name = javaClass.getName()
  46. if name in _CLASSES:
  47. return _CLASSES[name]
  48. pyJavaClass = _JavaClass(javaClass)
  49. _CLASSES[name] = pyJavaClass
  50. return pyJavaClass
  51. def _javaNew(self, *args):
  52. return object.__new__(self)
  53. def _javaExceptionNew(self, *args):
  54. return Exception.__new__(self)
  55. def _javaInit(self, *args):
  56. object.__init__(self)
  57. if len(args) == 1 and isinstance(args[0], tuple) \
  58. and args[0][0] is _SPECIAL_CONSTRUCTOR_KEY:
  59. self.__javaobject__ = args[0][1]
  60. else:
  61. self.__javaobject__ = self.__class__.__javaclass__.newClassInstance(
  62. *args)
  63. def _javaGetAttr(self, name):
  64. try:
  65. r = object.__getattribute__(self, name)
  66. except AttributeError as ex:
  67. if name in dir(self.__class__.__metaclass__):
  68. r = object.__getattribute__(self.__class__, name)
  69. else:
  70. raise ex
  71. if isinstance(r, _jpype._JavaMethod):
  72. return _jpype._JavaBoundMethod(r, self)
  73. return r
  74. class _JavaClass(type):
  75. def __new__(cls, jc):
  76. bases = []
  77. name = jc.getName()
  78. static_fields = {}
  79. members = {
  80. "__javaclass__": jc,
  81. "__init__": _javaInit,
  82. "__str__": lambda self: self.toString(),
  83. "__hash__": lambda self: self.hashCode(),
  84. "__eq__": lambda self, o: self.equals(o),
  85. "__ne__": lambda self, o: not self.equals(o),
  86. "__getattribute__": _javaGetAttr,
  87. }
  88. if name == 'java.lang.Object' or jc.isPrimitive():
  89. bases.append(object)
  90. elif not jc.isInterface():
  91. bjc = jc.getBaseClass(jc)
  92. bases.append(_getClassFor(bjc))
  93. if _JAVATHROWABLE is not None and jc.isSubclass("java.lang.Throwable"):
  94. from . import _jexception
  95. members["PYEXC"] = _jexception._makePythonException(name, bjc)
  96. itf = jc.getBaseInterfaces()
  97. for ic in itf:
  98. bases.append(_getClassFor(ic))
  99. if len(bases) == 0:
  100. bases.append(_JAVAOBJECT)
  101. # add the fields
  102. fields = jc.getClassFields()
  103. for i in fields:
  104. fname = i.getName()
  105. if fname in KEYWORDS:
  106. fname += "_"
  107. if i.isStatic():
  108. g = lambda self, fld=i: fld.getStaticAttribute()
  109. s = None
  110. if not i.isFinal():
  111. s = lambda self, v, fld=i: fld.setStaticAttribute(v)
  112. static_fields[fname] = property(g, s)
  113. else:
  114. g = lambda self, fld=i: fld.getInstanceAttribute(
  115. self.__javaobject__)
  116. s = None
  117. if not i.isFinal():
  118. s = lambda self, v, fld=i: fld.setInstanceAttribute(
  119. self.__javaobject__, v)
  120. members[fname] = property(g, s)
  121. # methods
  122. methods = jc.getClassMethods() # Return tuple of tuple (name, method).
  123. for jm in methods:
  124. mname = jm.getName()
  125. if mname in KEYWORDS:
  126. mname += "_"
  127. members[mname] = jm
  128. for i in _CUSTOMIZERS:
  129. if i.canCustomize(name, jc):
  130. i.customize(name, jc, bases, members)
  131. # remove multiple bases that would cause a MRO problem
  132. toRemove = set()
  133. for c in bases:
  134. for d in bases:
  135. if c == d:
  136. continue
  137. if issubclass(c, d):
  138. toRemove.add(d)
  139. for i in toRemove:
  140. bases.remove(i)
  141. # Prepare the meta-metaclass
  142. meta_bases = []
  143. for i in bases:
  144. if i is object:
  145. meta_bases.append(cls)
  146. else:
  147. meta_bases.append(i.__metaclass__)
  148. metaclass = type.__new__(type, name + "$$Static", tuple(meta_bases),
  149. static_fields)
  150. members['__metaclass__'] = metaclass
  151. result = type.__new__(metaclass, name, tuple(bases), members)
  152. return result