100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
|
# *****************************************************************************
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
#
|
||
|
# See NOTICE file for details.
|
||
|
#
|
||
|
# *****************************************************************************
|
||
|
"""
|
||
|
JPype Beans Module
|
||
|
------------------
|
||
|
|
||
|
This customizer finds all occurences of methods with get or set and converts
|
||
|
them into Python properties. This behavior is sometimes useful in programming
|
||
|
with JPype with interactive shells, but also leads to a lot of confusion.
|
||
|
Is this class exposing a variable or is this a property added JPype.
|
||
|
|
||
|
As an unnecessary behavior that violates both the Python principle
|
||
|
*"There should be one-- and preferably only one --obvious way to do it."* and
|
||
|
the C++ principle *"You only pay for what you use"*. This misfeature
|
||
|
was removed from the distribution as a default. However, given that it is
|
||
|
useful to have methods appear as properties, it was moved to a
|
||
|
an optional module.
|
||
|
|
||
|
To use beans as properties:
|
||
|
|
||
|
.. code-block:: python
|
||
|
|
||
|
import jpype.beans
|
||
|
|
||
|
The beans property modification is a global behavior and applies retroactively
|
||
|
to all classes currently loaded. Once started it can not be undone.
|
||
|
"""
|
||
|
import _jpype
|
||
|
from . import _jcustomizer
|
||
|
from ._pykeywords import pysafe as _pysafe
|
||
|
|
||
|
|
||
|
def _extract_accessor_pairs(members):
|
||
|
"""Extract pairs of corresponding property access methods
|
||
|
(getter and setter) from a Java class's members (attributes).
|
||
|
|
||
|
If a public method with a property's name exists no pair for
|
||
|
that property will be extracted.
|
||
|
|
||
|
Returns a dictionary with the property name as key and a tuple
|
||
|
of (getter method, setter method) as value. A tuple element
|
||
|
value might be `None` if only a getter or only a setter
|
||
|
exists.
|
||
|
"""
|
||
|
accessor_pairs = {}
|
||
|
|
||
|
for name, member in members.items():
|
||
|
if not isinstance(member, _jpype._JMethod) or len(name) <= 3:
|
||
|
continue
|
||
|
if name == "getClass":
|
||
|
continue
|
||
|
|
||
|
if member._isBeanAccessor():
|
||
|
property_name = name[3].lower() + name[4:]
|
||
|
try:
|
||
|
pair = accessor_pairs[property_name]
|
||
|
pair[0] = member
|
||
|
except KeyError:
|
||
|
accessor_pairs[property_name] = [member, None]
|
||
|
elif member._isBeanMutator():
|
||
|
property_name = name[3].lower() + name[4:]
|
||
|
try:
|
||
|
pair = accessor_pairs[property_name]
|
||
|
pair[1] = member
|
||
|
except KeyError:
|
||
|
accessor_pairs[property_name] = [None, member]
|
||
|
return accessor_pairs
|
||
|
|
||
|
|
||
|
@_jcustomizer.JImplementationFor("java.lang.Object")
|
||
|
class _BeansCustomizer(object):
|
||
|
""" Add properties for get/set Bean patterns found in classes. """
|
||
|
|
||
|
def __jclass_init__(self):
|
||
|
accessor_pairs = _extract_accessor_pairs(self.__dict__)
|
||
|
for attr_name, (getter, setter) in accessor_pairs.items():
|
||
|
attr_name = _pysafe(attr_name)
|
||
|
|
||
|
# Don't mess with an existing member
|
||
|
if attr_name is None or attr_name in self.__dict__:
|
||
|
continue
|
||
|
|
||
|
# Add the property
|
||
|
self._customize(attr_name, property(getter, setter))
|