调整版本并做测试

This commit is contained in:
2026-02-27 17:10:54 +08:00
parent fa673138f6
commit 31be9d0e97
77 changed files with 679 additions and 25 deletions

View 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})"

View 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)

View 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