void setFunction(String name, Function.SuperGetFunction func,
}
public void setFunction(IFunctionEntry functionEntry){
- if(functionEntry.owner() != this)
- throw new IllegalHandleException("function owner pool must equal added pool");
-
funcPool.computeIfAbsent(functionEntry.getName(), e -> new HashMap<>()).put(functionEntry.getType(), functionEntry);
}
diff --git a/src/main/java/dynamilize/Demodulator.java b/src/main/java/dynamilize/Demodulator.java
new file mode 100644
index 0000000..2666ab3
--- /dev/null
+++ b/src/main/java/dynamilize/Demodulator.java
@@ -0,0 +1,89 @@
+package dynamilize;
+
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+/**反模块化工具, 仅提供了一个主要方法{@link Demodulator#makeModuleOpen(Module, Package, Module)}用于强制对需要的模块开放模块的软件包。
+ * 此类行为可能完全打破模块化的访问保护,本身是不安全的,若不是必要情况,请尽量避免使用该类
+ *
此类仅在JDK9之后可用,避免在更早的版本引用此类的方法,且此类仅在desktop平台可用,安卓平台不可使用此类的任何行为*/
+@SuppressWarnings({"unchecked"})
+public class Demodulator{
+ private static final long fieldFilterOffset = 112L;
+
+ private static final Unsafe unsafe;
+
+ static{
+ try{
+ Constructor cstr = Unsafe.class.getDeclaredConstructor();
+ cstr.setAccessible(true);
+ unsafe = cstr.newInstance();
+
+ ensureFieldOpen();
+ }catch(NoSuchMethodException|InstantiationException|IllegalAccessException|InvocationTargetException e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void makeModuleOpen(Module from, Class> clazz, Module to){
+ if (clazz.isArray()){
+ makeModuleOpen(from, clazz.getComponentType(), to);
+ }
+ else makeModuleOpen(from, clazz.getPackage(), to);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void makeModuleOpen(Module from, Package pac, Module to){
+ if(checkModuleOpen(from, pac, to)) return;
+
+ try{
+ Field opensField = Module.class.getDeclaredField("openPackages");
+ Map> opensMap = (Map>) unsafe.getObjectVolatile(from, unsafe.objectFieldOffset(opensField));
+ if(opensMap == null){
+ opensMap = new HashMap<>();
+ unsafe.putObjectVolatile(from, unsafe.objectFieldOffset(opensField), opensMap);
+ }
+
+ Set opens = opensMap.computeIfAbsent(pac.getName(), e -> new HashSet<>());
+ try{
+ opens.add(to);
+ }catch(UnsupportedOperationException e){
+ ArrayList lis = new ArrayList<>(opens);
+ lis.add(to);
+ opensMap.put(pac.getName(), new HashSet<>(lis));
+ }
+ }catch(NoSuchFieldException e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static boolean checkModuleOpen(Module from, Package pac, Module to){
+ Objects.requireNonNull(from);
+ Objects.requireNonNull(to);
+
+ if(pac == null) return true;
+
+ return from.isOpen(pac.getName(), to);
+ }
+
+ public static boolean checkAndMakeModuleOpen(Module from, Package pac, Module to){
+ if(!checkModuleOpen(from, pac, to)){
+ makeModuleOpen(from, pac, to);
+ return false;
+ }
+ return true;
+ }
+
+ public static void ensureFieldOpen(){
+ try{
+ Class> clazz = Class.forName("jdk.internal.reflect.Reflection");
+ Map, Set> map = (Map, Set>) unsafe.getObject(clazz, fieldFilterOffset);
+ map.clear();
+ }catch(ClassNotFoundException e){
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/dynamilize/DynamicClass.java b/src/main/java/dynamilize/DynamicClass.java
index 4a89856..6ba7b5e 100644
--- a/src/main/java/dynamilize/DynamicClass.java
+++ b/src/main/java/dynamilize/DynamicClass.java
@@ -16,7 +16,7 @@
* 当动态类的超类的方法行为发生变更时,若类的行为中引用了超类方法,则类的行为会随之改变
* 仅在动态对象的方法来自动态类描述的行为时,上述变更才会生效
*
- *
描述动态类的行为需要{@linkplain DynamicClass#visitClass(Class) 行为样版}或者函数表达式,以增量模式编辑类型行为,方法和默认变量只能新增/变更,不可删除
+ *
描述动态类的行为需要{@linkplain DynamicClass#visitClass(Class,JavaHandleHelper) 行为样版}或者函数表达式,以增量模式编辑类型行为,方法和默认变量只能新增/变更,不可删除
*
{@code
* 下面是一个简单的样例:
* public class Template{
@@ -28,24 +28,16 @@
* }
*
* 引用:
+ * DynamicMaker maker = DynamicMaker.getDefault();
* DynamicClass dyClass = DynamicClass.get("Sample");
- * dyClass.visitClass(Template.class);
- * DynamicObject dyObject = DynamicMaker.getDefault().newInstance(dyClass);
+ * dyClass.visitClass(Template.class, maker.getHelper());
+ * DynamicObject dyObject = maker.newInstance(dyClass);
* dyObject.invokeFunc("method", "str");
*
* >>> string0
* }
*
- *
- * 注意,动态类型的行为变更是有时效的,这遵循以下规则:
- *
- * - 在一个动态对象被创建之前的所有对动态类型的变更,都对新创建的动态对象有效
- *
- 对于一个已被创建的动态对象,在动态类型中声明新的函数和变量,以及修改动态类型中的变量初始值都不会对已存在的对象产生直接影响
- *
- 对于一个已被创建的动态对象,若它的某一函数没有通过对象的{@link DynamicObject#setFunc(String, Function, Class[])}方法变更,则对动态类型的此方法进行变更将会改变这个对象的该函数行为
- *
- 若一个已存在的动态对象的某一函数已经被{@link DynamicObject#setFunc(String, Function, Class[])}方法变更,则其动态类型的行为变更对该对象的此函数行为没有直接影响
- *
- 对象的变量初始值只和被创建时有关,比如对于变量的样版,变量初始值或者初始值函数只和被创建时,该字段的值或函数有关;对于函数,变量初始值的函数只在被创建时调用并返回值。
- *
- *
+ * 动态类型声明的变量初始值只在对象被创建时有效,任何时候改变类的变量初始值都不会对已有实例造成影响
*
* @see DynamicMaker#newInstance(Class, Class[], DynamicClass, Object...)
* @see DynamicMaker#newInstance(DynamicClass)
@@ -177,7 +169,7 @@ public IVariable[] getVariables(){
*
* 如果模板里存在不希望被作为样版的字段或者方法,你可以使用{@link Exclude}注解标记此目标以排除。
* 所有描述动态类行为的方法和变量都必须具有public static修饰符*/
- public void visitClass(Class> template){
+ public void visitClass(Class> template, JavaHandleHelper helper){
checkFinalized();
for(Method method: template.getDeclaredMethods()){
@@ -185,7 +177,7 @@ public void visitClass(Class> template){
if(!Modifier.isStatic(method.getModifiers()) || !Modifier.isPublic(method.getModifiers())) continue;
- data.setFunction(new JavaMethodEntry(method, data));
+ data.setFunction(helper.genJavaMethodRef(method, data));
}
for(Field field: template.getDeclaredFields()){
@@ -197,19 +189,19 @@ public void visitClass(Class> template){
}
}
- /**访问一个方法样版,不同于{@link DynamicClass#visitClass(Class)},此方法只访问一个单独的方法并创建其行为样版。
- *
关于此方法的具体行为,请参阅访问行为样版类型的{@linkplain DynamicClass#visitClass(Class) 方法部分}
+ /**访问一个方法样版,不同于{@link DynamicClass#visitClass(Class,JavaHandleHelper)},此方法只访问一个单独的方法并创建其行为样版。
+ *
关于此方法的具体行为,请参阅访问行为样版类型的{@linkplain DynamicClass#visitClass(Class,JavaHandleHelper) 方法部分}
*
* @param method 访问的方法样版*/
- public void visitMethod(Method method){
+ public void visitMethod(Method method, JavaHandleHelper helper){
if(!Modifier.isStatic(method.getModifiers()) || !Modifier.isPublic(method.getModifiers()))
throw new IllegalHandleException("method template must be public and static");
- data.setFunction(new JavaMethodEntry(method, data));
+ data.setFunction(helper.genJavaMethodRef(method, data));
}
- /**访问一个字段样版,不同于{@link DynamicClass#visitClass(Class)},此方法只访问一个单独的字段并创建其行为样版。
- *
关于此方法的具体行为,请参阅访问行为样版类型的{@linkplain DynamicClass#visitClass(Class) 字段部分}
+ /**访问一个字段样版,不同于{@link DynamicClass#visitClass(Class,JavaHandleHelper)},此方法只访问一个单独的字段并创建其行为样版。
+ *
关于此方法的具体行为,请参阅访问行为样版类型的{@linkplain DynamicClass#visitClass(Class,JavaHandleHelper) 字段部分}
*
* @param field 访问的字段样版*/
public void visitField(Field field){
@@ -219,7 +211,7 @@ public void visitField(Field field){
setVariableWithField(field);
}
- /**以lambda模式设置函数,使用匿名函数描述类型行为,对类型行为变更的效果与{@link DynamicClass#visitClass(Class)}的方法部分相同
+ /**以lambda模式设置函数,使用匿名函数描述类型行为,对类型行为变更的效果与{@link DynamicClass#visitClass(Class,JavaHandleHelper)}的方法部分相同
*
* @param name 函数名称
* @param func 描述函数行为的匿名函数
@@ -248,7 +240,7 @@ public void setFunction(String name, Function.NonRetSuperGetFunc func, Cl
}, argTypes);
}
- /**常量模式设置变量初始值,行为与{@link DynamicClass#visitClass(Class)}字段部分相同
+ /**常量模式设置变量初始值,行为与{@link DynamicClass#visitClass(Class,JavaHandleHelper)}字段部分相同
*
* @param name 变量名称
* @param value 常量值
@@ -257,7 +249,7 @@ public void setVariable(String name, Object value, boolean isConst){
setVariable(name, () -> value, isConst);
}
- /**函数模式设置变量初始化工厂,行为与{@link DynamicClass#visitClass(Class)}字段部分相同
+ /**函数模式设置变量初始化工厂,行为与{@link DynamicClass#visitClass(Class,JavaHandleHelper)}字段部分相同
*
* @param name 变量名称
* @param prov 生产变量初始值的工厂函数
diff --git a/src/main/java/dynamilize/DynamicMaker.java b/src/main/java/dynamilize/DynamicMaker.java
index 9df7070..21fd0c3 100644
--- a/src/main/java/dynamilize/DynamicMaker.java
+++ b/src/main/java/dynamilize/DynamicMaker.java
@@ -115,7 +115,26 @@ public static DynamicMaker getDefault(){
BaseClassLoader loader = new BaseClassLoader(DynamicMaker.class.getClassLoader());
ASMGenerator generator = new ASMGenerator(loader, Opcodes.V1_8);
- return new DynamicMaker(acc -> acc.setAccessible(true)){
+ return new DynamicMaker(new JavaHandleHelper() {
+ @Override
+ public IVariable genJavaVariableRef(Field field, DataPool targetPool) {
+ Demodulator.makeModuleOpen(field.getType().getModule(), field.getType(), DynamicMaker.class.getModule());
+ field.setAccessible(true);
+ return new JavaVariable(field);
+ }
+
+ @Override
+ public IFunctionEntry genJavaMethodRef(Method method, DataPool targetPool) {
+ Demodulator.makeModuleOpen(method.getReturnType().getModule(), method.getReturnType(), DynamicMaker.class.getModule());
+
+ for (Class> type : method.getParameterTypes()) {
+ Demodulator.makeModuleOpen(type.getModule(), type, DynamicMaker.class.getModule());
+ }
+
+ method.setAccessible(true);
+ return new JavaMethodEntry(method, targetPool);
+ }
+ }){
@Override
protected Class extends T> generateClass(Class baseClass, Class>[] interfaces){
return makeClassInfo(baseClass, interfaces).generate(generator);
@@ -267,8 +286,7 @@ public void setVariable(IVariable var){
for(Field field: curr.getDeclaredFields()){
if(Modifier.isStatic(field.getModifiers()) || isInternalField(field.getName())) continue;
- helper.setAccess(field);
- res.setVariable(new JavaVariable(field));
+ res.setVariable(helper.genJavaVariableRef(field, res));
}
curr = curr.getSuperclass();
}
@@ -685,7 +703,7 @@ protected ClassInfo extends T> makeClassInfo(Class baseClass, Class>[
// super(*parameters*);
// this.$superbasepointer$ = $datapool$.getReader(this);
//
- // this.$datapool$.init(*parameters*);
+ // this.$datapool$.init(this, *parameters*);
// }
for(Constructor> cstr: baseClass.getDeclaredConstructors()){
if((cstr.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) continue;
diff --git a/src/main/java/dynamilize/DynamicObject.java b/src/main/java/dynamilize/DynamicObject.java
index b83623b..074c75c 100644
--- a/src/main/java/dynamilize/DynamicObject.java
+++ b/src/main/java/dynamilize/DynamicObject.java
@@ -146,7 +146,7 @@ default R invokeFunc(String name, Object... args){
return r;
}
- /**指明形式参数列表执行对象的指定成员函数,如果参数中有从类型分配的对象或者null值,使用type明确指定形参类型可以有效提升执行效率
+ /**指明形式参数列表执行对象的指定成员函数,如果参数中有从类型派生的对象或者null值,使用type明确指定形参类型可以有效提升执行效率
*
* @param name 函数名称
* @param args 传递给函数的实参列表
@@ -173,7 +173,8 @@ default R invokeFunc(String name, ArgumentList args){
return res.invoke( this, args);
}
- default T self(){
+ /**将对象自身经过一次强转换并返回,请勿重写此方法的行为,这个方法仅为方便使用而设计,没有规范认为使用动态对象需要此方法获得实例*/
+ default T objSelf(){
return (T) this;
}
}
diff --git a/src/main/java/dynamilize/FunctionEntry.java b/src/main/java/dynamilize/FunctionEntry.java
index 05dc4b5..0230c34 100644
--- a/src/main/java/dynamilize/FunctionEntry.java
+++ b/src/main/java/dynamilize/FunctionEntry.java
@@ -5,14 +5,12 @@ public class FunctionEntry implements IFunctionEntry{
private final boolean modifiable;
private final Function func;
private final FunctionType type;
- private final DataPool owner;
- public FunctionEntry(String name, boolean modifiable, Function func, FunctionType type, DataPool owner){
+ public FunctionEntry(String name, boolean modifiable, Function func, FunctionType type){
this.name = name;
this.modifiable = modifiable;
this.func = func;
this.type = type;
- this.owner = owner;
}
public FunctionEntry(String name, boolean modifiable, Function.SuperGetFunction func, FunctionType type, DataPool owner){
@@ -25,8 +23,7 @@ public FunctionEntry(String name, boolean modifiable, Function.SuperGetFunction<
p.recycle();
return res;
},
- type,
- owner
+ type
);
}
@@ -40,11 +37,6 @@ public boolean modifiable(){
return modifiable;
}
- @Override
- public DataPool owner(){
- return owner;
- }
-
@Override
@SuppressWarnings("unchecked")
public Function getFunction(){
diff --git a/src/main/java/dynamilize/FunctionType.java b/src/main/java/dynamilize/FunctionType.java
index 50af45a..bd44ff2 100644
--- a/src/main/java/dynamilize/FunctionType.java
+++ b/src/main/java/dynamilize/FunctionType.java
@@ -10,7 +10,8 @@
import java.util.Stack;
public class FunctionType{
- public static int MAX_RECYCLE = 2048;
+ /**复用回收区容量,改数值通常不需要设置,但如果您可能需要大规模的递归或大量的并发调用,那么您可能需要将这个限制设置为一个更高的数值*/
+ public static int MAX_RECYCLE = 4096;
private static final Class>[] EMPTY = new Class[0];
private static final Stack RECYCLE_POOL = new Stack<>();
diff --git a/src/main/java/dynamilize/IFunctionEntry.java b/src/main/java/dynamilize/IFunctionEntry.java
index 4987103..e725d38 100644
--- a/src/main/java/dynamilize/IFunctionEntry.java
+++ b/src/main/java/dynamilize/IFunctionEntry.java
@@ -11,9 +11,6 @@ public interface IFunctionEntry{
*/
boolean modifiable();
- /**获取此入口所在的池*/
- DataPool owner();
-
/**
* 获取此方法入口定义的引用匿名函数
*/
diff --git a/src/main/java/dynamilize/JavaHandleHelper.java b/src/main/java/dynamilize/JavaHandleHelper.java
index e32295a..dbb9694 100644
--- a/src/main/java/dynamilize/JavaHandleHelper.java
+++ b/src/main/java/dynamilize/JavaHandleHelper.java
@@ -1,13 +1,14 @@
package dynamilize;
-import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
/**出于jdk16+进一步升级的模块化管理以及跨平台和跨版本考虑,提供java基本行为的平台支持器,这包含了一些与版本/平台有关的行为接口。
* 实施时应当按方法的功能说明针对运行平台进行实现。
*
* @author EBwilson */
public interface JavaHandleHelper{
- /**设置访问检查对象的可访问状态为true,jdk16以后{@link AccessibleObject#setAccessible(boolean)}具有模块open检查,
- * 此方法需要额外进行反模块化实现后再设置访问许可。*/
- void setAccess(AccessibleObject object);
+ IVariable genJavaVariableRef(Field field, DataPool targetPool);
+
+ IFunctionEntry genJavaMethodRef(Method method, DataPool targetPool);
}
diff --git a/src/main/java/dynamilize/JavaMethodEntry.java b/src/main/java/dynamilize/JavaMethodEntry.java
index 634733f..832d412 100644
--- a/src/main/java/dynamilize/JavaMethodEntry.java
+++ b/src/main/java/dynamilize/JavaMethodEntry.java
@@ -10,7 +10,7 @@
import java.lang.reflect.Parameter;
import java.util.ArrayList;
-/**对{@linkplain DynamicClass#visitClass(Class) 行为样版}中方法描述的入口,在动态类中描述子实例的某一函数行为。
+/**对{@linkplain DynamicClass#visitClass(Class, JavaHandleHelper) 行为样版}中方法描述的入口,在动态类中描述子实例的某一函数行为。
*
方法入口的运行实际上是对样版方法的引用,因此需要确保样版方法所在的类始终有效,方法入口会生成这个方法的入口函数提供给动态对象使用
*
* @author EBwilson */
@@ -21,7 +21,6 @@ public class JavaMethodEntry implements IFunctionEntry{
private final Function, ?> defFunc;
private final boolean isFinal;
- private final DataPool owner;
/**直接通过目标方法创建方法入口,并生成对方法引用的句柄提供给匿名函数以描述此函数行为
*
@@ -29,13 +28,12 @@ public class JavaMethodEntry implements IFunctionEntry{
public JavaMethodEntry(Method invokeMethod, DataPool owner){
this.name = invokeMethod.getName();
this.isFinal = Modifier.isFinal(invokeMethod.getModifiers());
- this.owner = owner;
if(!Modifier.isStatic(invokeMethod.getModifiers()))
throw new IllegalHandleException("cannot assign a non-static method to function");
Parameter[] parameters = invokeMethod.getParameters();
- ArrayList arg = new ArrayList<>();
+ ArrayList> arg = new ArrayList<>();
boolean thisPointer = false, superPointer = false;
for(int i = 0; i < parameters.length; i++){
@@ -56,10 +54,10 @@ else if(param.getAnnotation(Super.class) != null){
superPointer = true;
}
- else arg.add(param);
+ else arg.add(param.getType());
}
- type = FunctionType.inst(FunctionType.toTypes(arg));
+ type = FunctionType.inst(arg);
boolean thisP = thisPointer;
boolean superP = superPointer;
@@ -79,7 +77,7 @@ else if(param.getAnnotation(Super.class) != null){
if(thisP && superP) realArgArr[1] = owner.getSuper(self, superPool = self.baseSuperPointer());
else if(!thisP && superP) realArgArr[0] = owner.getSuper(self, superPool = self.baseSuperPointer());
- if(argsArray.length != 0) System.arraycopy(argsArray, 0, realArgArr, offset, realArgArr.length);
+ if(argsArray.length != 0) System.arraycopy(argsArray, 0, realArgArr, offset, argsArray.length);
try{
Object res = call.invokeWithArguments(realArgArr);
@@ -105,11 +103,6 @@ public boolean modifiable(){
return !isFinal;
}
- @Override
- public DataPool owner(){
- return owner;
- }
-
@Override
public Function getFunction(){
return (Function) defFunc;
diff --git a/src/main/java/dynamilize/annotation/This.java b/src/main/java/dynamilize/annotation/This.java
index 0c4bf61..f0808b7 100644
--- a/src/main/java/dynamilize/annotation/This.java
+++ b/src/main/java/dynamilize/annotation/This.java
@@ -5,8 +5,8 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-/**this指针标记,用于{@link dynamilize.DynamicClass#visitClass(Class)}访问方法行为样版时,标记方法的第一个参数,
- * 被标记的参数在函数调用时,将作为this指针传递对象自身。此参素并不加入函数参数表匹配,请参见{@linkplain dynamilize.DynamicClass#visitClass(Class) 访问方法样版部分}
+/**this指针标记,用于{@link dynamilize.DynamicClass#visitClass(Class,dynamilize.JavaHandleHelper)}访问方法行为样版时,标记方法的第一个参数,
+ * 被标记的参数在函数调用时,将作为this指针传递对象自身。此参素并不加入函数参数表匹配,请参见{@linkplain dynamilize.DynamicClass#visitClass(Class, dynamilize.JavaHandleHelper) 访问方法样版部分}
* 尽管没有明确规定,但标记为this指针的参数应当是只读的(具备final修饰符)
*
* @author EBwilson */
diff --git a/src/test/java/HotUpdateDemo.java b/src/test/java/HotUpdateDemo.java
index 09e05d0..f6e269e 100644
--- a/src/test/java/HotUpdateDemo.java
+++ b/src/test/java/HotUpdateDemo.java
@@ -22,7 +22,7 @@ class World implements Module{
DynamicMaker maker = DynamicMaker.getDefault();
public Scene scene = new Scene();
- public Entities entities = maker.newInstance(Entities.class, HotUpdateDemo.Updater).self();
+ public Entities entities = maker.newInstance(Entities.class, HotUpdateDemo.Updater).objSelf();
@Override
public void update(){
diff --git a/src/test/java/ProxySample.java b/src/test/java/ProxySample.java
index 7e82c51..1e4af34 100644
--- a/src/test/java/ProxySample.java
+++ b/src/test/java/ProxySample.java
@@ -11,7 +11,7 @@ public class ProxySample{
});
public static void main(String[] args){
- ArrayList list = proxyMaker.newProxyInstance(ArrayList.class).self();
+ ArrayList list = proxyMaker.newProxyInstance(ArrayList.class).objSelf();
list.add("first element");
}
}
diff --git a/usage_sample/.gitignore b/usage_sample/.gitignore
new file mode 100644
index 0000000..b63da45
--- /dev/null
+++ b/usage_sample/.gitignore
@@ -0,0 +1,42 @@
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/usage_sample/build.gradle b/usage_sample/build.gradle
new file mode 100644
index 0000000..34095f8
--- /dev/null
+++ b/usage_sample/build.gradle
@@ -0,0 +1,18 @@
+plugins {
+ id 'java'
+}
+
+group = 'com.github.EB-wilson'
+version = '1.4-B1'
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation rootProject
+}
+
+test {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java b/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java
new file mode 100644
index 0000000..1e18014
--- /dev/null
+++ b/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java
@@ -0,0 +1,135 @@
+package com.github.ebwilson.sample;
+
+import dynamilize.*;
+import dynamilize.annotation.Super;
+import dynamilize.annotation.This;
+
+import java.util.Date;
+import java.util.HashMap;
+
+/**这是动态对象的基本使用示例,在下面给出了一个使用动态对象的工作流以向您演示动态对象和动态类型的基本使用方法
+ *
请首先阅读此案例并掌握动态类型及动态对象的基本使用方法后再阅读应用的案例*/
+public class BaseUse {
+ @SuppressWarnings("unchecked")
+ public static void main(String[] args) {
+ DynamicMaker maker = DynamicMaker.getDefault();//获取默认动态工厂
+ DynamicClass Sample = DynamicClass.get("Sample");//创建动态类型,这是必要的,无论动态类是否有行为,get方法会返回给定名称的动态类型,如果类型尚不存在则会创建一个新的动态类型
+
+ /*===============================
+ * 如下所示是动态对象的基本使用方法
+ * 该段落展示最基本的动态对象的行为操作
+ * ===============================*/
+
+ //使用动态工厂来实例化动态对象,注意,返回的目标已经具备了动态对象的一切行为
+ HashMap map = maker.newInstance(HashMap.class, Sample).objSelf();
+
+ //强转换为动态对象以调用行为,但实际上maker的newInstance方法创建返回的类型就是DynamicObject,objSelf()方法只是对对象this的一次强类型转换,此处因为泛型转换的问题没有直接使用返回的DynamicObject实例
+ DynamicObject> dyMap = (DynamicObject>) map;
+ //设置行为,对put方法进行监视:
+ dyMap.setFunc("put", (self, su, arg) -> {
+ su.invokeFunc("put", arg);//调用超方法,等价于super.put(key, value)
+
+ System.out.println("putting " + arg.get(0) + " -> " + arg.get(1));
+ }, Object.class, Object.class);//泛型擦除,对泛型参数的限定需使用类型参数的上界,此方法上界未定,即Object
+
+ //测试打印
+ map.put("a", "string 1");
+ map.put("b", "string 2");
+ map.put("c", "string 3");
+
+ System.out.println("===========sep line==========");
+
+ //对于动态对象,可以像脚本语言一样使用钩子函数:
+ Function, Object> hook = dyMap.getFunc("put", Object.class, Object.class);
+ dyMap.setFunc("put", (self, arg) -> {
+ hook.invoke(self, arg);//调用钩子
+ System.out.println("putting now, current entries amount: " + self.objSelf().size());
+ }, Object.class, Object.class);
+
+ //测试打印
+ map.put("d", "string 4");
+ map.put("e", "string 5");
+ map.put("f", "string 6");
+
+ System.out.println("===========sep line==========");
+
+ //您也可以用反射式的语句调用动态对象的方法:
+ System.out.println("reflectional invoke:");
+ dyMap.invokeFunc("put", "g", "string 7");
+
+ //当然,您也可以以类似的方式去操作对象的字段值:
+ System.out.println("current entries amount: " + dyMap.getVar("size"));
+
+ /*=======================================================
+ * 以上是动态对象上的基本操作,到这里您可能对动态类型的作用稍有疑惑
+ * 您将在这个段落了解到动态类型的用法及意义
+ * =======================================================*/
+
+ System.out.println("===========sep line==========");
+ //上面已经定义过一个动态类型Sample,直接使用它,首先给动态类型声明一个函数:
+ Sample.setFunction("put", (self, su, arg) -> {
+ System.out.println("Dynamic class instance handle:");
+ su.invokeFunc("put", arg);//这里的语义和对动态类型直接定义是一致的
+ }, Object.class, Object.class);
+
+ //测试打印,观察打印结果,可以发现调用的过程中最低层次的调用发生了变化
+ //其实,在动态对象中除部分方法对java方法的引用外,最低层的函数引用是指向动态类型的,只是这一层的默认行为是向上调用或者无行为
+ //因此,当你改变动态类型中描述的行为时,所有没有中断掉向上的引用的这个动态类型的实例,此方法的行为都会随之改变
+ map.put("i", "string 8");
+ map.put("j", "string 9");
+ map.put("k", "string 10");
+
+ System.out.println("===========sep line==========");
+
+ //同样的,如果新增函数
+ Sample.setFunction("putTime", (self, arg) -> {
+ System.out.println("current time: " + new Date());
+ self.invokeFunc("put", arg.get(0), new Date().toString());
+ }, String.class);
+ dyMap.invokeFunc("putTime", "currTime");
+
+ //从map中获取currTime,可见给动态类型设置的行为被同步到了它的实例当中
+ System.out.println("get time entry, res: " + map.get("currTime"));
+
+ System.out.println("===========sep line==========");
+
+ //当然,使用lambda为对象设置行为有些繁琐,为动态类型定义方法还有更为方便的形式
+ //在下方,我们定义了一个类型Template作为类型样板,在此使样板类型生效
+ Sample.visitClass(Template.class, maker.getHelper());
+
+ //测试打印
+ System.out.println("get: " + map.get("a"));
+ System.out.println("get: " + map.get("b"));
+ System.out.println("get: " + map.get("c"));
+
+ System.out.println("===========sep line==========");
+
+ //另外,动态类型也是可以被继承的,就像如下所示
+ DynamicClass SampleChild = DynamicClass.declare("SampleChild", Sample);
+ HashMap map1 = maker.newInstance(HashMap.class, SampleChild).objSelf();
+
+ SampleChild.setFunction("put", (self, su, arg) -> {
+ su.invokeFunc("put", arg);
+ System.out.println("current map: " + self);
+ }, Object.class, Object.class);
+
+ //测试打印,观察结果,对象从其超类继承了put方法的行为,而此类型定义的行为紧随之后执行,容易看出动态类型继承的行为和java本身的类继承行为非常相似
+ map1.put("abc", "extend sample 1");
+ map1.put("def", "extend sample 2");
+ map1.put("ghi", "extend sample 3");
+
+ //至此,关于动态类型的基本的使用方法说明就结束了,接下来会在案例中的其他文件中展示一些具体的应用,请首先将基本使用方法掌握后再阅读后续的案例
+ }
+
+ //使用java定义方法的模板,令对象直接从java类型中引用它的方法,使程序语义更清晰
+ static class Template{
+ //用于定义行为的方法必须是静态的,this指针通过第一个参数上添加@This注解传入,super则是第二个参数使用@Super注解,位置不可交换,但可以省略,譬如此处的self其实就是不必要的
+ //在this和super之后的参数配合方法的名称进行签名,这个例子的签名等价于 public Object get(Object key),会覆写map的行为
+
+ //另外,使用动态类型时,this指针的类型就是不确定的了,所以通常来说不指定它的泛型限定类,但对于只会用于一个合法的java类层次结构的动态类,你可以为它分配一个确切的类型以更方便的使用,
+ public static Object get(@This DynamicObject> self, @Super DataPool.ReadOnlyPool su, Object key){
+ System.out.println("getting entries, key: " + key);
+ return su.invokeFunc("get", key);//此处类型不确切,所以使用反射调用方法
+ }
+ }
+}
\ No newline at end of file
From 9e098650d8446fea6badb846766bacf5312fb4ff Mon Sep 17 00:00:00 2001
From: EB-wilson <77141581+EB-wilson@users.noreply.github.com>
Date: Sat, 13 May 2023 22:11:34 +0800
Subject: [PATCH 03/34] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 59f51d1..844b5ba 100644
--- a/README.md
+++ b/README.md
@@ -137,4 +137,4 @@
****
- 动态类型声明的变量初始值只在对象被创建时有效,任何时候改变类的变量初始值都不会对已有实例造成影响
-您可以参照项目中给出的一些使用[案例]()和javadoc了解更多关于这个仓库的使用方法。
+您可以参照项目中给出的一些使用[案例](https://github.com/EB-wilson/JavaDynamilizer/tree/master/usage_sample/src/main/java/com/github/ebwilson/sample)和javadoc了解更多关于这个仓库的使用方法。
From d69296195e0f9f45017452d5cd7f4dfb8ee1818f Mon Sep 17 00:00:00 2001
From: EBwilson <2534946881@qq.com>
Date: Sat, 13 May 2023 22:31:13 +0800
Subject: [PATCH 04/34] =?UTF-8?q?=E8=A1=A5=E5=85=85README.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 4 +++-
.../src/main/java/com/github/ebwilson/sample/README.md | 7 +++++++
2 files changed, 10 insertions(+), 1 deletion(-)
create mode 100644 usage_sample/src/main/java/com/github/ebwilson/sample/README.md
diff --git a/README.md b/README.md
index 844b5ba..681a663 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,8 @@
......
}
+> 当前这个项目还尚不成熟和健壮,需要更多的使用与建议来进一步完善和优化,如果您有能力还请不吝参与此框架的开发。
+
## 基本使用
创建一个最简单的动态实例,它委托自java类HashMap:
@@ -37,7 +39,7 @@
DynamicObject> dyObj = DynamicMaker.getDefault().newInstance(new Class[]{Map.class}, Demo);
Map, ?> map = (Map, ?>)dyObj;
-但是实现接口你必须使用`setFunc`方法对所有的接口抽象方法进行实现,否则对此方法的引用会抛出致命异常。
+但是在实现接口时,您必须使用`setFunc`方法来对所有的接口抽象方法进行实现,否则对此方法的引用会抛出致命异常。
## 动态类型
diff --git a/usage_sample/src/main/java/com/github/ebwilson/sample/README.md b/usage_sample/src/main/java/com/github/ebwilson/sample/README.md
new file mode 100644
index 0000000..b389fcb
--- /dev/null
+++ b/usage_sample/src/main/java/com/github/ebwilson/sample/README.md
@@ -0,0 +1,7 @@
+##案例
+---
+这里列出了JavaDynamilizer的使用参考样例,包括基本的特性及用法样例,AOP,反射框架,热修复等实例,并提供了自定义实现的案例指南,您可以通过阅读这些样例参考以更快的了解本框架的使用方法及功能和意义。
+
+在这个目录内存放的各个案例包内存放了关于JavaDynamilizer的一般应用时的代码,建议首先从[基本使用方法](https://github.com/EB-wilson/JavaDynamilizer/tree/master/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java)开始阅读,在了解了框架的基本使用方法之后再阅读应用。
+
+> 由于我个人对需求假设的能力较弱,此页面鼓励各位开发者提供更加优质的使用样本
\ No newline at end of file
From f070e4de98f38863b9a1b605633ad7aba9870cc5 Mon Sep 17 00:00:00 2001
From: EB-wilson <77141581+EB-wilson@users.noreply.github.com>
Date: Sat, 13 May 2023 22:32:04 +0800
Subject: [PATCH 05/34] Update README.md
---
.../src/main/java/com/github/ebwilson/sample/README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/usage_sample/src/main/java/com/github/ebwilson/sample/README.md b/usage_sample/src/main/java/com/github/ebwilson/sample/README.md
index b389fcb..bc5d67c 100644
--- a/usage_sample/src/main/java/com/github/ebwilson/sample/README.md
+++ b/usage_sample/src/main/java/com/github/ebwilson/sample/README.md
@@ -1,7 +1,7 @@
-##案例
+## 案例
---
这里列出了JavaDynamilizer的使用参考样例,包括基本的特性及用法样例,AOP,反射框架,热修复等实例,并提供了自定义实现的案例指南,您可以通过阅读这些样例参考以更快的了解本框架的使用方法及功能和意义。
在这个目录内存放的各个案例包内存放了关于JavaDynamilizer的一般应用时的代码,建议首先从[基本使用方法](https://github.com/EB-wilson/JavaDynamilizer/tree/master/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java)开始阅读,在了解了框架的基本使用方法之后再阅读应用。
-> 由于我个人对需求假设的能力较弱,此页面鼓励各位开发者提供更加优质的使用样本
\ No newline at end of file
+> 由于我个人对需求假设的能力较弱,此页面鼓励各位开发者提供更加优质的使用样本
From be3b652193f10d11018e6b599fdd8e728318f9b1 Mon Sep 17 00:00:00 2001
From: EB-wilson <77141581+eb-wilson@users.noreply.github.com>
Date: Sun, 14 May 2023 23:35:39 +0800
Subject: [PATCH 06/34] =?UTF-8?q?=E4=BF=AE=E5=A4=8DProxy=E4=B8=8A=E7=9A=84?=
=?UTF-8?q?=E9=80=BB=E8=BE=91=E9=94=99=E8=AF=AF=EF=BC=8C=E8=A1=A5=E5=85=85?=
=?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=8F=82=E8=80=83=E6=A0=B7=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/misc.xml | 2 +-
src/main/java/dynamilize/DynamicClass.java | 4 +-
src/main/java/dynamilize/DynamicMaker.java | 63 +++++---
.../java/dynamilize/JavaHandleHelper.java | 2 +
src/main/java/dynamilize/ProxyMaker.java | 152 ++++++------------
.../dynamilize/classmaker/ASMGenerator.java | 12 +-
.../com/github/ebwilson/sample/BaseUse.java | 12 +-
.../ebwilson/sample/aop/AspectUsage.java | 16 ++
.../ebwilson/sample/aop/ProxyUsage.java | 64 ++++++++
9 files changed, 197 insertions(+), 130 deletions(-)
create mode 100644 usage_sample/src/main/java/com/github/ebwilson/sample/aop/AspectUsage.java
create mode 100644 usage_sample/src/main/java/com/github/ebwilson/sample/aop/ProxyUsage.java
diff --git a/.idea/misc.xml b/.idea/misc.xml
index a4c702e..31edf08 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -16,7 +16,7 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/dynamilize/DynamicClass.java b/src/main/java/dynamilize/DynamicClass.java
index 6ba7b5e..94d731f 100644
--- a/src/main/java/dynamilize/DynamicClass.java
+++ b/src/main/java/dynamilize/DynamicClass.java
@@ -177,6 +177,7 @@ public void visitClass(Class> template, JavaHandleHelper helper){
if(!Modifier.isStatic(method.getModifiers()) || !Modifier.isPublic(method.getModifiers())) continue;
+ helper.makeAccess(method);
data.setFunction(helper.genJavaMethodRef(method, data));
}
@@ -197,6 +198,7 @@ public void visitMethod(Method method, JavaHandleHelper helper){
if(!Modifier.isStatic(method.getModifiers()) || !Modifier.isPublic(method.getModifiers()))
throw new IllegalHandleException("method template must be public and static");
+ helper.makeAccess(method);
data.setFunction(helper.genJavaMethodRef(method, data));
}
@@ -278,6 +280,6 @@ private void checkFinalized(){
@Override
public String toString(){
- return "dyC:" + name;
+ return "dynamic class:" + name;
}
}
diff --git a/src/main/java/dynamilize/DynamicMaker.java b/src/main/java/dynamilize/DynamicMaker.java
index 21fd0c3..39ec33a 100644
--- a/src/main/java/dynamilize/DynamicMaker.java
+++ b/src/main/java/dynamilize/DynamicMaker.java
@@ -116,22 +116,34 @@ public static DynamicMaker getDefault(){
ASMGenerator generator = new ASMGenerator(loader, Opcodes.V1_8);
return new DynamicMaker(new JavaHandleHelper() {
+ @Override
+ public void makeAccess(Object object) {
+ if (object instanceof Method method){
+ Demodulator.makeModuleOpen(method.getReturnType().getModule(), method.getReturnType(), DynamicMaker.class.getModule());
+
+ for (Class> type : method.getParameterTypes()) {
+ Demodulator.makeModuleOpen(type.getModule(), type, DynamicMaker.class.getModule());
+ }
+
+ method.setAccessible(true);
+ }
+ else if (object instanceof Field field){
+ Demodulator.makeModuleOpen(field.getType().getModule(), field.getType(), DynamicMaker.class.getModule());
+
+ field.setAccessible(true);
+ }
+ else if (object instanceof Class> clazz){
+ Demodulator.makeModuleOpen(clazz.getModule(), clazz.getPackage(), DynamicMaker.class.getModule());
+ }
+ }
+
@Override
public IVariable genJavaVariableRef(Field field, DataPool targetPool) {
- Demodulator.makeModuleOpen(field.getType().getModule(), field.getType(), DynamicMaker.class.getModule());
- field.setAccessible(true);
return new JavaVariable(field);
}
@Override
public IFunctionEntry genJavaMethodRef(Method method, DataPool targetPool) {
- Demodulator.makeModuleOpen(method.getReturnType().getModule(), method.getReturnType(), DynamicMaker.class.getModule());
-
- for (Class> type : method.getParameterTypes()) {
- Demodulator.makeModuleOpen(type.getModule(), type, DynamicMaker.class.getModule());
- }
-
- method.setAccessible(true);
return new JavaMethodEntry(method, targetPool);
}
}){
@@ -286,6 +298,7 @@ public void setVariable(IVariable var){
for(Field field: curr.getDeclaredFields()){
if(Modifier.isStatic(field.getModifiers()) || isInternalField(field.getName())) continue;
+ helper.makeAccess(field);
res.setVariable(helper.genJavaVariableRef(field, res));
}
curr = curr.getSuperclass();
@@ -309,7 +322,16 @@ private static boolean isInternalField(String name){
* @param interfaces 需要实现的接口列表*/
@SuppressWarnings("unchecked")
protected Class extends T> getDynamicBase(Class base, Class>[] interfaces){
- return (Class extends T>) classPool.computeIfAbsent(new ClassImplements<>(base, interfaces), e -> generateClass(base, interfaces));
+ return (Class extends T>) classPool.computeIfAbsent(new ClassImplements<>(base, interfaces), e -> {
+ Class> c = base;
+
+ while (c != null){
+ c = c.getSuperclass();
+ helper.makeAccess(c);
+ }
+
+ return generateClass(base, interfaces);
+ });
}
/**由基类与接口列表建立动态类的打包名称,打包名称具有唯一性(或者足够高的离散性,不应出现频繁的碰撞)和不变性
@@ -759,7 +781,6 @@ protected ClassInfo extends T> makeClassInfo(Class baseClass, Class>[
Stack> interfaceStack = new Stack<>();
HashMap> overrideMethods = new HashMap<>();
- HashMap> finalMethods = new HashMap<>();
Class> curr = baseClass;
@@ -775,17 +796,7 @@ protected ClassInfo extends T> makeClassInfo(Class baseClass, Class>[
typeClass = asType(curr);
for(Method method: curr.getDeclaredMethods()){
- // 如果方法是静态的,或者方法不对子类可见则不重写此方法
- if(Modifier.isStatic(method.getModifiers())) continue;
- if((method.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) continue;
-
- if(Modifier.isFinal(method.getModifiers())){
- finalMethods.computeIfAbsent(method.getName(), e -> new HashSet<>()).add(FunctionType.from(method));
- continue;
- }
-
- if(!overrideMethods.computeIfAbsent(method.getName(), e -> new HashSet<>()).add(FunctionType.from(method))
- || finalMethods.getOrDefault(method.getName(), EMP_MAP).contains(FunctionType.from(method))) continue;
+ if (!filterMethod(overrideMethods, method)) continue;
String methodName = method.getName();
ClassInfo> returnType = asType(method.getReturnType());
@@ -1145,6 +1156,14 @@ protected ClassInfo extends T> makeClassInfo(Class baseClass, Class>[
return classInfo;
}
+ private static boolean filterMethod(HashMap> overrideMethods, Method method) {
+ // 如果方法是静态的,或者方法不对子类可见则不重写此方法
+ if(Modifier.isStatic(method.getModifiers()) || Modifier.isFinal(method.getModifiers())) return false;
+ if((method.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) return false;
+
+ return overrideMethods.computeIfAbsent(method.getName(), e -> new HashSet<>()).add(FunctionType.from(method));
+ }
+
@SuppressWarnings("unchecked")
protected void makeSwitch(HashMap callSuperCaseMap, CodeBlock
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 5f72fd5..b886d72 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,10 @@ plugins {
apply plugin: 'maven-publish'
group 'com.github.EB-wilson'
-version '1.5-B1'
+version '1.6-A1'
+
+sourceCompatibility = 17
+targetCompatibility = 17
repositories {
mavenCentral()
@@ -38,19 +41,18 @@ allprojects{
tasks.withType(JavaCompile){
options.encoding = "UTF-8"
- sourceCompatibility = 17
- targetCompatibility = 9
-
options.fork = true
options.forkOptions.jvmArgs.addAll([
- "--add-opens", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
- "--add-opens", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
- "--add-opens", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
- "--add-opens", "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
- "--add-opens", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
- "--add-opens", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"
+ "--add-opens", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+ "--add-opens", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+ "--add-opens", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
+ "--add-opens", "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
+ "--add-opens", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-opens", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"
])
- options.compilerArgs.addAll(['--release', '9'])
+ options.compilerArgs.addAll([
+ "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"
+ ])
}
}
diff --git a/src/main/java/dynamilize/ClassImplements.java b/src/main/java/dynamilize/ClassImplements.java
index e44ed24..ed41901 100644
--- a/src/main/java/dynamilize/ClassImplements.java
+++ b/src/main/java/dynamilize/ClassImplements.java
@@ -3,6 +3,9 @@
import java.util.Arrays;
import java.util.Objects;
+/**保存类的超类及实现接口的容器,用于快速确认委托的构造类型
+ *
+ * @author EBwilson */
class ClassImplements{
final Class base;
final Class>[] interfaces;
diff --git a/src/main/java/dynamilize/Demodulator.java b/src/main/java/dynamilize/Demodulator.java
index 2666ab3..d52e95c 100644
--- a/src/main/java/dynamilize/Demodulator.java
+++ b/src/main/java/dynamilize/Demodulator.java
@@ -5,17 +5,25 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.*;
/**反模块化工具, 仅提供了一个主要方法{@link Demodulator#makeModuleOpen(Module, Package, Module)}用于强制对需要的模块开放模块的软件包。
* 此类行为可能完全打破模块化的访问保护,本身是不安全的,若不是必要情况,请尽量避免使用该类
- *
此类仅在JDK9之后可用,避免在更早的版本引用此类的方法,且此类仅在desktop平台可用,安卓平台不可使用此类的任何行为*/
+ *
此类仅在JDK9之后可用,避免在更早的版本引用此类的方法,且此类仅在desktop平台可用,安卓平台不可使用此类的任何行为
+ *
+ * @author EBwilson */
@SuppressWarnings({"unchecked"})
public class Demodulator{
private static final long fieldFilterOffset = 112L;
private static final Unsafe unsafe;
+ private static final Field opensField;
+ private static final Field exportField;
+
+ private static final Method exportNative;
+
static{
try{
Constructor cstr = Unsafe.class.getDeclaredConstructor();
@@ -23,7 +31,17 @@ public class Demodulator{
unsafe = cstr.newInstance();
ensureFieldOpen();
- }catch(NoSuchMethodException|InstantiationException|IllegalAccessException|InvocationTargetException e){
+
+ opensField = Module.class.getDeclaredField("openPackages");
+ exportField = Module.class.getDeclaredField("exportedPackages");
+
+ makeModuleOpen(Module.class.getModule(), "java.lang", Demodulator.class.getModule());
+
+ exportNative = Module.class.getDeclaredMethod("addExports0", Module.class, String.class, Module.class);
+ exportNative.setAccessible(true);
+ exportNative.invoke(null, Module.class.getModule(), "java.lang", Demodulator.class.getModule());
+ }catch(NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException |
+ NoSuchFieldException e){
throw new RuntimeException(e);
}
}
@@ -35,29 +53,50 @@ public static void makeModuleOpen(Module from, Class> clazz, Module to){
else makeModuleOpen(from, clazz.getPackage(), to);
}
- @SuppressWarnings("unchecked")
public static void makeModuleOpen(Module from, Package pac, Module to){
if(checkModuleOpen(from, pac, to)) return;
- try{
- Field opensField = Module.class.getDeclaredField("openPackages");
- Map> opensMap = (Map>) unsafe.getObjectVolatile(from, unsafe.objectFieldOffset(opensField));
- if(opensMap == null){
- opensMap = new HashMap<>();
- unsafe.putObjectVolatile(from, unsafe.objectFieldOffset(opensField), opensMap);
- }
-
- Set opens = opensMap.computeIfAbsent(pac.getName(), e -> new HashSet<>());
- try{
- opens.add(to);
- }catch(UnsupportedOperationException e){
- ArrayList lis = new ArrayList<>(opens);
- lis.add(to);
- opensMap.put(pac.getName(), new HashSet<>(lis));
- }
- }catch(NoSuchFieldException e){
+ makeModuleOpen(from, pac.getName(), to);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void makeModuleOpen(Module from, String pac, Module to){
+ try {
+ if (exportNative != null) exportNative.invoke(null, from, pac, to);
+ } catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
+
+ Map> opensMap = (Map>) unsafe.getObjectVolatile(from, unsafe.objectFieldOffset(opensField));
+ if(opensMap == null){
+ opensMap = new HashMap<>();
+ unsafe.putObjectVolatile(from, unsafe.objectFieldOffset(opensField), opensMap);
+ }
+
+ Map> exportsMap = (Map>) unsafe.getObjectVolatile(from, unsafe.objectFieldOffset(exportField));
+ if(exportsMap == null){
+ exportsMap = new HashMap<>();
+ unsafe.putObjectVolatile(from, unsafe.objectFieldOffset(exportField), exportsMap);
+ }
+
+ Set opens = opensMap.computeIfAbsent(pac, e -> new HashSet<>());
+ Set exports = exportsMap.computeIfAbsent(pac, e -> new HashSet<>());
+
+ try{
+ opens.add(to);
+ }catch(UnsupportedOperationException e){
+ ArrayList lis = new ArrayList<>(opens);
+ lis.add(to);
+ opensMap.put(pac, new HashSet<>(lis));
+ }
+
+ try{
+ exports.add(to);
+ }catch(UnsupportedOperationException e){
+ ArrayList lis = new ArrayList<>(exports);
+ lis.add(to);
+ exportsMap.put(pac, new HashSet<>(lis));
+ }
}
public static boolean checkModuleOpen(Module from, Package pac, Module to){
diff --git a/src/main/java/dynamilize/DynamicFactory.java b/src/main/java/dynamilize/DynamicFactory.java
new file mode 100644
index 0000000..533171a
--- /dev/null
+++ b/src/main/java/dynamilize/DynamicFactory.java
@@ -0,0 +1,155 @@
+package dynamilize;
+
+import dynamilize.classmaker.ASMGenerator;
+import dynamilize.classmaker.AbstractClassGenerator;
+import dynamilize.classmaker.BaseClassLoader;
+import dynamilize.classmaker.ByteClassLoader;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+/**用于创建{@linkplain DynamicMaker 动态生成器}的工厂类,内部提供了默认生成器的声明
+ *
+ * @author EBwilson
+ * @since 1.6*/
+public class DynamicFactory {
+ private PackageAccHandler handler;
+ private AbstractClassGenerator generator;
+ private JavaHandleHelper helper;
+
+ private static final DynamicFactory DEFAULT = new DynamicFactory(){{
+ setDefaultGenerator();
+ setDefaultHelper();
+ }};
+
+ /**直接获取默认的通用实现实例,该方法获取的动态生成器等价于:
+ * {@code
+ * new DynamicFactory().setDefaultGenerator().setDefaultHelper().getMaker();
+ * }
+ *
+ * @see DynamicFactory#setDefaultGenerator()
+ * @see DynamicFactory#setDefaultHelper()
+ * @return 一个由默认声明生产的动态生成器*/
+ public static DynamicMaker getDefault(){
+ return DEFAULT.getMaker();
+ }
+
+ /**获取{@linkplain DynamicMaker 动态生成器}实例
+ *
+ * @throws NullPointerException 若有必要的属性尚未设置*/
+ public DynamicMaker getMaker(){
+ PackageAccHandler handler = this.handler;
+
+ AbstractClassGenerator generator = this.generator;
+
+ Objects.requireNonNull(helper);
+ Objects.requireNonNull(generator);
+
+ return handler == null? new DynamicMaker(helper) {
+ @Override
+ protected Class extends T> generateClass(Class baseClass, Class>[] interfaces) {
+ return makeClassInfo(baseClass, interfaces).generate(generator);
+ }
+ }: new DynamicMaker(helper) {
+ @Override
+ protected Class extends T> generateClass(Class baseClass, Class>[] interfaces) {
+ return makeClassInfo(baseClass, interfaces).generate(generator);
+ }
+
+ @Override
+ protected Class extends T> handleBaseClass(Class baseClass) {
+ return handler.handle(baseClass);
+ }
+ };
+ }
+
+ /**设置{@linkplain PackageAccHandler 包私有访问处理器},若不设置则动态生成器不对超类的包私有方法进行委托
+ *
+ * @see PackageAccHandler*/
+ public DynamicFactory setPackageAccHandler(PackageAccHandler handler){
+ this.handler = handler;
+ return this;
+ }
+
+ /**设置将{@linkplain dynamilize.classmaker.ClassInfo 类型描述}生成为Java类对象的{@linkplain AbstractClassGenerator 类型生成器},必要!
+ *
+ * @see AbstractClassGenerator*/
+ public DynamicFactory setGenerator(AbstractClassGenerator generator){
+ this.generator = generator;
+ return this;
+ }
+
+ /**设置对Java层行为进行处理的{@linkplain JavaHandleHelper Java行为支持器},必要!
+ *
+ * @see JavaHandleHelper*/
+ public DynamicFactory setJavaHandleHelper(JavaHandleHelper helper){
+ this.helper = helper;
+ return this;
+ }
+
+ /**使用{@linkplain DynamicFactory#setDefaultGenerator(ByteClassLoader, int) 默认配置}设置类型生成器,字节码加载器使用默认实现{@link BaseClassLoader},目标字节码版本为152(Java1.8)
+ *
+ * @see DynamicFactory#setDefaultGenerator(ByteClassLoader, int)
+ * @see BaseClassLoader*/
+ public DynamicFactory setDefaultGenerator(){
+ return setDefaultGenerator(new BaseClassLoader(DynamicFactory.class.getClassLoader()), Opcodes.V1_8);
+ }
+
+ /**将类型生成器设置为{@link ASMGenerator}的实现,该实现适用于绝大多数情况的JVM
+ *
+ * @param loader 加载字节码为类对象的类加载器
+ * @param byteLevel 目标字节码级别,最低支持50(Java1.8)
+ *
+ * @see ASMGenerator*/
+ public DynamicFactory setDefaultGenerator(ByteClassLoader loader, int byteLevel){
+ if (byteLevel < 52 || byteLevel > 255)
+ throw new IllegalArgumentException("illegal byte code level: " + byteLevel);
+
+ generator = new ASMGenerator(loader, byteLevel);
+
+ return this;
+ }
+
+ /**设置{@link JavaHandleHelper}的默认内部实现,该实现直接引用{@link JavaVariable}和{@link JavaMethodEntry}以及默认的反模块化访问
+ *
+ * @see JavaVariable
+ * @see JavaMethodEntry*/
+ public DynamicFactory setDefaultHelper(){
+ helper = new JavaHandleHelper() {
+ @Override
+ public void makeAccess(Object object) {
+ if (object instanceof Method method){
+ Demodulator.makeModuleOpen(method.getReturnType().getModule(), method.getReturnType(), DynamicMaker.class.getModule());
+
+ for (Class> type : method.getParameterTypes()) {
+ Demodulator.makeModuleOpen(type.getModule(), type, DynamicMaker.class.getModule());
+ }
+
+ method.setAccessible(true);
+ }
+ else if (object instanceof Field field){
+ Demodulator.makeModuleOpen(field.getType().getModule(), field.getType(), DynamicMaker.class.getModule());
+
+ field.setAccessible(true);
+ }
+ else if (object instanceof Class> clazz){
+ Demodulator.makeModuleOpen(clazz.getModule(), clazz.getPackage(), DynamicMaker.class.getModule());
+ }
+ }
+
+ @Override
+ public IVariable genJavaVariableRef(Field field, DataPool targetPool) {
+ return new JavaVariable(field);
+ }
+
+ @Override
+ public IFunctionEntry genJavaMethodRef(Method method, DataPool targetPool) {
+ return new JavaMethodEntry(method, targetPool);
+ }
+ };
+
+ return this;
+ }
+}
diff --git a/src/main/java/dynamilize/DynamicMaker.java b/src/main/java/dynamilize/DynamicMaker.java
index 662d7c2..6449926 100644
--- a/src/main/java/dynamilize/DynamicMaker.java
+++ b/src/main/java/dynamilize/DynamicMaker.java
@@ -3,7 +3,6 @@
import dynamilize.classmaker.*;
import dynamilize.classmaker.code.*;
import dynamilize.classmaker.code.annotation.AnnotationType;
-import org.objectweb.asm.Opcodes;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -103,55 +102,14 @@ protected DynamicMaker(JavaHandleHelper helper){
this.helper = helper;
}
- /**获取默认的动态类型工厂,工厂具备基于{@link ASMGenerator}与适用于HotSpot JVM运行时的{@link JavaHandleHelper}进行的实现。
- * 适用于:
- *
- * - java运行时版本1.8的所有jvm
- *
- java运行时版本大于等于1.9的甲骨文HotSpot JVM
- *
- IBM OpenJ9运行时尚未支持
- *
- * 若有范围外的需求,可按需要进行实现*/
+ /**获取默认的动态类型工厂,工厂具备基于{@link ASMGenerator}与默认的{@link JavaHandleHelper}进行的实现。
+ * 若有范围外的需求,可按需要进行实现
+ *
+ * @deprecated DynamicMaker的预制创建已转移到DynamicFactory,此API将被移除
+ * @see DynamicFactory*/
+ @Deprecated
public static DynamicMaker getDefault(){
- BaseClassLoader loader = new BaseClassLoader(DynamicMaker.class.getClassLoader());
- ASMGenerator generator = new ASMGenerator(loader, Opcodes.V1_8);
-
- return new DynamicMaker(new JavaHandleHelper() {
- @Override
- public void makeAccess(Object object) {
- if (object instanceof Method method){
- Demodulator.makeModuleOpen(method.getReturnType().getModule(), method.getReturnType(), DynamicMaker.class.getModule());
-
- for (Class> type : method.getParameterTypes()) {
- Demodulator.makeModuleOpen(type.getModule(), type, DynamicMaker.class.getModule());
- }
-
- method.setAccessible(true);
- }
- else if (object instanceof Field field){
- Demodulator.makeModuleOpen(field.getType().getModule(), field.getType(), DynamicMaker.class.getModule());
-
- field.setAccessible(true);
- }
- else if (object instanceof Class> clazz){
- Demodulator.makeModuleOpen(clazz.getModule(), clazz.getPackage(), DynamicMaker.class.getModule());
- }
- }
-
- @Override
- public IVariable genJavaVariableRef(Field field, DataPool targetPool) {
- return new JavaVariable(field);
- }
-
- @Override
- public IFunctionEntry genJavaMethodRef(Method method, DataPool targetPool) {
- return new JavaMethodEntry(method, targetPool);
- }
- }){
- @Override
- protected Class extends T> generateClass(Class baseClass, Class>[] interfaces){
- return makeClassInfo(baseClass, interfaces).generate(generator);
- }
- };
+ return DynamicFactory.getDefault();
}
/**使用默认构造函数构造没有实现额外接口的动态类的实例,实例的java类型委托类为{@link Object}
@@ -238,6 +196,7 @@ public DynamicObject newInstance(Class base, Class>[] interfaces, Dy
}
}
+ /**获取此maker的{@linkplain JavaHandleHelper java行为支持器}*/
public JavaHandleHelper getHelper(){
return helper;
}
@@ -330,7 +289,7 @@ protected Class extends T> getDynamicBase(Class base, Class>[] interf
c = c.getSuperclass();
}
- return generateClass(base, interfaces);
+ return generateClass(handleBaseClass(base), interfaces);
});
}
@@ -1266,6 +1225,16 @@ protected void makeSwitch(HashMap callSuperCaseMap, CodeBlock具体来说,该映射在委托包私有方法时需要创建一串将包私有方法访问修饰符提升的类层次结构,分别去访问基类的各个超类所在包的保护域
+ *
默认的实现是非包私有委托的
+ *
+ * @param baseClass 进行动态委托的基类
+ * @return 对基类进行映射处理的类,默认情况下就是类本身*/
+ protected Class extends T> handleBaseClass(Class baseClass){
+ return baseClass;
+ }
+
/**生成委托自基类并实现了给出的接口列表的类型,而类的行为描述请参考{@link DynamicMaker#makeClassInfo(Class, Class[])},类型描述会在此方法产出。
* 该方法需要做的事通常是将makeClassInfo获得的类型标识进行生成并加载其表示的java类型
*
diff --git a/src/main/java/dynamilize/Func.java b/src/main/java/dynamilize/Func.java
index 0c3387a..8ce3381 100644
--- a/src/main/java/dynamilize/Func.java
+++ b/src/main/java/dynamilize/Func.java
@@ -1,5 +1,6 @@
package dynamilize;
+@FunctionalInterface
public interface Func{
R invoke(ArgumentList args);
diff --git a/src/main/java/dynamilize/FunctionType.java b/src/main/java/dynamilize/FunctionType.java
index bd44ff2..65f9853 100644
--- a/src/main/java/dynamilize/FunctionType.java
+++ b/src/main/java/dynamilize/FunctionType.java
@@ -9,6 +9,9 @@
import java.util.List;
import java.util.Stack;
+/**函数类型封装对象,记录函数的参数类型用于比对和搜索函数
+ *
+ * @author EBwilson */
public class FunctionType{
/**复用回收区容量,改数值通常不需要设置,但如果您可能需要大规模的递归或大量的并发调用,那么您可能需要将这个限制设置为一个更高的数值*/
public static int MAX_RECYCLE = 4096;
diff --git a/src/main/java/dynamilize/IFunctionEntry.java b/src/main/java/dynamilize/IFunctionEntry.java
index e725d38..79409f9 100644
--- a/src/main/java/dynamilize/IFunctionEntry.java
+++ b/src/main/java/dynamilize/IFunctionEntry.java
@@ -1,23 +1,15 @@
package dynamilize;
public interface IFunctionEntry{
- /**
- * 获取入口的名称
- */
+ /**获取入口的名称*/
String getName();
- /**
- * 此入口是否允许被替换
- */
+ /**此入口是否允许被替换*/
boolean modifiable();
- /**
- * 获取此方法入口定义的引用匿名函数
- */
+ /**获取此方法入口定义的引用匿名函数*/
Function getFunction();
- /**
- * 获取此方法的形式参数表类型
- */
+ /**获取此方法的形式参数表类型*/
FunctionType getType();
}
diff --git a/src/main/java/dynamilize/JavaVariable.java b/src/main/java/dynamilize/JavaVariable.java
index a223bda..ce4f1b4 100644
--- a/src/main/java/dynamilize/JavaVariable.java
+++ b/src/main/java/dynamilize/JavaVariable.java
@@ -5,6 +5,9 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+/**对java字段的引用对象,基于{@linkplain MethodHandle 方法句柄}的默认内部实现
+ *
+ * @author EBwilson */
@SuppressWarnings("unchecked")
public class JavaVariable implements IVariable{
private final Field field;
diff --git a/src/main/java/dynamilize/PackageAccHandler.java b/src/main/java/dynamilize/PackageAccHandler.java
new file mode 100644
index 0000000..8745994
--- /dev/null
+++ b/src/main/java/dynamilize/PackageAccHandler.java
@@ -0,0 +1,175 @@
+package dynamilize;
+
+import dynamilize.classmaker.ClassInfo;
+import dynamilize.classmaker.CodeBlock;
+import dynamilize.classmaker.Parameter;
+import dynamilize.classmaker.code.IClass;
+import dynamilize.classmaker.code.ILocal;
+import dynamilize.classmaker.code.IMethod;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**包私有方法访问提升使用的工具类,该类用于对一个目标类创建一串用于提升包私有方法的继承子树,以达到对包私有方法进行重写的目的
+ *
具体来说,将目标基类传入{@link PackageAccHandler#handle(Class)}方法以后,会依次检查此类型的,每一个父类型中是否存在包私有的方法,
+ * 若存在包私有方法,那么就会使用这个类的包名对上一层类型继承一次,通过{@link PackageAccHandler#loadClass(ClassInfo, Class)}将这个类加载到同一保护域,
+ * 此时,此次继承类型即可访问目标类包私有方法,重写并将其访问修饰符提升为{@code protected},如此完成对基类所有超类的遍历后即可访问所有该类层次结构中的包私有方法
+ *
+ * 直观的说,这个类做的事情如下:
+ *
{@code
+ * 假设有下面几个类:
+ *
+ * package pac1;
+ * public class A{
+ * void method1(){ //包私有方法
+ *
+ * }
+ *
+ * public void test(){
+ * method1();
+ * }
+ * }
+ *
+ * package pac2;
+ * import pac1.A;
+ * public class B extends A{
+ * void method2(){ //包私有方法
+ *
+ * }
+ *
+ * @Override
+ * public void test(){
+ * super.test();
+ * method2();
+ * }
+ * }
+ *
+ * 如果对handle方法传入B类,那么会创建如下两个类型:
+ *
+ * package pac2:
+ * public class B$packageAccess$0 extends B{
+ * @Override
+ * protected void method2(){
+ * super.method2();
+ * }
+ * }
+ *
+ * package pac1:
+ * import pac2.B$packageAccess$0;
+ * public class A$packageAccess$0 extends B$packageAccess$0{
+ * @Override
+ * protected void method1(){
+ * super.method2();
+ * }
+ * }
+ *
+ * 最后handle方法会将类对象pac1.A$packageAccess$0返回,此时,所有包私有方法都已被提升为protected,其子类对两个包私有方法的重写,在调用test方法时都会生效
+ * }
+ * 注意:以上所示的跨包继承同包类的方法重写实际上在java编译器中是不合法的,但在JVM当中此逻辑有效,上述代码仅作逻辑示意
+ *
+ * @author EBwilson
+ * @since 1.6*/
+@SuppressWarnings("unchecked")
+public abstract class PackageAccHandler {
+ public static final int PAC_PRI_FLAGS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
+ private final Map, Class>> classMap = new HashMap<>();
+
+ public Class extends T> handle(Class baseClass) {
+ return (Class extends T>) classMap.computeIfAbsent(baseClass, c -> {
+ Class> curr = c;
+ Class> opening = null;
+
+ while (curr != null) {
+ if (shouldOpen(curr)) {
+ ClassInfo> ci = makeClassInfo(opening == null ? ClassInfo.asType(curr) : ClassInfo.asType(opening), curr);
+ opening = loadClass(ci, curr);
+ }
+
+ curr = curr.getSuperclass();
+ }
+
+ return opening == null? c: opening;
+ });
+ }
+
+ protected boolean shouldOpen(Class> checking){
+ if (checking == Object.class) return false;
+
+ for (Method method : checking.getDeclaredMethods()) {
+ if ((method.getModifiers() & PAC_PRI_FLAGS) == 0){
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("rawtypes")
+ protected ClassInfo extends T> makeClassInfo(ClassInfo> superClass, Class> base){
+ ClassInfo> res = new ClassInfo<>(
+ Modifier.PUBLIC,
+ base.getName() + "$packageAccess$" + superClass.name().hashCode(),
+ superClass
+ );
+
+ ClassInfo> baseC = ClassInfo.asType(base);
+
+ for (Method method : base.getDeclaredMethods()) {
+ if ((method.getModifiers() & PAC_PRI_FLAGS) == 0){
+ IMethod, ?> sup = baseC.getMethod(
+ ClassInfo.asType(method.getReturnType()),
+ method.getName(),
+ Arrays.stream(method.getParameterTypes()).map(ClassInfo::asType).toArray(ClassInfo[]::new)
+ );
+
+ CodeBlock> code = res.declareMethod(
+ Modifier.PROTECTED,
+ method.getName(),
+ ClassInfo.asType(method.getReturnType()),
+ Parameter.asParameter(method.getParameters())
+ );
+
+ ILocal self = code.getThis();
+ if (method.getReturnType() == void.class){
+ code.invokeSuper(
+ self,
+ sup,
+ null,
+ code.getParamList().toArray(ILocal[]::new)
+ );
+ }
+ else{
+ ILocal ret = code.local(ClassInfo.asType(method.getReturnType()));
+
+ code.invokeSuper(
+ self,
+ sup,
+ ret,
+ code.getParamList().toArray(ILocal[]::new)
+ );
+ code.returnValue(ret);
+ }
+ }
+ }
+
+ for (Constructor> constructor : superClass.getTypeClass().getDeclaredConstructors()) {
+ if ((constructor.getModifiers() & PAC_PRI_FLAGS) == 0 && !(base.getPackage().equals(superClass.getTypeClass().getPackage()))) continue;
+ if ((constructor.getModifiers() & (Modifier.PRIVATE | Modifier.FINAL)) != 0) continue;
+
+ IMethod, ?> su = superClass.getConstructor(Arrays.stream(constructor.getParameterTypes()).map(ClassInfo::asType).toArray(IClass[]::new));
+
+ CodeBlock> code = res.declareConstructor(Modifier.PUBLIC, Parameter.asParameter(constructor.getParameters()));
+ code.invoke(code.getThis(), su, null, code.getParamList().toArray(ILocal[]::new));
+ }
+
+ return (ClassInfo extends T>) res;
+ }
+
+ /**将目标{@linkplain ClassInfo 类型信息}加载为与基类型同一保护域的对象,根据目标运行平台实现该方法,默认的JDK实现:{@link UnsafePackageAccHandler}
+ *
+ * @see UnsafePackageAccHandler*/
+ protected abstract Class extends T> loadClass(ClassInfo> clazz, Class baseClass);
+}
diff --git a/src/main/java/dynamilize/UnsafePackageAccHandler.java b/src/main/java/dynamilize/UnsafePackageAccHandler.java
new file mode 100644
index 0000000..5f38ef5
--- /dev/null
+++ b/src/main/java/dynamilize/UnsafePackageAccHandler.java
@@ -0,0 +1,42 @@
+package dynamilize;
+
+import dynamilize.classmaker.AbstractClassGenerator;
+import dynamilize.classmaker.ClassInfo;
+import jdk.internal.misc.Unsafe;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**基于{@link Unsafe}实现的强制保护域类加载处理程序
+ *
+ * @author EBwilson
+ * @since 1.6*/
+public class UnsafePackageAccHandler extends PackageAccHandler{
+ private static final Unsafe unsafe;
+
+ static{
+ try{
+ Demodulator.makeModuleOpen(Object.class.getModule(), "jdk.internal.misc", UnsafePackageAccHandler.class.getModule());
+
+ Constructor cstr = Unsafe.class.getDeclaredConstructor();
+ cstr.setAccessible(true);
+ unsafe = cstr.newInstance();
+ }catch(NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ private final AbstractClassGenerator generator;
+
+ public UnsafePackageAccHandler(AbstractClassGenerator generator){
+ this.generator = generator;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Class extends T> loadClass(ClassInfo> clazz, Class baseClass) {
+ byte[] bytes = generator.genByteCode(clazz);
+
+ return (Class extends T>) unsafe.defineClass(clazz.name(), bytes, 0, bytes.length, baseClass.getClassLoader(), null);
+ }
+}
diff --git a/src/main/java/dynamilize/classmaker/ASMGenerator.java b/src/main/java/dynamilize/classmaker/ASMGenerator.java
index 9652f99..545bc07 100644
--- a/src/main/java/dynamilize/classmaker/ASMGenerator.java
+++ b/src/main/java/dynamilize/classmaker/ASMGenerator.java
@@ -16,7 +16,11 @@
import static dynamilize.classmaker.ClassInfo.*;
-/**基于ASM字节码操作框架实现的默认类型生成器,*/
+/**基于ASM字节码操作框架实现的默认类型生成器
+ *
+ *
该类存在一个尚未修复的性能问题,即对部分可堆栈化的局部变量的优化
+ *
+ * @author EBwilson */
public class ASMGenerator extends AbstractClassGenerator implements Opcodes{
protected static final Map> CASTTABLE = new HashMap<>();
@@ -277,7 +281,7 @@ public byte[] genByteCode(ClassInfo> classInfo){
@Override
@SuppressWarnings("unchecked")
- protected Class generateClass(ClassInfo classInfo) throws ClassNotFoundException{
+ protected Class generateClass(ClassInfo classInfo) throws ClassNotFoundException{
try{
return (Class) classLoader.loadClass(classInfo.name(), false);
}catch(ClassNotFoundException e){
diff --git a/src/main/java/dynamilize/classmaker/AnnotatedMember.java b/src/main/java/dynamilize/classmaker/AnnotatedMember.java
index 44d7358..d232017 100644
--- a/src/main/java/dynamilize/classmaker/AnnotatedMember.java
+++ b/src/main/java/dynamilize/classmaker/AnnotatedMember.java
@@ -13,9 +13,6 @@
import java.util.List;
public abstract class AnnotatedMember implements AnnotatedElement{
- private static ClassInfo TARGET_TYPE;
- private static ClassInfo REPEATABLE_TYPE;
-
private final String name;
private int modifiers;
@@ -67,12 +64,11 @@ public void addAnnotation(IAnnotation> annotation){
annotationsList = new ArrayList<>();
}
- if(REPEATABLE_TYPE == null) REPEATABLE_TYPE = ClassInfo.asType(Repeatable.class);
checkType(annotation);
for(IAnnotation> anno: annotationsList){
if(anno.annotationType().equals(annotation.annotationType())){
- if(!anno.annotationType().typeClass().hasAnnotation(REPEATABLE_TYPE))
+ if(!anno.annotationType().typeClass().hasAnnotation(ClassInfo.asType(Repeatable.class)))
throw new IllegalHandleException("cannot add multiple annotations with same name that without repeatable meta annotation");
}
}
@@ -81,9 +77,7 @@ public void addAnnotation(IAnnotation> annotation){
}
protected void checkType(IAnnotation> annotation){
- if(TARGET_TYPE == null) TARGET_TYPE = ClassInfo.asType(Target.class);
-
- IAnnotation tarMark = annotation.annotationType().typeClass().getAnnotation(TARGET_TYPE);
+ IAnnotation tarMark = annotation.annotationType().typeClass().getAnnotation(ClassInfo.asType(Target.class));
if(tarMark == null) return;
for(ElementType type: tarMark.asAnnotation().value()){
diff --git a/src/main/java/dynamilize/classmaker/ClassInfo.java b/src/main/java/dynamilize/classmaker/ClassInfo.java
index 1f5b07c..86dcc85 100644
--- a/src/main/java/dynamilize/classmaker/ClassInfo.java
+++ b/src/main/java/dynamilize/classmaker/ClassInfo.java
@@ -29,7 +29,7 @@
* public static String INFO = "HelloWorld";
*
* public static main(String[] args){
- * if(System.nanoTime() > 123456789){
+ * if(System.nanoTime() < 123456789){
* System.out.println(INFO);
* }
* else System.out.println("Late")
@@ -38,7 +38,50 @@
*
* 要生成一个等效类型,应做如下描述:
*
+ * ClassInfo> demoInfo = new ClassInfo<>(
+ * Modifier.PUBLIC,
+ * "Demo",
+ * ClassInfo.OBJECT_TYPE//或者为null,默认指向java.lang.Object
+ * );
*
+ * IField INFO = demoInfo.declareField(
+ * Modifier.PUBLIC | Modifier.STATIC,
+ * "INFO",
+ * ClassInfo.STRING_TYPE,
+ * "HelloWorld"
+ * );
+ * IField out = ClassInfo.asType(System.class).getField(ClassInfo.asType(PrintWriter.class), "out");
+ *
+ * IMethod, Long> nanoTime = ClassInfo.asType(System.class).getMethod(ClassInfo.LONG_TYPE, "nanoTime");
+ * IMethod, Void> println = ClassInfo.asType(PrintWriter.class).getMethod(ClassInfo.VOID_TYPE, "println", ClassInfo.STRING_TYPE);
+ *
+ * CodeBlock code = demoInfo.declareMethod(
+ * Modifier.PUBLIC | Modifier.STATIC,
+ * "main",
+ * ClassInfo.VOID_TYPE,
+ * Parameter.trans(ClassInfo.STRING_TYPE.asArray())
+ * );
+ * ILocal time = code.local(ClassInfo.LONG_TYPE);
+ * code.invokeStatic(nanoTime, time);
+ *
+ * ILocal lo = code.local(ClassInfo.STRING_TYPE);
+ * ILocal ou = code.local(ClassInfo.asType(PrintWriter.class));
+ * code.assignStatic(out, ou);
+ *
+ * Label label = code.label();
+ * ILocal cons = code.local(ClassInfo.LONG_TYPE);
+ * code.loadConstant(cons, 123456789L);
+ * code.compare(time, ">=", cons, label);
+ *
+ * code.assignStatic(INFO, lo);
+ * code.invoke(ou, println, null, lo);
+ * code.returnVoid();
+ *
+ * code.markLabel(label);
+ * code.loadConstant(lo, "Late");
+ * code.invoke(ou, println, null, lo);
+ *
+ * 对此demoInfo进行生成即可得到等效的类
* }
* 这样的过程是繁琐的,但是也是快速的,跳过编译器产生类文件牺牲了可操作性以换取了类的生成速度,建议将行为描述为模板后再基于模板进行变更以提高开发效率*/
public class ClassInfo extends AnnotatedMember implements IClass{
diff --git a/src/main/java/dynamilize/classmaker/CodeBlock.java b/src/main/java/dynamilize/classmaker/CodeBlock.java
index 3bd5a20..5e6b680 100644
--- a/src/main/java/dynamilize/classmaker/CodeBlock.java
+++ b/src/main/java/dynamilize/classmaker/CodeBlock.java
@@ -7,8 +7,10 @@
import java.util.*;
import static dynamilize.classmaker.ClassInfo.*;
-import static dynamilize.classmaker.ClassInfo.CHAR_TYPE;
+/**描述方法具体行为的代码块对象,方法被分解为{@linkplain Element 基本行为}串联的线性结构,提供了快速添加行为的方法
+ *
+ * @author EBwilson */
public class CodeBlock implements ICodeBlock{
protected ArrayList statements = new ArrayList<>();
@@ -157,12 +159,24 @@ public final void assignStatic(IClass> clazz, String src, ILo
);
}
+ public final void assignStatic(IField src, ILocal to){
+ codes().add(
+ new GetField<>(null, src, to)
+ );
+ }
+
public final void assignStatic(IClass> clazz, ILocal src, String to){
codes().add(
new PutField<>(null, src, clazz.getField(src.type(), to))
);
}
+ public final void assignStatic(ILocal src, IField extends S> to){
+ codes().add(
+ new PutField<>(null, src, to)
+ );
+ }
+
public final void invoke(ILocal> target, IMethod, Ret> method, ILocal returnTo, ILocal>... args){
codes().add(
new Invoke<>(target, false, method, returnTo, args)
@@ -175,6 +189,12 @@ public final void invoke(ILocal> target, String method, ILocal retu
);
}
+ public final void invokeStatic(IMethod, Ret> method, ILocal returnTo, ILocal>... args){
+ codes().add(
+ new Invoke<>(null, false, method, returnTo, args)
+ );
+ }
+
public final void invokeStatic(IClass> target, String method, ILocal returnTo, ILocal>... args){
codes().add(
new Invoke<>(null, false, target.getMethod(returnTo.type(), method, Arrays.stream(args).map(ILocal::type).toArray(IClass>[]::new)), returnTo, args)
diff --git a/src/test/java/Test.java b/src/test/java/Test.java
new file mode 100644
index 0000000..1fc3bf4
--- /dev/null
+++ b/src/test/java/Test.java
@@ -0,0 +1,39 @@
+import dynamilize.*;
+import dynamilize.classmaker.ASMGenerator;
+import dynamilize.classmaker.BaseClassLoader;
+import org.objectweb.asm.Opcodes;
+import tesaaa.TBA;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+public class Test {
+ public static void main(String[] args) throws Throwable {
+ DynamicMaker maker = new DynamicFactory()
+ .setDefaultHelper()
+ .setDefaultGenerator()
+ .setPackageAccHandler(
+ new UnsafePackageAccHandler(
+ new ASMGenerator(new BaseClassLoader(Test.class.getClassLoader()), Opcodes.V1_8)
+ )
+ ).getMaker();
+
+ DynamicClass cl = DynamicClass.get("SAM");
+ DynamicObject sam = maker.newInstance(TBA.class, cl);
+
+ sam.setFunc("run", (s, su, a) -> {
+ System.out.println("yyyyyyyyyyy");
+ });
+ sam.setFunc("run2", (s, su, a) -> {
+ System.out.println("zzzzzz");
+ });
+
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle h = lookup.findConstructor(TBA.class, MethodType.methodType(void.class));
+
+ h.invoke();
+
+ sam.objSelf().run1();
+ }
+}
diff --git a/src/test/java/tesaaa/TBA.java b/src/test/java/tesaaa/TBA.java
new file mode 100644
index 0000000..ba0f8a1
--- /dev/null
+++ b/src/test/java/tesaaa/TBA.java
@@ -0,0 +1,15 @@
+package tesaaa;
+
+import test.Sample;
+
+public class TBA extends Sample {
+
+ void run2(){
+ System.out.println("ordinal");
+ }
+
+ public void run1(){
+ super.run1();
+ run2();
+ }
+}
diff --git a/src/test/java/test/Sample.java b/src/test/java/test/Sample.java
new file mode 100644
index 0000000..4067aff
--- /dev/null
+++ b/src/test/java/test/Sample.java
@@ -0,0 +1,11 @@
+package test;
+
+public class Sample {
+ void run(){
+ System.out.println("ordinal");
+ }
+
+ public void run1(){
+ run();
+ }
+}
diff --git a/usage_sample/build.gradle b/usage_sample/build.gradle
index 34095f8..8be6856 100644
--- a/usage_sample/build.gradle
+++ b/usage_sample/build.gradle
@@ -2,9 +2,6 @@ plugins {
id 'java'
}
-group = 'com.github.EB-wilson'
-version = '1.4-B1'
-
repositories {
mavenCentral()
}
diff --git a/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java b/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java
index 2e0419e..29a5b90 100644
--- a/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java
+++ b/usage_sample/src/main/java/com/github/ebwilson/sample/BaseUse.java
@@ -12,7 +12,7 @@
public class BaseUse {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
- DynamicMaker maker = DynamicMaker.getDefault();//获取默认动态工厂
+ DynamicMaker maker = DynamicFactory.getDefault();//获取默认动态工厂
DynamicClass Sample = DynamicClass.get("Sample");//创建动态类型,这是必要的,无论动态类是否有行为,get方法会返回给定名称的动态类型,如果类型尚不存在则会创建一个新的动态类型
/*===============================
diff --git a/usage_sample/src/main/java/com/github/ebwilson/sample/aop/ProxyUsage.java b/usage_sample/src/main/java/com/github/ebwilson/sample/aop/ProxyUsage.java
index 75fb4c3..fc63350 100644
--- a/usage_sample/src/main/java/com/github/ebwilson/sample/aop/ProxyUsage.java
+++ b/usage_sample/src/main/java/com/github/ebwilson/sample/aop/ProxyUsage.java
@@ -1,6 +1,7 @@
package com.github.ebwilson.sample.aop;
import dynamilize.DynamicClass;
+import dynamilize.DynamicFactory;
import dynamilize.DynamicMaker;
import dynamilize.ProxyMaker;
@@ -11,7 +12,7 @@
public class ProxyUsage {
public static void main(String[] args) {
//获取默认动态工厂
- DynamicMaker maker = DynamicMaker.getDefault();
+ DynamicMaker maker = DynamicFactory.getDefault();
//创建一个代理工厂,此类工厂将用于创建代理实例,当实例的任意可重写方法被调用时,其都会被捕获并转入声明该工厂时给定的代理函数,如下
ProxyMaker proxyMaker = ProxyMaker.getDefault(maker, (proxy, superFunction, arg) -> {
diff --git a/usage_sample/src/main/java/com/github/ebwilson/sample/dynamic/HotFixUsage.java b/usage_sample/src/main/java/com/github/ebwilson/sample/dynamic/HotFixUsage.java
new file mode 100644
index 0000000..ae8074f
--- /dev/null
+++ b/usage_sample/src/main/java/com/github/ebwilson/sample/dynamic/HotFixUsage.java
@@ -0,0 +1,4 @@
+package com.github.ebwilson.sample.dynamic;
+
+public class HotFixUsage {
+}
diff --git a/usage_sample/src/main/java/com/github/ebwilson/sample/dynamic/ReflectionFrameUsage.java b/usage_sample/src/main/java/com/github/ebwilson/sample/dynamic/ReflectionFrameUsage.java
new file mode 100644
index 0000000..e9bc711
--- /dev/null
+++ b/usage_sample/src/main/java/com/github/ebwilson/sample/dynamic/ReflectionFrameUsage.java
@@ -0,0 +1,4 @@
+package com.github.ebwilson.sample.dynamic;
+
+public class ReflectionFrameUsage {
+}
From 1d0667d6b194aef70cacf7e130895debd414ae90 Mon Sep 17 00:00:00 2001
From: EBwilson <2534946881@qq.com>
Date: Sun, 2 Jul 2023 01:32:19 +0800
Subject: [PATCH 09/34] =?UTF-8?q?=E8=B0=83=E6=95=B4API=E7=BB=93=E6=9E=84?=
=?UTF-8?q?=EF=BC=8C=E5=AE=8C=E5=96=84=E5=AF=B9=E5=8C=85=E7=A7=81=E6=9C=89?=
=?UTF-8?q?=E6=96=B9=E6=B3=95=E7=9A=84=E5=A7=94=E6=89=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index b886d72..fa317a2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ plugins {
apply plugin: 'maven-publish'
group 'com.github.EB-wilson'
-version '1.6-A1'
+version 'V1.6-A1'
sourceCompatibility = 17
targetCompatibility = 17
From 5fddf97fb037e71561de1ffcdb9a46557dd70f29 Mon Sep 17 00:00:00 2001
From: EBwilson <2534946881@qq.com>
Date: Sun, 2 Jul 2023 01:40:30 +0800
Subject: [PATCH 10/34] =?UTF-8?q?=E8=B0=83=E6=95=B4API=E7=BB=93=E6=9E=84?=
=?UTF-8?q?=EF=BC=8C=E5=AE=8C=E5=96=84=E5=AF=B9=E5=8C=85=E7=A7=81=E6=9C=89?=
=?UTF-8?q?=E6=96=B9=E6=B3=95=E7=9A=84=E5=A7=94=E6=89=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index fa317a2..b081ffc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -18,7 +18,7 @@ repositories {
dependencies {
implementation 'org.ow2.asm:asm:9.3'
- annotationProcessor 'com.github.EB-wilson.UniverseCore:annotations:1.7.4'
+ annotationProcessor 'com.github.EB-wilson.UniverseCore:annotations:1.8.1'
}
publishing {
From 91313dce1b08cb09dd1bb0ed0c7a4b47c749de01 Mon Sep 17 00:00:00 2001
From: EBwilson <2534946881@qq.com>
Date: Sun, 2 Jul 2023 10:08:47 +0800
Subject: [PATCH 11/34] =?UTF-8?q?=E8=B0=83=E6=95=B4API=E7=BB=93=E6=9E=84?=
=?UTF-8?q?=EF=BC=8C=E5=AE=8C=E5=96=84=E5=AF=B9=E5=8C=85=E7=A7=81=E6=9C=89?=
=?UTF-8?q?=E6=96=B9=E6=B3=95=E7=9A=84=E5=A7=94=E6=89=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/compiler.xml | 4 ++--
build.gradle | 4 ++--
.../java/dynamilize/PackageAccHandler.java | 7 +++---
.../dynamilize/UnsafePackageAccHandler.java | 23 ++++++++++++++-----
4 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 52453d2..353dd87 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -5,12 +5,12 @@
-
+
-
+