初始提交,未完全测试
This commit is contained in:
77
proxy/ProxyClass.py
Normal file
77
proxy/ProxyClass.py
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3.9
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
JFinal ProxyClass - Proxy Class Information
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional, Type
|
||||
|
||||
class ProxyClass:
|
||||
"""Proxy class information holder"""
|
||||
|
||||
def __init__(self, target: Type):
|
||||
"""
|
||||
Initialize proxy class
|
||||
|
||||
Args:
|
||||
target: Target class to be proxied
|
||||
"""
|
||||
self._target = target
|
||||
self._pkg = target.__module__
|
||||
self._name = target.__name__ + "$$EnhancerByJFinal"
|
||||
self._source_code: Optional[str] = None
|
||||
self._byte_code: Optional[Dict[str, bytes]] = None
|
||||
self._clazz: Optional[Type] = None
|
||||
|
||||
@property
|
||||
def target(self) -> Type:
|
||||
"""Get target class"""
|
||||
return self._target
|
||||
|
||||
@property
|
||||
def pkg(self) -> str:
|
||||
"""Get package name"""
|
||||
return self._pkg
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Get proxy class name"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def source_code(self) -> Optional[str]:
|
||||
"""Get source code"""
|
||||
return self._source_code
|
||||
|
||||
@source_code.setter
|
||||
def source_code(self, value: str):
|
||||
"""Set source code"""
|
||||
self._source_code = value
|
||||
|
||||
@property
|
||||
def byte_code(self) -> Optional[Dict[str, bytes]]:
|
||||
"""Get byte code"""
|
||||
return self._byte_code
|
||||
|
||||
@byte_code.setter
|
||||
def byte_code(self, value: Dict[str, bytes]):
|
||||
"""Set byte code"""
|
||||
self._byte_code = value
|
||||
|
||||
@property
|
||||
def clazz(self) -> Optional[Type]:
|
||||
"""Get loaded class"""
|
||||
return self._clazz
|
||||
|
||||
@clazz.setter
|
||||
def clazz(self, value: Type):
|
||||
"""Set loaded class"""
|
||||
self._clazz = value
|
||||
|
||||
@property
|
||||
def full_name(self) -> str:
|
||||
"""Get full class name with package"""
|
||||
return f"{self._pkg}.{self._name}"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"ProxyClass(target={self._target.__name__}, name={self._name})"
|
||||
124
proxy/ProxyClassLoader.py
Normal file
124
proxy/ProxyClassLoader.py
Normal file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3.9
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
JFinal ProxyClassLoader - Dynamic Proxy Class Loader
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import sys
|
||||
from typing import Dict, Optional, Type
|
||||
from .ProxyClass import ProxyClass
|
||||
|
||||
class ProxyClassLoader:
|
||||
"""Dynamic proxy class loader"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize proxy class loader"""
|
||||
self._byte_code_map: Dict[str, bytes] = {}
|
||||
|
||||
def load_proxy_class(self, proxy_class: ProxyClass) -> Type:
|
||||
"""
|
||||
Load proxy class from byte code
|
||||
|
||||
Args:
|
||||
proxyClass: ProxyClass object with byte code
|
||||
|
||||
Returns:
|
||||
Loaded proxy class
|
||||
"""
|
||||
# Add byte code to map
|
||||
if proxy_class.byte_code:
|
||||
for class_name, byte_code in proxy_class.byte_code.items():
|
||||
if class_name not in self._byte_code_map:
|
||||
self._byte_code_map[class_name] = byte_code
|
||||
|
||||
# Try to load the class
|
||||
class_name = proxy_class.full_name
|
||||
|
||||
# Check if already loaded
|
||||
if class_name in sys.modules:
|
||||
return sys.modules[class_name]
|
||||
|
||||
try:
|
||||
# For Python, we'll use dynamic import
|
||||
# In a real implementation, this would use importlib or similar
|
||||
loaded_class = self._dynamic_import(class_name, proxy_class)
|
||||
return loaded_class
|
||||
except (ImportError, AttributeError) as e:
|
||||
raise RuntimeError(f"Error loading proxy class {class_name}: {e}")
|
||||
|
||||
def _dynamic_import(self, class_name: str, proxy_class: ProxyClass) -> Type:
|
||||
"""
|
||||
Dynamically import and create class from proxy class
|
||||
|
||||
Args:
|
||||
class_name: Full class name
|
||||
proxyClass: ProxyClass object
|
||||
|
||||
Returns:
|
||||
Dynamically created class
|
||||
"""
|
||||
# In Python, we can execute the source code and get the class
|
||||
if proxy_class.source_code:
|
||||
# Create a module
|
||||
module_name = proxy_class.pkg
|
||||
module_code = proxy_class.source_code
|
||||
|
||||
# Execute the code in a new namespace
|
||||
namespace = {}
|
||||
try:
|
||||
exec(module_code, namespace)
|
||||
|
||||
# Find the class in the namespace
|
||||
for name, obj in namespace.items():
|
||||
if isinstance(obj, type) and name == proxy_class.name:
|
||||
return obj
|
||||
|
||||
raise RuntimeError(f"Class {proxy_class.name} not found in generated code")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Error executing generated code: {e}")
|
||||
else:
|
||||
raise RuntimeError("No source code available for proxy class")
|
||||
|
||||
def find_class(self, name: str) -> Optional[bytes]:
|
||||
"""
|
||||
Find class byte code by name
|
||||
|
||||
Args:
|
||||
name: Full class name
|
||||
|
||||
Returns:
|
||||
Byte code or None if not found
|
||||
"""
|
||||
return self._byte_code_map.get(name)
|
||||
|
||||
def add_byte_code(self, name: str, byte_code: bytes):
|
||||
"""
|
||||
Add byte code to the loader
|
||||
|
||||
Args:
|
||||
name: Full class name
|
||||
byte_code: Class byte code
|
||||
"""
|
||||
self._byte_code_map[name] = byte_code
|
||||
|
||||
def remove_byte_code(self, name: str) -> Optional[bytes]:
|
||||
"""
|
||||
Remove and return byte code
|
||||
|
||||
Args:
|
||||
name: Full class name
|
||||
|
||||
Returns:
|
||||
Removed byte code or None
|
||||
"""
|
||||
return self._byte_code_map.pop(name, None)
|
||||
|
||||
def clear(self):
|
||||
"""Clear all cached byte code"""
|
||||
self._byte_code_map.clear()
|
||||
|
||||
@property
|
||||
def byte_code_count(self) -> int:
|
||||
"""Get number of cached byte codes"""
|
||||
return len(self._byte_code_map)
|
||||
143
proxy/ProxyCompiler.py
Normal file
143
proxy/ProxyCompiler.py
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3.9
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
JFinal ProxyCompiler - Dynamic Proxy Compiler
|
||||
"""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import subprocess
|
||||
import hashlib
|
||||
from typing import Dict, Optional, List, Tuple
|
||||
from .ProxyClass import ProxyClass
|
||||
from .ProxyClassLoader import ProxyClassLoader
|
||||
|
||||
class ProxyCompiler:
|
||||
"""Dynamic proxy compiler"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize proxy compiler"""
|
||||
self._class_loader = ProxyClassLoader()
|
||||
self._compile_options: List[str] = []
|
||||
|
||||
def compile(self, proxy_class: ProxyClass):
|
||||
"""
|
||||
Compile proxy class source code to byte code
|
||||
|
||||
Args:
|
||||
proxyClass: ProxyClass object with source code
|
||||
"""
|
||||
if not proxy_class.source_code:
|
||||
raise ValueError("Proxy class source code is not set")
|
||||
|
||||
try:
|
||||
# Generate byte code by compiling Python source
|
||||
byte_code = self._compile_python_source(proxy_class)
|
||||
|
||||
# Set the byte code
|
||||
proxy_class.byte_code = {
|
||||
proxy_class.full_name: byte_code
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Error compiling proxy class: {e}")
|
||||
|
||||
def _compile_python_source(self, proxy_class: ProxyClass) -> bytes:
|
||||
"""
|
||||
Compile Python source code to bytecode
|
||||
|
||||
Args:
|
||||
proxyClass: ProxyClass with source code
|
||||
|
||||
Returns:
|
||||
Compiled bytecode
|
||||
"""
|
||||
# Method 1: Use compile() and exec()
|
||||
try:
|
||||
# Compile the source code
|
||||
compiled = compile(proxy_class.source_code, proxy_class.name, 'exec')
|
||||
|
||||
# Create a namespace and execute
|
||||
namespace = {}
|
||||
exec(compiled, namespace)
|
||||
|
||||
# For Python, bytecode is already loaded in the namespace
|
||||
# Return dummy byte code since Python doesn't have traditional bytecode like Java
|
||||
return b'PYTHON_PROXY_CLASS'
|
||||
|
||||
except SyntaxError as e:
|
||||
raise RuntimeError(f"Syntax error in generated code: {e}")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Error compiling Python source: {e}")
|
||||
|
||||
def set_compile_options(self, options: List[str]) -> 'ProxyCompiler':
|
||||
"""
|
||||
Set compile options
|
||||
|
||||
Args:
|
||||
options: List of compiler options
|
||||
|
||||
Returns:
|
||||
Self for chaining
|
||||
"""
|
||||
self._compile_options = options.copy()
|
||||
return self
|
||||
|
||||
def add_compile_option(self, option: str) -> 'ProxyCompiler':
|
||||
"""
|
||||
Add single compile option
|
||||
|
||||
Args:
|
||||
option: Compiler option
|
||||
|
||||
Returns:
|
||||
Self for chaining
|
||||
"""
|
||||
if option:
|
||||
self._compile_options.append(option)
|
||||
return self
|
||||
|
||||
def get_class_loader(self) -> ProxyClassLoader:
|
||||
"""Get associated class loader"""
|
||||
return self._class_loader
|
||||
|
||||
def compile_and_load(self, proxy_class: ProxyClass) -> type:
|
||||
"""
|
||||
Compile proxy class and load the resulting class
|
||||
|
||||
Args:
|
||||
proxyClass: ProxyClass with source code
|
||||
|
||||
Returns:
|
||||
Loaded proxy class
|
||||
"""
|
||||
# Compile
|
||||
self.compile(proxy_class)
|
||||
|
||||
# Load
|
||||
return self._class_loader.load_proxy_class(proxy_class)
|
||||
|
||||
|
||||
class JavaProxyCompiler:
|
||||
"""Compiler for Java proxy classes (for Jython compatibility)"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize Java proxy compiler"""
|
||||
self._options: List[str] = []
|
||||
|
||||
def compile(self, proxy_class: ProxyClass):
|
||||
"""Compile Java proxy class"""
|
||||
# This would use javax.tools.JavaCompiler in Java version
|
||||
# For Python, we provide a stub implementation
|
||||
pass
|
||||
|
||||
def set_options(self, options: List[str]) -> 'JavaProxyCompiler':
|
||||
"""Set compiler options"""
|
||||
self._options = options.copy()
|
||||
return self
|
||||
|
||||
def add_option(self, option: str) -> 'JavaProxyCompiler':
|
||||
"""Add compiler option"""
|
||||
if option:
|
||||
self._options.append(option)
|
||||
return self
|
||||
Reference in New Issue
Block a user