""" Java java.lang.reflect APIs implemented in Python. java.lang.reflect package - Field, Method, Constructor, Array, Modifier, Proxy, etc. Wraps Python inspect module. """ from __future__ import annotations from .._core import Stub, AndroidOnlyError import inspect as _inspect import types as _types from typing import Any, List, Optional, Tuple __all__ = [ "Field", "Method", "Constructor", "Array", "Modifier", "InvocationHandler", "Proxy", "Parameter", "AccessibleObject", "Executable", "GenericArrayType", "ParameterizedType", "TypeVariable", "WildcardType", "GenericDeclaration", "AnnotatedType", "AnnotatedArrayType", "AnnotatedParameterizedType", "AnnotatedTypeVariable", "AnnotatedWildcardType", ] # ============================================================ # Modifier # ============================================================ class Modifier(Stub): """ java.lang.reflect.Modifier Provides static methods and constants for decoding class and member access modifiers. Uses actual JVM modifier bit values. """ PUBLIC: int = 0x0001 PRIVATE: int = 0x0002 PROTECTED: int = 0x0004 STATIC: int = 0x0008 FINAL: int = 0x0010 SYNCHRONIZED: int = 0x0020 VOLATILE: int = 0x0040 TRANSIENT: int = 0x0080 NATIVE: int = 0x0100 INTERFACE: int = 0x0200 ABSTRACT: int = 0x0400 STRICT: int = 0x0800 _MODIFIER_NAMES = { 0x0001: "public", 0x0002: "private", 0x0004: "protected", 0x0008: "static", 0x0010: "final", 0x0020: "synchronized", 0x0040: "volatile", 0x0080: "transient", 0x0100: "native", 0x0200: "interface", 0x0400: "abstract", 0x0800: "strictfp", } def __init__(self): super().__init__() @staticmethod def isPublic(mod: int) -> bool: return (mod & Modifier.PUBLIC) != 0 @staticmethod def isPrivate(mod: int) -> bool: return (mod & Modifier.PRIVATE) != 0 @staticmethod def isProtected(mod: int) -> bool: return (mod & Modifier.PROTECTED) != 0 @staticmethod def isStatic(mod: int) -> bool: return (mod & Modifier.STATIC) != 0 @staticmethod def isFinal(mod: int) -> bool: return (mod & Modifier.FINAL) != 0 @staticmethod def isSynchronized(mod: int) -> bool: return (mod & Modifier.SYNCHRONIZED) != 0 @staticmethod def isVolatile(mod: int) -> bool: return (mod & Modifier.VOLATILE) != 0 @staticmethod def isTransient(mod: int) -> bool: return (mod & Modifier.TRANSIENT) != 0 @staticmethod def isNative(mod: int) -> bool: return (mod & Modifier.NATIVE) != 0 @staticmethod def isInterface(mod: int) -> bool: return (mod & Modifier.INTERFACE) != 0 @staticmethod def isAbstract(mod: int) -> bool: return (mod & Modifier.ABSTRACT) != 0 @staticmethod def isStrict(mod: int) -> bool: return (mod & Modifier.STRICT) != 0 @staticmethod def toString(mod: int) -> str: parts = [] for bit, name in sorted(Modifier._MODIFIER_NAMES.items()): if mod & bit: parts.append(name) return " ".join(parts) @staticmethod def classModifiers() -> int: return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | \ Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | Modifier.STRICT @staticmethod def constructorModifiers() -> int: return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE @staticmethod def fieldModifiers() -> int: return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | \ Modifier.STATIC | Modifier.FINAL | Modifier.TRANSIENT | Modifier.VOLATILE @staticmethod def interfaceModifiers() -> int: return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | \ Modifier.ABSTRACT | Modifier.STATIC | Modifier.STRICT @staticmethod def methodModifiers() -> int: return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | \ Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | \ Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.STRICT @staticmethod def parameterModifiers() -> int: return Modifier.FINAL # ============================================================ # AccessibleObject # ============================================================ class AccessibleObject(Stub): """ java.lang.reflect.AccessibleObject Base class for Field, Method, and Constructor. """ def __init__(self): super().__init__() self._accessible = False def setAccessible(self, flag: bool): """Sets the accessible flag for this object.""" self._accessible = flag def isAccessible(self) -> bool: """Returns the value of the accessible flag.""" return self._accessible def getAnnotation(self, annotation_class: type) -> Optional[Stub]: """Returns the annotation for this element (if present).""" return None def getDeclaredAnnotations(self) -> List: """Returns all annotations directly present on this element.""" return [] def getAnnotations(self) -> List: """Returns all annotations on this element.""" return [] def getAnnotationsByType(self, annotation_class: type) -> List: """Returns annotations of the specified type on this element.""" return [] def isAnnotationPresent(self, annotation_class: type) -> bool: """Returns True if the specified annotation is present.""" return False def toString(self) -> str: return f"{self.__class__.__name__}@{hex(id(self))}" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Field # ============================================================ class Field(AccessibleObject): """ java.lang.reflect.Field Provides information about, and dynamic access to, a single field of a class. """ def __init__(self, declaring_class: type = None, name: str = None, field_type: type = None, modifiers: int = 0): super().__init__() self._declaring_class = declaring_class self._name = name self._field_type = field_type self._modifiers = modifiers self._generic_type = field_type def getName(self) -> str: return self._name or "" def getType(self) -> type: return self._field_type or object def getModifiers(self) -> int: return self._modifiers def get(self, obj: Any) -> Any: """Returns the value of the field on the given object.""" if self._name is None: return None if obj is None and Modifier.isStatic(self._modifiers): # Static field access on the class if self._declaring_class and hasattr(self._declaring_class, self._name): return getattr(self._declaring_class, self._name) return None if obj is not None and hasattr(obj, self._name): return getattr(obj, self._name) return None def set(self, obj: Any, value: Any): """Sets the field on the given object to the given value.""" if self._name is None: return if obj is None and Modifier.isStatic(self._modifiers): if self._declaring_class: setattr(self._declaring_class, self._name, value) return if obj is not None and hasattr(obj, self._name): setattr(obj, self._name, value) def setAccessible(self, flag: bool): self._accessible = flag def getDeclaringClass(self) -> type: return self._declaring_class def getGenericType(self): return self._generic_type def getAnnotation(self, annotation_class: type): return None def getDeclaredAnnotations(self) -> List: return [] def isAccessible(self) -> bool: return self._accessible def isSynthetic(self) -> bool: return False def toGenericString(self) -> str: return f"{Modifier.toString(self._modifiers)} {self._field_type.__name__ if self._field_type else '?'} {self._name}" def getBoolean(self, obj: Any) -> bool: val = self.get(obj) return bool(val) if val is not None else False def getByte(self, obj: Any) -> int: val = self.get(obj) return int(val) if val is not None else 0 def getChar(self, obj: Any) -> str: val = self.get(obj) return str(val)[0] if val else '\0' def getShort(self, obj: Any) -> int: val = self.get(obj) return int(val) if val is not None else 0 def getInt(self, obj: Any) -> int: val = self.get(obj) return int(val) if val is not None else 0 def getLong(self, obj: Any) -> int: val = self.get(obj) return int(val) if val is not None else 0 def getFloat(self, obj: Any) -> float: val = self.get(obj) return float(val) if val is not None else 0.0 def getDouble(self, obj: Any) -> float: val = self.get(obj) return float(val) if val is not None else 0.0 def setBoolean(self, obj: Any, value: bool): self.set(obj, value) def setByte(self, obj: Any, value: int): self.set(obj, value) def setChar(self, obj: Any, value: str): self.set(obj, value) def setShort(self, obj: Any, value: int): self.set(obj, value) def setInt(self, obj: Any, value: int): self.set(obj, value) def setLong(self, obj: Any, value: int): self.set(obj, value) def setFloat(self, obj: Any, value: float): self.set(obj, value) def setDouble(self, obj: Any, value: float): self.set(obj, value) def toString(self) -> str: return self.toGenericString() def equals(self, other) -> bool: if not isinstance(other, Field): return False return (self._declaring_class == other._declaring_class and self._name == other._name and self._field_type == other._field_type) def hashCode(self) -> int: return hash((self._declaring_class, self._name)) & 0x7FFFFFFF # ============================================================ # Executable (abstract base for Method & Constructor) # ============================================================ class Executable(AccessibleObject): """ java.lang.reflect.Executable Shared base for Method and Constructor. """ def __init__(self, declaring_class: type = None, name: str = None, parameter_types: List[type] = None, exception_types: List[type] = None, modifiers: int = 0): super().__init__() self._declaring_class = declaring_class self._name = name self._parameter_types = parameter_types or [] self._exception_types = exception_types or [] self._modifiers = modifiers def getParameterTypes(self) -> List[type]: return list(self._parameter_types) def getParameterCount(self) -> int: return len(self._parameter_types) def getExceptionTypes(self) -> List[type]: return list(self._exception_types) def getModifiers(self) -> int: return self._modifiers def getDeclaringClass(self) -> type: return self._declaring_class def getName(self) -> str: return self._name or "" def getAnnotation(self, annotation_class: type): return None def getDeclaredAnnotations(self) -> List: return [] def getParameterAnnotations(self) -> List[List]: return [[] for _ in self._parameter_types] def isVarArgs(self) -> bool: return False def isSynthetic(self) -> bool: return False def toGenericString(self) -> str: return f"{Modifier.toString(self._modifiers)} {self._name}({', '.join(t.__name__ for t in self._parameter_types)})" def toString(self) -> str: return self.toGenericString() def equals(self, other) -> bool: if not isinstance(other, Executable): return False return (self._declaring_class == other._declaring_class and self._name == other._name and self._parameter_types == other._parameter_types) def hashCode(self) -> int: return hash((self._declaring_class, self._name)) & 0x7FFFFFFF # ============================================================ # Method # ============================================================ class Method(Executable): """ java.lang.reflect.Method Provides information about, and access to, a single method of a class. """ def __init__(self, declaring_class: type = None, name: str = None, return_type: type = None, parameter_types: List[type] = None, exception_types: List[type] = None, modifiers: int = 0, impl_func: callable = None): super().__init__(declaring_class, name, parameter_types, exception_types, modifiers) self._return_type = return_type self._impl_func = impl_func self._generic_return_type = return_type self._generic_parameter_types = parameter_types or [] def getReturnType(self) -> type: return self._return_type or type(None) def getGenericReturnType(self): return self._generic_return_type def getGenericParameterTypes(self) -> List: return list(self._generic_parameter_types) def invoke(self, obj: Any, *args) -> Any: """ Invokes the underlying method on the given object with the given args. """ if self._impl_func is not None: return self._impl_func(obj, *args) if self._name is None: return None # Try to call the method on the object if obj is not None and hasattr(obj, self._name): method = getattr(obj, self._name) if callable(method): return method(*args) # Static call on class if self._declaring_class and hasattr(self._declaring_class, self._name): method = getattr(self._declaring_class, self._name) if callable(method): return method(*args) return None def getDefaultValue(self): """Returns the default value for the annotation member.""" return None def isBridge(self) -> bool: return False def toGenericString(self) -> str: ret = self._return_type.__name__ if self._return_type else "void" params = ', '.join(t.__name__ for t in self._parameter_types) return f"{Modifier.toString(self._modifiers)} {ret} {self._name}({params})" def toString(self) -> str: return self.toGenericString() def equals(self, other) -> bool: if not isinstance(other, Method): return False return (self._declaring_class == other._declaring_class and self._name == other._name and self._parameter_types == other._parameter_types) def hashCode(self) -> int: return hash((self._declaring_class, self._name)) & 0x7FFFFFFF # ============================================================ # Constructor # ============================================================ class Constructor(Executable): """ java.lang.reflect.Constructor Provides information about, and access to, a single constructor of a class. """ def __init__(self, declaring_class: type = None, parameter_types: List[type] = None, exception_types: List[type] = None, modifiers: int = 0): super().__init__(declaring_class, declaring_class.__name__ if declaring_class else "", parameter_types, exception_types, modifiers) def newInstance(self, *args) -> Any: """Creates a new instance of the declaring class.""" if self._declaring_class is None: raise AndroidOnlyError("No declaring class for constructor") try: return self._declaring_class(*args) except Exception as e: raise AndroidOnlyError(f"Cannot instantiate {self._declaring_class}: {e}") def toGenericString(self) -> str: params = ', '.join(t.__name__ for t in self._parameter_types) return f"{Modifier.toString(self._modifiers)} {self._name}({params})" def toString(self) -> str: return self.toGenericString() def equals(self, other) -> bool: if not isinstance(other, Constructor): return False return (self._declaring_class == other._declaring_class and self._parameter_types == other._parameter_types) def hashCode(self) -> int: return hash((self._declaring_class, tuple(self._parameter_types))) & 0x7FFFFFFF # ============================================================ # Array # ============================================================ class Array(Stub): """ java.lang.reflect.Array Provides static methods to dynamically create and access arrays. """ def __init__(self): super().__init__() @staticmethod def newInstance(component_type: type, *dimensions) -> Any: """Creates a new array with the specified component type and dimensions.""" if len(dimensions) == 1: return [None] * dimensions[0] # Multi-dimensional result = [] for _ in range(dimensions[0]): result.append(Array.newInstance(component_type, *dimensions[1:])) return result @staticmethod def getLength(array: Any) -> int: """Returns the length of the specified array.""" return len(array) @staticmethod def get(array: Any, index: int) -> Any: """Returns the element at the specified index.""" return array[index] @staticmethod def set(array: Any, index: int, value: Any): """Sets the element at the specified index.""" array[index] = value @staticmethod def getBoolean(array: Any, index: int) -> bool: return bool(array[index]) @staticmethod def getByte(array: Any, index: int) -> int: return int(array[index]) @staticmethod def getChar(array: Any, index: int) -> str: return str(array[index]) @staticmethod def getShort(array: Any, index: int) -> int: return int(array[index]) @staticmethod def getInt(array: Any, index: int) -> int: return int(array[index]) @staticmethod def getLong(array: Any, index: int) -> int: return int(array[index]) @staticmethod def getFloat(array: Any, index: int) -> float: return float(array[index]) @staticmethod def getDouble(array: Any, index: int) -> float: return float(array[index]) @staticmethod def setBoolean(array: Any, index: int, value: bool): array[index] = value @staticmethod def setByte(array: Any, index: int, value: int): array[index] = value @staticmethod def setChar(array: Any, index: int, value: str): array[index] = value @staticmethod def setShort(array: Any, index: int, value: int): array[index] = value @staticmethod def setInt(array: Any, index: int, value: int): array[index] = value @staticmethod def setLong(array: Any, index: int, value: int): array[index] = value @staticmethod def setFloat(array: Any, index: int, value: float): array[index] = value @staticmethod def setDouble(array: Any, index: int, value: float): array[index] = value # ============================================================ # Parameter # ============================================================ class Parameter(AccessibleObject): """ java.lang.reflect.Parameter Information about a method parameter. """ def __init__(self, name: str = None, param_type: type = None, modifiers: int = 0, is_implicit: bool = False, is_name_present: bool = True): super().__init__() self._name = name or "" self._param_type = param_type or object self._modifiers = modifiers self._is_implicit = is_implicit self._is_name_present = is_name_present self._parameterized_type = param_type def getName(self) -> str: return self._name def getType(self) -> type: return self._param_type def getParameterizedType(self): return self._parameterized_type def getModifiers(self) -> int: return self._modifiers def isNamePresent(self) -> bool: return self._is_name_present def isImplicit(self) -> bool: return self._is_implicit def isSynthetic(self) -> bool: return False def isVarArgs(self) -> bool: return False def toString(self) -> str: return f"{Modifier.toString(self._modifiers)} {self._param_type.__name__} {self._name}" def equals(self, other) -> bool: if not isinstance(other, Parameter): return False return (self._name == other._name and self._param_type == other._param_type) def hashCode(self) -> int: return hash((self._name, self._param_type)) & 0x7FFFFFFF # ============================================================ # InvocationHandler # ============================================================ class InvocationHandler(Stub): """ java.lang.reflect.InvocationHandler Interface for invocation handlers of proxy instances. """ def invoke(self, proxy: Any, method: Any, args: List) -> Any: """Processes a method invocation on a proxy instance.""" raise NotImplementedError("invoke must be implemented by subclass") # ============================================================ # Proxy # ============================================================ class Proxy(Stub): """ java.lang.reflect.Proxy Provides static methods for creating dynamic proxy classes and instances. """ _invocation_handler: InvocationHandler = None def __init__(self, handler: InvocationHandler = None): super().__init__() self._invocation_handler = handler @staticmethod def newProxyInstance(class_loader: Any, interfaces: List[type], handler: InvocationHandler) -> Stub: """Creates a proxy instance for the specified interfaces.""" proxy = Proxy(handler) proxy._interfaces = interfaces return proxy @staticmethod def getInvocationHandler(proxy: Any) -> InvocationHandler: """Returns the invocation handler for the specified proxy instance.""" if isinstance(proxy, Proxy): return proxy._invocation_handler return None @staticmethod def getProxyClass(class_loader: Any, interfaces: List[type]) -> type: """Returns the proxy class for the specified interfaces.""" return Proxy @staticmethod def isProxyClass(cls: type) -> bool: """Returns True if the class is a proxy class.""" return cls == Proxy or (hasattr(cls, '__bases__') and Proxy in cls.__bases__) def toString(self) -> str: return f"Proxy@{hex(id(self))}" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Generic Array Type (stub interface) # ============================================================ class GenericArrayType(Stub): """ java.lang.reflect.GenericArrayType Represents an array type whose component type is a parameterized type or type variable. """ def __init__(self, generic_component_type=None): super().__init__() self._generic_component_type = generic_component_type def getGenericComponentType(self): return self._generic_component_type def toString(self) -> str: return f"{self._generic_component_type}[]" # ============================================================ # ParameterizedType # ============================================================ class ParameterizedType(Stub): """ java.lang.reflect.ParameterizedType Represents a parameterized type, e.g. List. """ def __init__(self, raw_type=None, actual_type_arguments=None, owner_type=None): super().__init__() self._raw_type = raw_type self._actual_type_arguments = actual_type_arguments or [] self._owner_type = owner_type def getRawType(self): return self._raw_type def getActualTypeArguments(self): return list(self._actual_type_arguments) def getOwnerType(self): return self._owner_type def toString(self) -> str: args = ', '.join(str(a) for a in self._actual_type_arguments) return f"{self._raw_type}<{args}>" # ============================================================ # TypeVariable # ============================================================ class TypeVariable(Stub): """ java.lang.reflect.TypeVariable Represents a type variable, like T in Foo. """ def __init__(self, name: str = None, bounds: List = None, generic_declaration: Any = None): super().__init__() self._name = name or "T" self._bounds = bounds or [object] self._generic_declaration = generic_declaration def getName(self) -> str: return self._name def getBounds(self) -> List: return list(self._bounds) def getGenericDeclaration(self) -> Any: return self._generic_declaration def toString(self) -> str: return self._name # ============================================================ # WildcardType # ============================================================ class WildcardType(Stub): """ java.lang.reflect.WildcardType Represents a wildcard type, like ?, ? extends T, ? super T. """ def __init__(self, upper_bounds: List = None, lower_bounds: List = None): super().__init__() self._upper_bounds = upper_bounds or [object] self._lower_bounds = lower_bounds or [] def getUpperBounds(self) -> List: return list(self._upper_bounds) def getLowerBounds(self) -> List: return list(self._lower_bounds) def toString(self) -> str: if self._lower_bounds: return f"? super {self._lower_bounds[0]}" if self._upper_bounds and self._upper_bounds[0] is not object: return f"? extends {self._upper_bounds[0]}" return "?" # ============================================================ # GenericDeclaration # ============================================================ class GenericDeclaration(Stub): """ java.lang.reflect.GenericDeclaration Interface for entities that declare type variables. """ def getTypeParameters(self) -> List[TypeVariable]: return [] def toGenericString(self) -> str: return self.toString() # ============================================================ # AnnotatedType interfaces # ============================================================ class AnnotatedType(Stub): """ java.lang.reflect.AnnotatedType Represents an annotated type. """ def __init__(self, type_=None, annotations: List = None): super().__init__() self._type = type_ self._annotations = annotations or [] def getType(self): return self._type def getAnnotations(self) -> List: return list(self._annotations) def getAnnotation(self, annotation_class: type): for a in self._annotations: if isinstance(a, annotation_class): return a return None def toString(self) -> str: return str(self._type) if self._type else "?" class AnnotatedArrayType(AnnotatedType): """ java.lang.reflect.AnnotatedArrayType Represents an annotated array type. """ def __init__(self, annotated_generic_component_type=None, type_=None, annotations=None): super().__init__(type_, annotations) self._annotated_generic_component_type = annotated_generic_component_type def getAnnotatedGenericComponentType(self) -> AnnotatedType: return self._annotated_generic_component_type class AnnotatedParameterizedType(AnnotatedType): """ java.lang.reflect.AnnotatedParameterizedType Represents an annotated parameterized type. """ def __init__(self, annotated_actual_type_arguments=None, type_=None, annotations=None): super().__init__(type_, annotations) self._annotated_actual_type_arguments = annotated_actual_type_arguments or [] def getAnnotatedActualTypeArguments(self) -> List[AnnotatedType]: return list(self._annotated_actual_type_arguments) class AnnotatedTypeVariable(AnnotatedType): """ java.lang.reflect.AnnotatedTypeVariable Represents an annotated type variable. """ def __init__(self, annotated_bounds=None, type_=None, annotations=None): super().__init__(type_, annotations) self._annotated_bounds = annotated_bounds or [] def getAnnotatedBounds(self) -> List[AnnotatedType]: return list(self._annotated_bounds) class AnnotatedWildcardType(AnnotatedType): """ java.lang.reflect.AnnotatedWildcardType Represents an annotated wildcard type. """ def __init__(self, annotated_upper_bounds=None, annotated_lower_bounds=None, type_=None, annotations=None): super().__init__(type_, annotations) self._annotated_upper_bounds = annotated_upper_bounds or [] self._annotated_lower_bounds = annotated_lower_bounds or [] def getAnnotatedUpperBounds(self) -> List[AnnotatedType]: return list(self._annotated_upper_bounds) def getAnnotatedLowerBounds(self) -> List[AnnotatedType]: return list(self._annotated_lower_bounds)