annoClass){
118 | Class> clazz = owner().getTypeClass();
119 | if(clazz == null)
120 | throw new IllegalHandleException("only get annotation object in existed type info");
121 |
122 | try{
123 | return clazz.getDeclaredMethod(name(), parameters().stream().map(e -> e.getType().getTypeClass()).toArray(Class[]::new)).getAnnotation(annoClass);
124 | }catch(NoSuchMethodException e){
125 | throw new IllegalHandleException(e);
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/annotations/src/main/java/dynamilize/annotations/DynamilizeClass.java:
--------------------------------------------------------------------------------
1 | package dynamilize.annotations;
2 |
3 | import dynamilize.*;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 | import java.lang.reflect.Field;
10 | import java.lang.reflect.Method;
11 |
12 | /**此注解用于将一个一般的java类型转化为动态类型记录
13 | * 具体来说,一个具备此注解的类,其中声明的各种方法语句的上下文都会被调整为适配到{@link DynamicClass#visitClass(Class, JavaHandleHelper)}的语义,
14 | * 并保存其对应的动态类型对象及名称。该注解并不会递归的处理被标记类中的内部类,但是被标记的类中不能有任何非静态的内部类
15 | *
此标记转换的动态类类名由DynamilizeClass.{@link DynamilizeClass#className()}给出,默认使用标记的类类名,细节请参阅这个注解属性
16 | *
17 | *
18 | *
19 | *
警告:此注解转换的动态类型标记可能并不能可靠的加载,在您使用这个注解生成的动态类之前,请通过调用类的任意字段/方法来确保此类型已加载
20 | * 特别注意,在注解{@link NewDynamic}中传递该类的NAME常量并不能使jvm加载这个类,因为NAME会被转化为常量提供给注解参数,
21 | * 因此在通过上下文注解引用的该动态类并不能可靠的加载此动态类
22 | *
23 | *
24 | * 以下是注解的工作细节:
25 | *
26 | * - 首先,检查该类型中的声明是否合法,而后在其中搜索{@linkplain JavaHandleHelper 辅助器},向其之后添加两个字段
27 | * {@code public static final DynamicClass INSTANCE}和{@code public static final String NAME}分别保存对动态类实例的引用和动态类类名,
28 | * 这两个字段都会添加{@link dynamilize.runtimeannos.Exclude}以排除,其中INSTANCE的初始化在后文会提到
29 | * - 接着,注解处理器会在此类上下文中定位每一个字段引用和方法引用,确定这些引用的目标是否为this或者super,若引用的目标满足且是一个隐式成员引用,
30 | * 那么会将this和super添加为显式声明
31 | * - 遍历此类所有方法,将所有成员方法全部变为静态方法,并在参数前两位添加符合{@link DynamicClass#visitMethod(Method, JavaHandleHelper)}规则的self参数和sup参数,
32 | * 而对于声明的静态方法则添加{@link dynamilize.runtimeannos.Exclude}注解从声明中排除
33 | * - 然后,将所有符合规则的成员方法中对本类上下文引用的语句转换为通过self参数传入的动态对象的方法调用,例如{@code this.run()}会被替换为{@code self.invokeFunc("run")},
34 | * 但是默认情况下这个对run的调用会添加方法签名以快速定位函数,关于签名选项,请参阅{@link DynamilizeClass#signatureMethods()}
35 | * - 最后,处理所有声明的字段,对成员字段会按照符合{@link DynamicClass#visitField(Field)}的规范变换,若其具有初始化数据,
36 | * 当初始化数据为常量值时会直接将字段设置为static,否则,字段的初始化语句会被包装为{@link dynamilize.Initializer.Producer},且字段类型也会同步调整。
37 | * 对于静态字段则会简单的像是对静态方法一样添加注解进行排除
38 | *
39 | *
40 | * 此外,被标记为动态类型记录的类也可以扩展一个动态类型记录,这会对INSTANCE字段的初始化产生影响,具体来说,初始化语句都是调用{@link DynamicClass#visit(String, Class, DynamicClass, JavaHandleHelper)}
41 | * 来直接获取动态类型实例,而扩展会影响的就是其最后一个参数,直观来看
{@code
42 | * //一个没有扩展的动态类型记录中,INSTANCE的等价初始化语句是这样的:
43 | * public static final DynamicClass INSTANCE = DynamicClass.visit(NAME, .class, null, $helper$);
44 | * //而有扩展一个父类的动态类型记录中,INSTANCE的等价初始化语句是这样的:
45 | * public static final DynamicClass INSTANCE = DynamicClass.visit(NAME, .class, .INSTANCE, $helper$);
46 | * }
47 | * 值得关注的是其中的字段{@code $helper$},这个字段是保存用于访问java类使用的辅助器的静态字段,
48 | * 您同样必须在原始的类型定义中创建指定名称的java静态字段,否则将无法通过编译,关于选择这个字段的细节,请参阅DynamilizeClass.{@link DynamilizeClass#helperField()}
49 | *
50 | * 另外,在您使用这个注解标记类型时,将类型标记为abstract并实现{@link DynamilizedClass}接口是一种不错的选择,该接口包含了INSTANCE字段和NAME字段,
51 | * 这是一种魔法操作,例如,在java中,您可以直接对被标记的类调用INSTANCE字段和NAME字段,但这是通过类转移的调用,实际上会指向{@link DynamilizedClass}接口的字段,
52 | * 但是在注解处理后,被标记类中会被添加这两个字段,从外部访问这个类型的INSTANCE和NAME字段的目标就会被确定而非重定向到DynamilizedClass接口,
53 | * 具体细节请参阅{@link DynamilizedClass}*/
54 | @Retention(RetentionPolicy.SOURCE)
55 | @Target(ElementType.TYPE)
56 | public @interface DynamilizeClass {
57 | /**应用于动态类的名称,这会为此类的NAME字段设置值,默认在不设置这个名称的情况下,注解处理器会使用被标记的类的完整类名作为该动态类的名称*/
58 | String className() default "";
59 | /**此类型动态化时所使用的静态java辅助器存储字段名称,在将类型声明转化为动态类的过程中,会在类的一级声明中搜索这个字段,
60 | * 并将INSTANCE字段添加在其后方以确保有效的调用此字段,默认为"$helper$",您可以自行指定字段名称*/
61 | String helperField() default "$helper$";
62 | /**是否对所有动态化的方法调用添加方法签名,关于方法签名的性能影响,可参阅{@link DataPool#select(String, FunctionType)},若您将此设置为true,
63 | * 那么所有从方法调用转换来的动态方法引用都会标记其调用的方法签名类型,并在调用时传入以提升性能
64 | * 您可以根据需要设置此选项,假如内存性能十分重要,则推荐设为false,否则通常来说设为true都能提升时间性能,尤其是在动态类型多次扩展嵌套的情况下*/
65 | boolean signatureMethods() default true;
66 |
67 | /**辅助类型动态声明的魔法接口,通常在您对一个类型标记为{@link DynamilizeClass}时,建议将类型设置为abstract并添加实现此接口
68 | *
接口扩展自{@link DynamicObject},以便在您描述类型行为时可以直接使用动态对象的方法,值得注意的是,
69 | * 您在此上下文中调用属于{@link DynamicObject}的API是不会被再次转化为动态调用动态方法的,即这些API会被注解处理器略过,仅仅将调用对象重定向到self参数
70 | *
此外,该接口中定义了两个常量字段和一个方法,字段用作在java语义中直接引用该类型的INSTANCE字段和NAME字段,在经过注解处理器处理后这两个字段不会被重定向到该接口。
71 | *
方法{@link DynamilizedClass#super$()}则是对动态super指针的虚拟引用,以便您可以以动态描述的方法那样调用super池的行为,对这个方法的调用在注解处理后会被转化为对sup参数的引用*/
72 | interface DynamilizedClass extends DynamicObject {
73 | DynamicClass INSTANCE = DynamicClass.get("");
74 | String NAME = "";
75 |
76 | default DataPool.ReadOnlyPool super$(){ return null; }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/usage_sample/src/main/java/com/github/ebwilson/sample_zh/aop/AspectUsage.java:
--------------------------------------------------------------------------------
1 | package com.github.ebwilson.sample_zh.aop;
2 |
3 | import dynamilize.*;
4 | import dynamilize.runtimeannos.AspectInterface;
5 | import dynamilize.runtimeannos.FuzzyMatch;
6 |
7 | /**本篇案例演示的是更好的面向切面用法,在您阅读本篇前请务必了解{@linkplain dynamilize.DynamicClass 动态类型}的使用及行为效果,以理解本篇中各行为的效果
8 | *
9 | *
正如本例子开头给出的三个类,多数情况下,面向对象的思想会指导开发者对一个类扩展多个子类进行编写,
10 | * 但是类进行扩展的过程是单向的,当我们需要对这些子类继承来的共有行为进行操作时,我们可能需要一个又一个的类分别扩展一个子类,
11 | * 然后又在子类里写下完全一样的方法重写,这就大大提高了工作量和代码的耦合度。
12 | *
13 | * 一般来说,解决这个问题通常会考虑改变代码的逻辑来减少耦合度,比如提升共同行为至基类,但通常这不是很好的办法,因此我们引入了面向切面编程,即AOP
14 | *
AOP思想指导开发者只关注多个类型的共有行为(这甚至可以不是从一个基类继承而来),而本框架更进一步的将其视为“可变的”,请继续往下阅读
*/
15 | public class AspectUsage {
16 | /**这是一个基类,它描述了几个方法,关注这些方法,这会是子类当中的共有特征*/
17 | public static class ClassA{
18 | public void update(){}
19 | public void draw(){}
20 | public void showInfo(){
21 | System.out.println("Now here is `ClassA`");
22 | }
23 | public void showInfo(String string){
24 | System.out.println("Here is `ClassA`'s info: " + string);
25 | }
26 | }
27 |
28 | //下面则是对ClassA的两个分别扩展的子类,思考一下,假设我们需要让ClassB和ClassC的实例具有如下效果:
29 | //×-在调用update()时,在执行后打印update方法被调用的次数
30 | //×-在调用draw()方法时,在draw的首行前增加一行和末尾追加一行,分别打印"--------------------"
31 | //×-在调用两个showInfo时,分别在之前添加一个"> "
32 |
33 | //另外,当子类远远不只有ClassB和ClassC的情况呢?
34 |
35 | public static class ClassB extends ClassA {
36 | public void update(){
37 | System.out.println("updating");
38 | }
39 | public void draw(){
40 | System.out.println("- - - - -");
41 | }
42 | public void showInfo(){
43 | System.out.println("Now here is `ClassB`");
44 | }
45 | public void showInfo(String string){
46 | System.out.println("Here is `ClassB`'s info: " + string);
47 | }
48 | }
49 |
50 | public static class ClassC extends ClassA {
51 | public void reset(){
52 | System.out.println("reset! (Actually did nothing)");
53 | }
54 | public void draw(){
55 | System.out.println("* * * * *");
56 | }
57 | public void showInfo(){
58 | System.out.println("Now here is `ClassC`");
59 | }
60 | public void showInfo(String string){
61 | System.out.println("Here is `ClassC`'s info: " + string);
62 | }
63 | }
64 |
65 | //请继续往下看,现在,创建一个DynamicMaker,此处使用默认工厂
66 | static DynamicMaker maker = DynamicFactory.getDefault();
67 |
68 | /**现在,针对上述的基类创建一个切面接口*/
69 | @AspectInterface
70 | public interface ClassAspect{
71 | void update();
72 | void draw();
73 | /**本方法标记为{@linkplain FuzzyMatch 模糊匹配},属性{@linkplain FuzzyMatch#anySameName() anySameName}标记此方法匹配所有同名重载*/
74 | @FuzzyMatch(anySameName = true)
75 | void showInfo();
76 | }
77 |
78 | //开始
79 | public static void main(String[] args) {
80 | //创建一个动态类
81 | DynamicClass SampleAspect = DynamicClass.get("SampleAspect");
82 |
83 | SampleAspect.setVariable("updateCounter", 0);
84 | //下面,我们描述这个切面动态类进行的所有操作
85 | SampleAspect.setFunction("update", (s, su, arg) -> {
86 | su.invokeFunc("update", arg);
87 | System.out.println("update invoked counter: " + s.calculateVar("updateCounter", (int i) -> i + 1));
88 | });
89 | SampleAspect.setFunction("draw", (s, su, arg) -> {
90 | System.out.println("--------------------");
91 | su.invokeFunc("draw", arg);
92 | System.out.println("--------------------");
93 | });
94 | //共同行为,采取同一函数同时设置为两个签名的重载方法
95 | Function.NonRetSuperGetFunc> fun = (s, su, arg) -> {
96 | System.out.print("> ");
97 | su.invokeFunc("showInfo", arg);
98 | };
99 | SampleAspect.setFunction("showInfo", fun);
100 | // -> public void showInfo(){...}
101 | SampleAspect.setFunction("showInfo", fun, String.class);
102 | // -> public void showInfo(String string){...}
103 |
104 | //接下来,我们分别创建两个类的切面代理对象:
105 | DynamicObject instB = maker.newInstance(ClassB.class, new Class[]{ClassAspect.class}, SampleAspect);
106 | DynamicObject instC = maker.newInstance(ClassC.class, new Class[]{ClassAspect.class}, SampleAspect);
107 |
108 | //测试打印
109 | System.out.println("testing instance B:");
110 | ClassB b = instB.objSelf();
111 | b.update();
112 | b.draw();
113 | b.showInfo();
114 | b.showInfo("sample test");
115 |
116 | System.out.println("testing instance C:");
117 | ClassC c = instC.objSelf();
118 | c.update();
119 | c.draw();
120 | c.showInfo();
121 | c.showInfo("sample test");
122 |
123 | c.reset();
124 |
125 | //显然,这大大的降低了代码的耦合度和工作量,你可以使用更少的代码来完成类似的工作,尤其在子类分支远远更多的情况下
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/baseimpl/src/main/java/dynamilize/Demodulator.java:
--------------------------------------------------------------------------------
1 | package dynamilize;
2 |
3 | import sun.misc.Unsafe;
4 |
5 | import java.lang.reflect.Constructor;
6 | import java.lang.reflect.Field;
7 | import java.lang.reflect.InvocationTargetException;
8 | import java.lang.reflect.Method;
9 | import java.util.*;
10 |
11 | /**反模块化工具, 仅提供了一个主要方法{@link Demodulator#makeModuleOpen(Module, Package, Module)}用于强制对需要的模块开放模块的软件包。
12 | * 此类行为可能完全打破模块化的访问保护,本身是不安全的,若不是必要情况,请尽量避免使用该类
13 | *
此类仅在JDK9之后可用,避免在更早的版本引用此类的方法,且此类仅在desktop平台可用,安卓平台不可使用此类的任何行为
14 | *
15 | * @author EBwilson */
16 | @SuppressWarnings({"unchecked"})
17 | public class Demodulator{
18 | private static final long fieldFilterOffset = 112L;
19 |
20 | private static final Unsafe unsafe;
21 |
22 | private static final Field opensField;
23 | private static final Field exportField;
24 |
25 | private static final Method exportNative;
26 |
27 | static{
28 | try{
29 | Constructor cstr = Unsafe.class.getDeclaredConstructor();
30 | cstr.setAccessible(true);
31 | unsafe = cstr.newInstance();
32 |
33 | ensureFieldOpen();
34 |
35 | opensField = Module.class.getDeclaredField("openPackages");
36 | exportField = Module.class.getDeclaredField("exportedPackages");
37 |
38 | makeModuleOpen(Module.class.getModule(), "java.lang", Demodulator.class.getModule());
39 |
40 | exportNative = Module.class.getDeclaredMethod("addExports0", Module.class, String.class, Module.class);
41 | exportNative.setAccessible(true);
42 | exportNative.invoke(null, Module.class.getModule(), "java.lang", Demodulator.class.getModule());
43 | }catch(NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException |
44 | NoSuchFieldException e){
45 | throw new RuntimeException(e);
46 | }
47 | }
48 |
49 | public static void makeModuleOpen(Module from, Class> clazz, Module to){
50 | if (clazz.isArray()){
51 | makeModuleOpen(from, clazz.getComponentType(), to);
52 | }
53 | else makeModuleOpen(from, clazz.getPackage(), to);
54 | }
55 |
56 | public static void makeModuleOpen(Module from, Package pac, Module to){
57 | if(checkModuleOpen(from, pac, to)) return;
58 |
59 | makeModuleOpen(from, pac.getName(), to);
60 | }
61 |
62 | @SuppressWarnings("unchecked")
63 | public static void makeModuleOpen(Module from, String pac, Module to){
64 | try {
65 | if (exportNative != null) exportNative.invoke(null, from, pac, to);
66 | } catch (IllegalAccessException | InvocationTargetException e) {
67 | throw new RuntimeException(e);
68 | }
69 |
70 | Map> opensMap = (Map>) unsafe.getObjectVolatile(from, unsafe.objectFieldOffset(opensField));
71 | if(opensMap == null){
72 | opensMap = new HashMap<>();
73 | unsafe.putObjectVolatile(from, unsafe.objectFieldOffset(opensField), opensMap);
74 | }
75 |
76 | Map> exportsMap = (Map>) unsafe.getObjectVolatile(from, unsafe.objectFieldOffset(exportField));
77 | if(exportsMap == null){
78 | exportsMap = new HashMap<>();
79 | unsafe.putObjectVolatile(from, unsafe.objectFieldOffset(exportField), exportsMap);
80 | }
81 |
82 | Set opens = opensMap.computeIfAbsent(pac, e -> new HashSet<>());
83 | Set exports = exportsMap.computeIfAbsent(pac, e -> new HashSet<>());
84 |
85 | try{
86 | opens.add(to);
87 | }catch(UnsupportedOperationException e){
88 | ArrayList lis = new ArrayList<>(opens);
89 | lis.add(to);
90 | opensMap.put(pac, new HashSet<>(lis));
91 | }
92 |
93 | try{
94 | exports.add(to);
95 | }catch(UnsupportedOperationException e){
96 | ArrayList lis = new ArrayList<>(exports);
97 | lis.add(to);
98 | exportsMap.put(pac, new HashSet<>(lis));
99 | }
100 | }
101 |
102 | public static boolean checkModuleOpen(Module from, Package pac, Module to){
103 | Objects.requireNonNull(from);
104 | Objects.requireNonNull(to);
105 |
106 | if(pac == null) return true;
107 |
108 | return from.isOpen(pac.getName(), to);
109 | }
110 |
111 | public static void ensureFieldOpen(){
112 | try{
113 | Class> clazz = Class.forName("jdk.internal.reflect.Reflection");
114 | Map, Set> map = (Map, Set>) unsafe.getObject(clazz, fieldFilterOffset);
115 | map.clear();
116 | }catch(ClassNotFoundException e){
117 | throw new RuntimeException(e);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/usage_sample/src/main/java/com/github/ebwilson/sample_zh/aop/ProxyUsage.java:
--------------------------------------------------------------------------------
1 | package com.github.ebwilson.sample_zh.aop;
2 |
3 | import dynamilize.*;
4 |
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.List;
8 |
9 | /**本篇向您演示该框架进行代理模式AOP的示例,这是一个类似cglib的行为,如果您不了解cglib,那么您可以参考{@link java.lang.reflect.Proxy},此用法与反射的Proxy类似,但是这并不依赖于切面对象的公共接口*/
10 | public class ProxyUsage {
11 | @SuppressWarnings("unchecked")
12 | public static void main(String[] args) {
13 | //获取默认动态工厂
14 | DynamicMaker maker = DynamicFactory.getDefault();
15 |
16 | //创建一个代理工厂,此类工厂将用于创建代理实例,当实例的任意可重写方法被调用时,其都会被捕获并转入声明该工厂时给定的代理函数,如下
17 | ProxyMaker proxyMaker = ProxyMaker.getDefault(maker, (proxy, func, superFunc, arg) -> {
18 | //调用任何方法时都将调用信息打印到输出流
19 | System.out.println("invoking " + superFunc + ", args: " + arg);
20 |
21 | //向上调用被拦截的方法,如果不调用的话此方法会被截断使此次调用无效
22 | return superFunc.invoke(proxy, arg);
23 | });
24 |
25 | //利用proxyMaker创建代理实例,代理实例的行为都会被代理工厂代理委托到代理函数上
26 | ArrayList list = proxyMaker.newProxyInstance(ArrayList.class).objSelf();
27 | HashMap map = proxyMaker.newProxyInstance(HashMap.class).objSelf();
28 |
29 | //测试打印,您将会看到下面进行的每一次操作都会被截获并打印在输出流
30 | list.add("first");
31 | list.add("second");
32 | list.add("third");
33 |
34 | map.put("first", "a1");
35 | map.put("second", "b2");
36 | map.put("third", "c3");
37 |
38 | list.add(map.get(list.get(0)));
39 |
40 | System.out.println("\n===========sep line==========\n");
41 |
42 | //尽管这上面调用的几个方法都被声明在了集合框架的接口之中,但是不同于反射proxy,JDER代理是不需要被监视行为来自接口的,如下:
43 | //这一条语句会调用list的toString()方法,这个方法来自类Object,同样的,它也被监视了
44 | System.out.println(list);
45 |
46 | System.out.println("\n===========sep line==========\n");
47 |
48 | //另外,对于一个代理委托实例您依然可以在创建它的时候给它分配一个动态超类,动态类的行为则会被增加在此代理的行为之前
49 |
50 | //创建动态类
51 | DynamicClass Sample = DynamicClass.get("Sample");
52 | Sample.setFunction("add", (self, su, arg) -> {
53 | System.out.println("this is call after than proxy monitor");
54 |
55 | return su.invokeFunc("add", arg);
56 | }, Object.class);
57 | ArrayList builder = proxyMaker.newProxyInstance(ArrayList.class, Sample).objSelf();
58 |
59 | //测试打印,观察打印结果,分配给动态对象的动态类行为被插入在监视器之前,代理处理器可以正确截断
60 | builder.add("hello ");
61 | builder.add("world");
62 | System.out.println(builder);
63 |
64 | System.out.println("\n===========sep line==========\n");
65 |
66 | //当然,就像代理的实际使用方法一样,我们可以使用一个代理对象来代为处理对被代理对象的行为调用,例如,我们用前文生成的builder作为代理对象:
67 | DynamicObject> dyBuilder = (DynamicObject>) builder;
68 | ProxyMaker proxy = ProxyMaker.getDefault(maker, (self, func, superFunc, arg) -> {
69 | System.out.println("invoke to proxy object");
70 | return func.invoke(dyBuilder, arg);
71 | });//直接将所有方法调用重定向到dyBuilder
72 | List listProxied = proxy.newProxyInstance(new Class[]{List.class}).objSelf();//创建的被代理的对象不应该超出委托目标的范围,这里使用List接口
73 |
74 | //测试打印
75 | listProxied.add("hello world again");
76 | System.out.println(builder);
77 | listProxied.clear();
78 | System.out.println(builder);
79 |
80 | System.out.println("\n===========sep line==========\n");
81 |
82 | //有时候,会需要对一些非动态化的对象作委托,这种时候需要将被代理的非动态对象进行动态包装,在DynamicMaker当中提供了一个包装方法:
83 | ArrayList delegate = new ArrayList<>();
84 | DynamicObject> wrapped = maker.wrapInstance(delegate);
85 |
86 | //这个对象与来自newInstance的动态对象不同,这是一个受限制的动态对象,例如它只能用于动态调用被包装对象的已有方法,而不能创建新函数
87 | wrapped.invokeFunc("add", "hello world");
88 | System.out.println(delegate);
89 |
90 | //并且尝试转换到被包装对象的类型会发生异常:
91 | //ArrayList test = (ArrayList)wrapped;//抛出异常
92 | //应使用:
93 | ArrayList test = wrapped.objSelf();
94 |
95 | //该包装可被用在类型代理上,当调用需要的被代理对象是一个非动态对象,而又不希望对它动态化,则可将其进行包装:
96 | ProxyMaker wrapProxy = ProxyMaker.getDefault(maker, (self, func, superFunc, arg) -> {
97 | System.out.println("invoke to proxy object, delegate method: " + func.signature());
98 | return func.invoke(wrapped, arg);
99 | });
100 | List proxied = wrapProxy.newProxyInstance(new Class[]{List.class}).objSelf();
101 |
102 | //测试打印
103 | proxied.add("i am a robot");
104 | System.out.println(delegate);
105 | proxied.clear();
106 | System.out.println(delegate);
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/baseimpl/src/main/java/dynamilize/JavaVariable.java:
--------------------------------------------------------------------------------
1 | package dynamilize;
2 |
3 | import java.lang.invoke.MethodHandle;
4 | import java.lang.invoke.MethodHandles;
5 | import java.lang.reflect.Field;
6 |
7 | /**对java字段的引用对象,基于{@linkplain MethodHandle 方法句柄}的默认内部实现
8 | *
9 | * @author EBwilson */
10 | public class JavaVariable implements IVariable{
11 | private final Field field;
12 |
13 | private final MethodHandle getter;
14 | private final MethodHandle setter;
15 |
16 | private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
17 |
18 | public JavaVariable(Field field){
19 | this.field = field;
20 |
21 | try {
22 | getter = LOOKUP.unreflectGetter(field);
23 | setter = LOOKUP.unreflectSetter(field);
24 | } catch (IllegalAccessException e) {
25 | throw new RuntimeException(e);
26 | }
27 | }
28 |
29 | @Override
30 | public String name(){
31 | return field.getName();
32 | }
33 |
34 | @Override
35 | public void init(DynamicObject> object) { /*no action*/ }
36 |
37 | @SuppressWarnings("unchecked")
38 | @Override
39 | public T get(DynamicObject> obj){
40 | try{
41 | return (T) getter.invoke(obj);
42 | }catch(ClassCastException e){
43 | throw e;
44 | }catch(Throwable e){
45 | throw new IllegalHandleException(e);
46 | }
47 | }
48 |
49 | @Override
50 | public void set(DynamicObject> obj, Object value){
51 | try{
52 | setter.invoke(obj, value);
53 | }catch(Throwable e){
54 | throw new IllegalHandleException(e);
55 | }
56 | }
57 |
58 | @Override
59 | public boolean get(DynamicObject> obj, boolean def) {
60 | try {
61 | return field.getBoolean(obj);
62 | } catch (IllegalAccessException e) {
63 | throw new IllegalHandleException(e);
64 | }
65 | }
66 |
67 | @Override
68 | public byte get(DynamicObject> obj, byte def) {
69 | try {
70 | return field.getByte(obj);
71 | } catch (IllegalAccessException e) {
72 | throw new IllegalHandleException(e);
73 | }
74 | }
75 |
76 | @Override
77 | public short get(DynamicObject> obj, short def) {
78 | try {
79 | return field.getShort(obj);
80 | } catch (IllegalAccessException e) {
81 | throw new IllegalHandleException(e);
82 | }
83 | }
84 |
85 | @Override
86 | public int get(DynamicObject> obj, int def) {
87 | try {
88 | return field.getInt(obj);
89 | } catch (IllegalAccessException e) {
90 | throw new IllegalHandleException(e);
91 | }
92 | }
93 |
94 | @Override
95 | public long get(DynamicObject> obj, long def) {
96 | try {
97 | return field.getLong(obj);
98 | } catch (IllegalAccessException e) {
99 | throw new IllegalHandleException(e);
100 | }
101 | }
102 |
103 | @Override
104 | public float get(DynamicObject> obj, float def) {
105 | try {
106 | return field.getFloat(obj);
107 | } catch (IllegalAccessException e) {
108 | throw new IllegalHandleException(e);
109 | }
110 | }
111 |
112 | @Override
113 | public double get(DynamicObject> obj, double def) {
114 | try {
115 | return field.getDouble(obj);
116 | } catch (IllegalAccessException e) {
117 | throw new IllegalHandleException(e);
118 | }
119 | }
120 |
121 | @Override
122 | public void set(DynamicObject> obj, boolean value) {
123 | try {
124 | field.setBoolean(obj, value);
125 | } catch (IllegalAccessException e) {
126 | throw new RuntimeException(e);
127 | }
128 | }
129 |
130 | @Override
131 | public void set(DynamicObject> obj, byte value) {
132 | try {
133 | field.setByte(obj, value);
134 | } catch (IllegalAccessException e) {
135 | throw new RuntimeException(e);
136 | }
137 | }
138 |
139 | @Override
140 | public void set(DynamicObject> obj, short value) {
141 | try {
142 | field.setShort(obj, value);
143 | } catch (IllegalAccessException e) {
144 | throw new RuntimeException(e);
145 | }
146 | }
147 |
148 | @Override
149 | public void set(DynamicObject> obj, int value) {
150 | try {
151 | field.setInt(obj, value);
152 | } catch (IllegalAccessException e) {
153 | throw new RuntimeException(e);
154 | }
155 | }
156 |
157 | @Override
158 | public void set(DynamicObject> obj, long value) {
159 | try {
160 | field.setLong(obj, value);
161 | } catch (IllegalAccessException e) {
162 | throw new RuntimeException(e);
163 | }
164 | }
165 |
166 | @Override
167 | public void set(DynamicObject> obj, float value) {
168 | try {
169 | field.setFloat(obj, value);
170 | } catch (IllegalAccessException e) {
171 | throw new RuntimeException(e);
172 | }
173 | }
174 |
175 | @Override
176 | public void set(DynamicObject> obj, double value) {
177 | try {
178 | field.setDouble(obj, value);
179 | } catch (IllegalAccessException e) {
180 | throw new RuntimeException(e);
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
52 |
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JavaDynamilizer
2 | 一个java语言的动态化支持框架,允许对java类型进行动态委托并构造动态实例,以类似脚本语言的“函数”和“变量”来替代“方法”和“字段”,它们是可以变化的,动态实例可以委托自任意可用的java类(非final且具有至少对子类可见的构造器),动态实例可以分配给被委托的java类。
3 | ****
4 | 要引用JavaDynamilizer部署项目,需要在项目依赖中添加对此仓库的依赖:
5 |
6 | dependencies {
7 | ......
8 | implementation 'com.github.EB-wilson.JavaDynamilizer:core:$version'
9 | implementation 'com.github.EB-wilson.JavaDynamilizer:baseimpl:$version'//基础的内部实现,若您需要自定义实现抽象层的话,这个模块就并不是必要的
10 | ......
11 | }
12 |
13 | > 当前这个项目还尚不成熟和健壮,需要更多的使用与建议来进一步完善和优化,如果您有能力还请不吝参与此框架的开发。
14 |
15 | 您可以参照项目中给出的一些使用[案例](https://github.com/EB-wilson/JavaDynamilizer/tree/master/usage_sample/src/main/java/com/github/ebwilson/sample)和javadoc了解更多关于这个仓库的使用方法。下面是基本使用方法简述:
16 |
17 | ## 基本使用
18 | 创建一个最简单的全委托动态实例,它委托自java类HashMap:
19 |
20 | DynamicMaker maker = DynamicFactory.getDefault();
21 | DynamicClass Sample = DynamicClass.get("Sample");
22 |
23 | HashMap map = maker.newInstance(HashMap.class, Sample).objSelf();
24 |
25 | 其中,map对象具有所有hashMap的行为并且可以分配给HashMap字段或者参数。而本工具的重点在于动态化实例,上面创建的map实例已经被动态化,它具有`dynamilize.DynamicObject`的特征,对于此对象已经可以进行行为变更和代码插桩了。
26 |
27 | 例如,接下来我们对上面的map的`put`方法添加一个监视,使任何时候向该映射中添加映射都会将这个键值对打印出来:
28 |
29 | DynamicObject> dyMap = (DynamicObject>)map;
30 | dyMap.setFunc("put", (self, args) -> {
31 | self.superPointer().invokeFunc("put", args);
32 | System.out.println("map putted, key: " + args.get(0) + ", value: " + args.get(1) + ".");
33 | }, Object.class, Object.class);
34 |
35 | 这时,如果执行`map.put("first", "hello world")`,那么会在系统输出流中收到如下信息:
36 |
37 | map putted, key: first, value: hello world.
38 |
39 | 另外,在构建一个动态实例时,您还可以令实例实现一组接口,同样的,实例可以被正确的分配给这个接口的类型:
40 |
41 | DynamicClass Demo = DynamicClass.get("Demo");
42 | DynamicObject> dyObj = DynamicFactory.getDefault().newInstance(new Class[]{Map.class}, Demo);
43 | Map, ?> map = (Map, ?>)dyObj;
44 |
45 | 但是在实现接口时,您必须使用`setFunc`方法来对所有的接口抽象方法进行实现,否则对此方法的引用会抛出致命异常。
46 |
47 | ## 动态类型
48 |
49 | > 前面提到了关于实现接口时,需要对方法进行逐一实现的情况,如果对每一个抽象方法都需要逐一引用`setFunc`进行设置实现的话,无疑代码会变得尤其复杂,为此我们引入**动态类型**,以便更加有效的利用动态实例。
50 |
51 | 每一个动态实例,都会有一个关联的动态类型,这类似于java本身的**类**与**对象**的关系,不同的是,动态类型描述了其实例的默认行为,如该类型的实例构建后所具有的默认函数和变量。从之前的例子我们已经可以知道,创建一个动态实例必须要来自一个动态类型:
52 |
53 | DynamicClass Demo = DynamicClass.get("Demo");
54 |
55 | 动态类型也有它的超类,距离这个动态类型最近的一个超类称为此类的**直接超类**,对于上述例子的`Demo`类,它的直接超类没有被明确确定,则它的直接超类为构造实例进行委托的java类;若有确定的直接超类:
56 |
57 | DynamicClass DemoChild = DynamicClass.declare("DemoChild", Demo);
58 |
59 | 直接超类与java类的类层次结构行为基本一致,即遵循原则:**引用一个函数或者变量时,以最接近此类型的超类优先被访问**。
60 |
61 | 下面,将讨论如何设置动态类型的行为。
62 | 动态类型的行为主要由函数和变量构成,对于函数设置有**访问样版模式**和**lambda模式**,对于变量,则有**访问样版模式**和**函数模式**以及**常量模式**,不同的模式有各自的应用场景和使用方法:
63 |
64 | 先创建一个新的动态类:
65 |
66 | DynamicClass Sample = DynamicLcass.get("Sample");
67 | ****
68 | - **函数**
69 |
70 | **访问样版模式**
71 | 即使用java类型描述一定的行为,用动态类型去访问这个java类型。
72 | 例如声明一个类型用作样版:
73 |
74 | public class Template{
75 | public static void run(){
76 | System.out.println("hello world");
77 | }
78 | }
79 |
80 | 那么用动态类型去访问:
81 |
82 | DynamicMaker maker = DynamicFactory.getDefault();
83 | Sample.visitClass(Template.class, maker.getHelper());
84 | DynamicObject> dyObj = maker.newInstance(Sample);
85 | dyObj.invokeFunc("run");
86 |
87 | 这将会在系统输出流中打印`hello world`。
88 | 访问类型样版会描述类型中声明的所有未排除的public static方法,如果你需要针对某一方法访问,则可以通过反射获取方法对象,使用`Sample.visitMethod(*reflection method*)`方法对方法进行单独访问。
89 | ****
90 | **lambda模式**
91 | 即匿名函数模式,意在使用lambda表达式声明的匿名函数来描述动态类型中函数的行为。
92 |
93 | Sample.setFunction("run", (self, args) -> System.out.println("hello world"));
94 | DynamicObject> dyObj = DynamicMaker.getDefault().newInstance(Sample);
95 | dyObj.invokeFunc("run");
96 |
97 | 这一段代码与前一种方法描述的对象行为是一致的。
98 | ****
99 | - **变量**
100 |
101 | **访问样板模式**
102 | 与函数的访问样板模式类似,只是函数访问的是方法,而变量要访问的是字段
103 | 例如,定义样板类型:
104 |
105 | public class Template{
106 | public static String var1 = "hello world";
107 | }
108 |
109 | 如果访问动态对象的变量`var1`:
110 |
111 | DynamicMaker maker = DynamicFactory.getDefault();
112 | Sample.visitClass(Template.class, maker.getHelper());
113 | DynamicObject> dyObj = maker.newInstance(Sample);
114 | System.out.println(dyObject.getVar("var1"));
115 |
116 | 这会在系统输出流种打印`hello world`。
117 | 与方法相同,访问一个类型样板会访问其中的所有public static字段,若需要就某一字段进行访问,则可以对反射获取的字段对象使用`Sample.visitField(*reflection field*)`方法来访问指定的字段。
118 | 另外,字段的访问样版可以被设置为函数:
119 |
120 | public class Template{
121 | public static Initializer.Producer var1 = () -> System.nanoTime();
122 | }
123 |
124 | 这与后文函数模式的效果一致。
125 | ****
126 | **常量模式**
127 | 即直接用一个常量作为变量的初始值:
128 |
129 | Sample.setVariable("var1", "hello world", false);
130 | DynamicObject> dyObj = DynamicMaker.getDefault().newInstance(Sample);
131 | System.out.println(dyObject.getVar("var1"));
132 |
133 | 这将获得与前一种方法同样的效果。
134 | ****
135 | **函数模式**
136 | 这种方式使用一个工厂函数生产变量初始值,每一个函数初始化都会调用给出的函数来生产变量的初始值,例如:
137 |
138 | Sample.setVariable("time", () -> System.nanoTime(), false);
139 |
140 | 则会使得对象的`time`变量与对象被创建时的系统纳秒计数一致。
141 | 函数与常量模式参数尾部的布尔值是确定此变量是否为**常量**,若为true,则此变量不可被改变。
142 | ****
143 | - 动态类型声明的变量初始值只在对象被创建时有效,任何时候改变类的变量初始值都不会对已有实例造成影响
144 |
--------------------------------------------------------------------------------
/usage_sample/src/main/java/com/github/ebwilson/sample/aop/AspectUsage.java:
--------------------------------------------------------------------------------
1 | package com.github.ebwilson.sample.aop;
2 |
3 | import dynamilize.*;
4 | import dynamilize.runtimeannos.AspectInterface;
5 | import dynamilize.runtimeannos.FuzzyMatch;
6 |
7 | /** This case shows a better usage for AOP. Please first read the usage and function of {@linkplain dynamilize.DynamicClass Dynamic Object}, so that you will have a better understand of the function in this case.
8 | *
9 | *
As the 3 classes provided in the beginning of the code. Usually, OOP (Object-Oriented Programming) teaches developers to extends several sub-classes.
10 | * But the extend of a class is single-directional. When dealing with the common behavior inherited, we may extend another sub-class over and over again.
11 | * And then we write the same overriding code in the each of the sub-classes, which increases workloads and coupling.
12 | *
13 | * Classically, the way to solve the problem is to change the logic of the code to decrease the coupling, for example, moving the common behavior to the base-class. But it does not work many time. So AOP (Aspect-Oriented Programming) comes up.
14 | *
It teaches developers to pay attention to the common behavior of multiple types, which is even able not to be extended form the same class. Further, the framework refer to the type as variable
*/
15 | public class AspectUsage {
16 | /**This is the base class where defined several methods, which will be the common behaviors of the sub-classes*/
17 | static class ClassA{
18 | public void update(){}
19 | public void draw(){}
20 | public void showInfo(){
21 | System.out.println("Now here is `ClassA`");
22 | }
23 | public void showInfo(String string){
24 | System.out.println("Here is `ClassA`'s info: " + string);
25 | }
26 | }
27 |
28 | //The following are the sub-classes extended from the ClassA. What do you think we should do to add the following functions to the instance of ClassB and ClassC:
29 | //×-After `update()`, prints how many times it is invoked;
30 | //×-Before and after `draw()`, prints a line "--------------------";
31 | //×-" Before `showInfo()`, prints a "> ".
32 |
33 | //And what if the sub-classes are more than ClassB and ClassC?
34 |
35 | public static class ClassB extends ClassA {
36 | public void update(){
37 | System.out.println("updating");
38 | }
39 | public void draw(){
40 | System.out.println("- - - - -");
41 | }
42 | public void showInfo(){
43 | System.out.println("Now here is `ClassB`");
44 | }
45 | public void showInfo(String string){
46 | System.out.println("Here is `ClassB`'s info: " + string);
47 | }
48 | }
49 |
50 | public static class ClassC extends ClassA {
51 | public void reset(){
52 | System.out.println("reset! (Actually did nothing)");
53 | }
54 | public void draw(){
55 | System.out.println("* * * * *");
56 | }
57 | public void showInfo(){
58 | System.out.println("Now here is `ClassC`");
59 | }
60 | public void showInfo(String string){
61 | System.out.println("Here is `ClassC`'s info: " + string);
62 | }
63 | }
64 |
65 | // Now let's get the default DynamicMaker
66 | static DynamicMaker maker = DynamicFactory.getDefault();
67 |
68 | /**An aspect interface for the class above.*/
69 | @AspectInterface
70 | public interface ClassAspect{
71 | void update();
72 | void draw();
73 | /**The method is with {@linkplain FuzzyMatch Fuzzy Match}, where the {@linkplain FuzzyMatch#anySameName() anySameName} parameter means that the method can override any methods with the same name*/
74 | @FuzzyMatch(anySameName = true)
75 | void showInfo();
76 | }
77 |
78 | //Let's start
79 | public static void main(String[] args) {
80 | //Creates a dynamic type
81 | DynamicClass SampleAspect = DynamicClass.get("SampleAspect");
82 |
83 | SampleAspect.setVariable("updateCounter", 0);
84 | //Next, we will describe the functions
85 | SampleAspect.setFunction("update", (s, su, arg) -> {
86 | su.invokeFunc("update", arg);
87 | System.out.println("update invoked counter: " + s.calculateVar("updateCounter", (int i) -> i + 1));
88 | });
89 | SampleAspect.setFunction("draw", (s, su, arg) -> {
90 | System.out.println("--------------------");
91 | su.invokeFunc("draw", arg);
92 | System.out.println("--------------------");
93 | });
94 | //Defines a function for two methods with different signatures
95 | Function.NonRetSuperGetFunc> fun = (s, su, arg) -> {
96 | System.out.print("> ");
97 | su.invokeFunc("showInfo", arg);
98 | };
99 | SampleAspect.setFunction("showInfo", fun);
100 | // -> public void showInfo(){...}
101 | SampleAspect.setFunction("showInfo", fun, String.class);
102 | // -> public void showInfo(String string){...}
103 |
104 | //Then, creates two classes' aspect proxy object
105 | DynamicObject instB = maker.newInstance(ClassB.class, new Class[]{ClassAspect.class}, SampleAspect);
106 | DynamicObject instC = maker.newInstance(ClassC.class, new Class[]{ClassAspect.class}, SampleAspect);
107 |
108 | //Test printing
109 | System.out.println("testing instance B:");
110 | ClassB b = instB.objSelf();
111 | b.update();
112 | b.draw();
113 | b.showInfo();
114 | b.showInfo("sample test");
115 |
116 | System.out.println("testing instance C:");
117 | ClassC c = instC.objSelf();
118 | c.update();
119 | c.draw();
120 | c.showInfo();
121 | c.showInfo("sample test");
122 |
123 | c.reset();
124 |
125 | //Obviously, this greatly reduces the coupling and workload of the code, and you can use less code to complete similar tasks, especially when there are far more sub-classes.
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/core/src/main/java/dynamilize/FunctionType.java:
--------------------------------------------------------------------------------
1 | package dynamilize;
2 |
3 | import dynamilize.classmaker.ClassInfo;
4 |
5 | import java.lang.invoke.MethodType;
6 | import java.lang.reflect.Executable;
7 | import java.lang.reflect.Method;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.Stack;
11 |
12 | /**函数类型封装对象,记录函数的参数类型用于比对和搜索函数
13 | *
14 | * @author EBwilson */
15 | public class FunctionType{
16 | /**复用回收区容量,改数值通常不需要设置,但如果您可能需要大规模的递归或大量的并发调用,那么您可能需要将这个限制设置为一个更高的数值*/
17 | public static int MAX_RECYCLE = 4096;
18 |
19 | private static final Class>[] EMPTY = new Class[0];
20 | private static final Stack RECYCLE_POOL = new Stack<>();
21 |
22 | private Class>[] paramType;
23 | private int hash;
24 |
25 | private FunctionType(Class>... paramType){
26 | this.paramType = paramType;
27 | hash = Arrays.hashCode(paramType);
28 | }
29 |
30 | //此类存在频繁的调用,数据量小,使用流处理数据会产生不必要的性能花销,使用for遍历取代流处理
31 | public static Class>[] wrapper(Class>... clazz){
32 | for(int i = 0; i < clazz.length; i++){
33 | clazz[i] = wrapper(clazz[i]);
34 | }
35 | return clazz;
36 | }
37 |
38 | public static Class>[] unwrapped(Class>... clazz){
39 | for(int i = 0; i < clazz.length; i++){
40 | clazz[i] = unwrapped(clazz[i]);
41 | }
42 | return clazz;
43 | }
44 |
45 | public static Class> wrapper(Class> clazz){
46 | if(clazz == int.class) return Integer.class;
47 | if(clazz == float.class) return Float.class;
48 | if(clazz == long.class) return Long.class;
49 | if(clazz == double.class) return Double.class;
50 | if(clazz == byte.class) return Byte.class;
51 | if(clazz == short.class) return Short.class;
52 | if(clazz == boolean.class) return Boolean.class;
53 | if(clazz == char.class) return Character.class;
54 | return clazz;
55 | }
56 |
57 | public static Class> unwrapped(Class> clazz){
58 | if(clazz == Integer.class) return int.class;
59 | if(clazz == Float.class) return float.class;
60 | if(clazz == Long.class) return long.class;
61 | if(clazz == Double.class) return double.class;
62 | if(clazz == Byte.class) return byte.class;
63 | if(clazz == Short.class) return short.class;
64 | if(clazz == Boolean.class) return boolean.class;
65 | if(clazz == Character.class) return char.class;
66 | return clazz;
67 | }
68 |
69 | public static FunctionType inst(List> paramType){
70 | return inst(paramType.toArray(new Class[0]));
71 | }
72 |
73 | public static synchronized FunctionType inst(Class>... paramType){
74 | if(RECYCLE_POOL.isEmpty()) return new FunctionType(paramType);
75 | FunctionType res = RECYCLE_POOL.pop();
76 | res.paramType = paramType;
77 | res.hash = Arrays.hashCode(paramType);
78 | return res;
79 | }
80 |
81 | public static FunctionType inst(Method method){
82 | return inst(method.getParameterTypes());
83 | }
84 |
85 | public static FunctionType inst(Object... param){
86 | return inst(unwrapped(toTypes(param)));
87 | }
88 |
89 | public static Class>[] toTypes(Object... objects){
90 | Class>[] types = new Class[objects.length];
91 |
92 | for(int i = 0; i < types.length; i++){
93 | types[i] = objects[i] == null? void.class: objects[i].getClass();
94 | }
95 |
96 | return types;
97 | }
98 |
99 | public static Class>[] toTypes(List> objects){
100 | Class>[] types = new Class[objects.size()];
101 |
102 | for(int i = 0; i < types.length; i++){
103 | types[i] = objects.get(i) == null? void.class: objects.get(i).getClass();
104 | }
105 |
106 | return types;
107 | }
108 |
109 | public static FunctionType inst(FunctionType type){
110 | return inst(type.paramType);
111 | }
112 |
113 | public static FunctionType from(MethodType type){
114 | return inst(type.parameterArray());
115 | }
116 |
117 | public static FunctionType from(Executable method){
118 | return inst(method.getParameterTypes());
119 | }
120 |
121 | public static FunctionType generic(int argCount){
122 | Class>[] argTypes = new Class[argCount];
123 | Arrays.fill(argTypes, void.class);
124 | return inst(argTypes);
125 | }
126 |
127 | public static String signature(Method method){
128 | return method.getName() + FunctionType.from(method);
129 | }
130 |
131 | public static String signature(String name, Class>... argTypes){
132 | return name + FunctionType.inst(argTypes);
133 | }
134 |
135 | public static String signature(String name, FunctionType type){
136 | return name + type;
137 | }
138 |
139 | public static int typeNameHash(Class>[] types){
140 | return Arrays.hashCode(Arrays.stream(types).map(Class::getName).toArray());
141 | }
142 |
143 | public boolean match(Object... args){
144 | return match(unwrapped(toTypes(args)));
145 | }
146 |
147 | public boolean match(Class>... argsType){
148 | if(argsType.length != paramType.length) return false;
149 |
150 | for(int i = 0; i < paramType.length; i++){
151 | if(argsType[i] == void.class) continue;
152 | if(!paramType[i].isAssignableFrom(argsType[i])) return false;
153 | }
154 |
155 | return true;
156 | }
157 |
158 | public Class>[] getTypes(){
159 | return paramType;
160 | }
161 |
162 | public void recycle(){
163 | if(RECYCLE_POOL.size() >= MAX_RECYCLE) return;
164 |
165 | paramType = EMPTY;
166 | hash = -1;
167 | RECYCLE_POOL.push(this);
168 | }
169 |
170 | @Override
171 | public boolean equals(Object o){
172 | if(this == o) return true;
173 | if(!(o instanceof FunctionType that)) return false;
174 | return paramType.length == that.paramType.length && hashCode() == o.hashCode();
175 | }
176 |
177 | @Override
178 | public int hashCode(){
179 | return hash;
180 | }
181 |
182 | @Override
183 | public String toString(){
184 | StringBuilder b = new StringBuilder("(");
185 |
186 | for(Class> clazz: paramType){
187 | b.append(ClassInfo.asType(clazz).realName());
188 | }
189 | b.append(")");
190 |
191 | return b.toString();
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/baseimpl/src/main/java/dynamilize/DynamicFactory.java:
--------------------------------------------------------------------------------
1 | package dynamilize;
2 |
3 | import dynamilize.classmaker.ASMGenerator;
4 | import dynamilize.classmaker.AbstractClassGenerator;
5 | import dynamilize.classmaker.BaseClassLoader;
6 | import dynamilize.classmaker.ByteClassLoader;
7 |
8 | import java.lang.reflect.Constructor;
9 | import java.lang.reflect.Executable;
10 | import java.lang.reflect.Field;
11 | import java.lang.reflect.Method;
12 | import java.util.Objects;
13 |
14 | /**用于创建{@linkplain DynamicMaker 动态生成器}的工厂类,内部提供了默认生成器的声明
15 | *
16 | * @author EBwilson
17 | * @since 1.6*/
18 | public class DynamicFactory {
19 | protected PackageAccHandler handler;
20 | protected AbstractClassGenerator generator;
21 | protected JavaHandleHelper helper;
22 |
23 | private static final DynamicFactory DEFAULT = new DynamicFactory(){{
24 | setDefaultGenerator();
25 | setDefaultHelper();
26 | setPackageAccHandler(new UnsafePackageAccHandler(generator));
27 | }};
28 |
29 | /**直接获取默认的通用实现实例,该方法获取的动态生成器等价于:
30 | * {@code
31 | * new DynamicFactory().setDefaultGenerator().setDefaultHelper().getMaker();
32 | * }
33 | *
34 | * @see DynamicFactory#setDefaultGenerator()
35 | * @see DynamicFactory#setDefaultHelper()
36 | * @return 一个由默认声明生产的动态生成器*/
37 | public static DynamicMaker getDefault(){
38 | return DEFAULT.getMaker();
39 | }
40 |
41 | /**获取{@linkplain DynamicMaker 动态生成器}实例
42 | *
43 | * @throws NullPointerException 若有必要的属性尚未设置*/
44 | public DynamicMaker getMaker(){
45 | PackageAccHandler handler = this.handler;
46 |
47 | AbstractClassGenerator generator = this.generator;
48 |
49 | Objects.requireNonNull(helper);
50 | Objects.requireNonNull(generator);
51 |
52 | return handler == null? new DynamicMaker(helper) {
53 | @Override
54 | protected Class extends T> generateClass(Class baseClass, Class>[] interfaces, Class>[] aspects) {
55 | return makeClassInfo(baseClass, interfaces, aspects).generate(generator);
56 | }
57 | }: new DynamicMaker(helper) {
58 | @Override
59 | protected Class extends T> generateClass(Class baseClass, Class>[] interfaces, Class>[] aspects) {
60 | return makeClassInfo(baseClass, interfaces, aspects).generate(generator);
61 | }
62 |
63 | @Override
64 | protected Class extends T> handleBaseClass(Class baseClass) {
65 | return handler.handle(baseClass);
66 | }
67 | };
68 | }
69 |
70 | /**设置{@linkplain PackageAccHandler 包私有访问处理器},若不设置则动态生成器不对超类的包私有方法进行委托
71 | *
72 | * @see PackageAccHandler*/
73 | public DynamicFactory setPackageAccHandler(PackageAccHandler handler){
74 | this.handler = handler;
75 | return this;
76 | }
77 |
78 | /**设置将{@linkplain dynamilize.classmaker.ClassInfo 类型描述}生成为Java类对象的{@linkplain AbstractClassGenerator 类型生成器},必要!
79 | *
80 | * @see AbstractClassGenerator*/
81 | public DynamicFactory setGenerator(AbstractClassGenerator generator){
82 | this.generator = generator;
83 | return this;
84 | }
85 |
86 | /**设置对Java层行为进行处理的{@linkplain JavaHandleHelper Java行为支持器},必要!
87 | *
88 | * @see JavaHandleHelper*/
89 | public DynamicFactory setJavaHandleHelper(JavaHandleHelper helper){
90 | this.helper = helper;
91 | return this;
92 | }
93 |
94 | /**使用{@linkplain DynamicFactory#setDefaultGenerator(ByteClassLoader, int) 默认配置}设置类型生成器,字节码加载器使用默认实现{@link BaseClassLoader},目标字节码版本为152(Java1.8)
95 | *
96 | * @see DynamicFactory#setDefaultGenerator(ByteClassLoader, int)
97 | * @see BaseClassLoader*/
98 | public DynamicFactory setDefaultGenerator(){
99 | return setDefaultGenerator(new BaseClassLoader(DynamicFactory.class.getClassLoader()), 52);
100 | }
101 |
102 | /**将类型生成器设置为{@link ASMGenerator}的实现,该实现适用于绝大多数情况的JVM
103 | *
104 | * @param loader 加载字节码为类对象的类加载器
105 | * @param byteLevel 目标字节码级别,最低支持50(Java1.8)
106 | *
107 | * @see ASMGenerator*/
108 | public DynamicFactory setDefaultGenerator(ByteClassLoader loader, int byteLevel){
109 | if (byteLevel < 52 || byteLevel > 255)
110 | throw new IllegalArgumentException("illegal byte code level: " + byteLevel);
111 |
112 | generator = new ASMGenerator(loader, byteLevel);
113 |
114 | return this;
115 | }
116 |
117 | /**设置{@link JavaHandleHelper}的默认内部实现,该实现直接引用{@link JavaVariable}和{@link JavaMethodEntry}以及默认的反模块化访问
118 | *
119 | * @see JavaVariable
120 | * @see JavaMethodEntry*/
121 | public DynamicFactory setDefaultHelper(){
122 | helper = new JavaHandleHelper() {
123 | @Override
124 | public void makeAccess(Object object) {
125 | if (object instanceof Executable ext){
126 | if (ext instanceof Method method) Demodulator.makeModuleOpen(method.getReturnType().getModule(), method.getReturnType(), DynamicMaker.class.getModule());
127 |
128 | if (ext instanceof Constructor> cstr) Demodulator.makeModuleOpen(cstr.getDeclaringClass().getModule(), cstr.getDeclaringClass(), DynamicMaker.class.getModule());
129 |
130 | for (Class> type : ext.getParameterTypes()) {
131 | Demodulator.makeModuleOpen(type.getModule(), type, DynamicMaker.class.getModule());
132 | }
133 |
134 | ext.setAccessible(true);
135 | }
136 | else if (object instanceof Field field){
137 | Demodulator.makeModuleOpen(field.getType().getModule(), field.getType(), DynamicMaker.class.getModule());
138 |
139 | field.setAccessible(true);
140 | }
141 | else if (object instanceof Class> clazz){
142 | Demodulator.makeModuleOpen(clazz.getModule(), clazz.getPackage(), DynamicMaker.class.getModule());
143 | }
144 | }
145 |
146 | @Override
147 | public IVariable genJavaVariableRef(Field field) {
148 | makeAccess(field);
149 | return new JavaVariable(field);
150 | }
151 |
152 | @Override
153 | public IFunctionEntry genJavaMethodRef(Method method) {
154 | makeAccess(method);
155 | return new JavaMethodEntry(method);
156 | }
157 | };
158 |
159 | return this;
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/usage_sample/src/main/java/com/github/ebwilson/sample_zh/BaseUse.java:
--------------------------------------------------------------------------------
1 | package com.github.ebwilson.sample_zh;
2 |
3 | import dynamilize.*;
4 | import dynamilize.runtimeannos.AspectInterface;
5 | import dynamilize.runtimeannos.Super;
6 | import dynamilize.runtimeannos.This;
7 |
8 | import java.util.Date;
9 | import java.util.HashMap;
10 |
11 | /**这是动态对象的基本使用示例,在下面给出了一个使用动态对象的工作流以向您演示动态对象和动态类型的基本使用方法
12 | *
请首先阅读此案例并掌握动态类型及动态对象的基本使用方法后再阅读应用的案例*/
13 | public class BaseUse {
14 | @SuppressWarnings("unchecked")
15 | public static void main(String[] args) {
16 | //获取默认动态工厂,关于自定义动态工厂实现请参阅高级应用
17 | DynamicMaker maker = DynamicFactory.getDefault();
18 |
19 | //创建动态类型,这是必要的,无论动态类是否有行为,get方法会返回给定名称的动态类型,如果类型尚不存在则会创建一个新的动态类型
20 | DynamicClass Sample = DynamicClass.get("Sample");
21 |
22 | /*===============================
23 | * 如下所示是动态对象的基本使用方法
24 | * 该段落展示最基本的动态对象的行为操作
25 | * ===============================*/
26 |
27 | //使用动态工厂来实例化动态对象,传递一个切面接口限定动态委托的范围,若限定切面为null,那么动态实例将对所有可见方法进行动态委托
28 | HashMap map = maker.newInstance(HashMap.class, new Class[]{Example.class}, Sample).objSelf();
29 |
30 | //强转换为动态对象以调用行为,但实际上maker的newInstance方法创建返回的类型就是DynamicObject,objSelf()方法只是对对象this的一次强类型转换,此处因为泛型转换的问题没有直接使用返回的DynamicObject实例
31 | DynamicObject> dyMap = (DynamicObject>) map;
32 | //设置行为,对put方法进行监视:
33 | dyMap.setFunc("put", (self, su, arg) -> {
34 | su.invokeFunc("put", arg);
35 | //调用超方法,等价于super.put(key, value)
36 |
37 | System.out.println("putting " + arg.get(0) + " -> " + arg.get(1));
38 | }, Object.class, Object.class);
39 | //泛型擦除,对泛型参数的限定需使用类型参数的上界,此方法上界未定,即Object
40 |
41 | //测试打印
42 | map.put("a", "string 1");
43 | map.put("b", "string 2");
44 | map.put("c", "string 3");
45 |
46 | System.out.println("\n===========sep line==========\n");
47 |
48 | //对于动态对象,可以像脚本语言一样使用钩子函数:
49 | Function, Object> hook = dyMap.getFunc("put", Object.class, Object.class);
50 | dyMap.setFunc("put", (self, arg) -> {
51 | hook.invoke(self, arg);//调用钩子
52 | System.out.println("putting now, current entries amount: " + self.objSelf().size());
53 | }, Object.class, Object.class);
54 |
55 | //测试打印
56 | map.put("d", "string 4");
57 | map.put("e", "string 5");
58 | map.put("f", "string 6");
59 |
60 | System.out.println("\n===========sep line==========\n");
61 |
62 | //您也可以用反射式的语句调用动态对象的方法:
63 | System.out.println("reflectional invoke:");
64 | dyMap.invokeFunc("put", "g", "string 7");
65 |
66 | //当然,您也可以以类似的方式去操作对象的字段值:
67 | System.out.println("current entries amount: " + dyMap.getVar("size"));
68 |
69 | /*=======================================================
70 | * 以上是动态对象上的基本操作,到这里您可能对动态类型的作用稍有疑惑
71 | * 您将在这个段落了解到动态类型的用法及意义
72 | * =======================================================*/
73 |
74 | System.out.println("\n===========sep line==========\n");
75 | //上面已经定义过一个动态类型Sample,直接使用它,首先给动态类型声明一个函数:
76 | Sample.setFunction("put", (self, su, arg) -> {
77 | System.out.println("Dynamic class instance handle:");
78 | su.invokeFunc("put", arg);
79 | //这里的语义和对动态类型直接定义是一致的
80 | }, Object.class, Object.class);
81 |
82 | //测试打印,观察打印结果,可以发现调用的过程中最低层次的调用发生了变化
83 | //其实,在动态对象中除部分方法对java方法的引用外,最低层的函数引用是指向动态类型的,只是这一层的默认行为是向上调用或者无行为
84 | //因此,当你改变动态类型中描述的行为时,所有没有中断掉向上的引用的这个动态类型的实例,此方法的行为都会随之改变
85 | map.put("i", "string 8");
86 | map.put("j", "string 9");
87 | map.put("k", "string 10");
88 |
89 | System.out.println("\n===========sep line==========\n");
90 |
91 | //同样的,如果新增函数
92 | Sample.setFunction("putTime", (self, arg) -> {
93 | System.out.println("current time: " + new Date());
94 | self.invokeFunc("put", arg.get(0), new Date().toString());
95 | }, String.class);
96 | dyMap.invokeFunc("putTime", "currTime");
97 |
98 | //从map中获取currTime,可见给动态类型设置的行为被同步到了它的实例当中
99 | System.out.println("get time entry, res: " + map.get("currTime"));
100 |
101 | System.out.println("\n===========sep line==========\n");
102 |
103 | //当然,使用lambda为对象设置行为有些繁琐,为动态类型定义方法还有更为方便的形式
104 | //在下方,我们定义了一个类型Template作为类型样板,在此使样板类型生效
105 | Sample.visitClass(Template.class, maker.getHelper());
106 |
107 | //测试打印
108 | System.out.println("get: " + map.get("a"));
109 | System.out.println("get: " + map.get("b"));
110 | System.out.println("get: " + map.get("c"));
111 |
112 | System.out.println("\n===========sep line==========\n");
113 |
114 | //另外,动态类型也是可以被继承的,就像如下所示
115 | DynamicClass SampleChild = DynamicClass.declare("SampleChild", Sample);
116 | HashMap map1 = maker.newInstance(HashMap.class, new Class[]{Example.class}, SampleChild).objSelf();
117 |
118 | SampleChild.setFunction("put", (self, su, arg) -> {
119 | su.invokeFunc("put", arg);
120 | System.out.println("current map: " + self);
121 | }, Object.class, Object.class);
122 |
123 | //测试打印,观察结果,对象从其超类继承了put方法的行为,而此类型定义的行为紧随之后执行,容易看出动态类型继承的行为和java本身的类继承行为非常相似
124 | map1.put("abc", "extend sample 1");
125 | map1.put("def", "extend sample 2");
126 | map1.put("ghi", "extend sample 3");
127 |
128 | //至此,关于动态类型的基本的使用方法说明就结束了,接下来会在案例中的其他文件中展示一些具体的应用,请首先将基本使用方法掌握后再阅读后续的案例
129 | }
130 |
131 | //使用java定义方法的模板,令对象直接从java类型中引用它的方法,使程序语义更清晰
132 | static class Template{
133 | //用于定义行为的方法必须是静态的,this指针通过第一个参数上添加@This注解传入,super则是第二个参数使用@Super注解,位置不可交换,但可以省略,譬如此处的self其实就是不必要的
134 | //在this和super之后的参数配合方法的名称进行签名,这个例子的签名等价于 public Object get(Object key),会覆写map的行为
135 |
136 | //另外,使用动态类型时,this指针的类型就是不确定的了,所以通常来说不指定它的泛型限定类,但对于只会用于一个合法的java类层次结构的动态类,你可以为它分配一个确切的类型以更方便的使用,
137 | public static Object get(@This DynamicObject> self, @Super DataPool.ReadOnlyPool su, Object key){
138 | System.out.println("getting entries, key: " + key);
139 | return su.invokeFunc("get", key);
140 | //此处类型不确切,所以使用反射调用方法
141 | }
142 | }
143 |
144 | /**定义切面接口,用于限定动态委托的处理范围*/
145 | @AspectInterface
146 | public interface Example{
147 | void put(Object k, Object v);
148 | Object get(Object k);
149 | }
150 | }
--------------------------------------------------------------------------------
/core/src/main/java/dynamilize/PackageAccHandler.java:
--------------------------------------------------------------------------------
1 | package dynamilize;
2 |
3 | import dynamilize.classmaker.ClassInfo;
4 | import dynamilize.classmaker.CodeBlock;
5 | import dynamilize.classmaker.Parameter;
6 | import dynamilize.classmaker.code.IClass;
7 | import dynamilize.classmaker.code.ILocal;
8 | import dynamilize.classmaker.code.IMethod;
9 |
10 | import java.lang.reflect.Constructor;
11 | import java.lang.reflect.Method;
12 | import java.lang.reflect.Modifier;
13 | import java.util.Arrays;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 |
17 | /**包私有方法访问提升使用的工具类,该类用于对一个目标类创建一串用于提升包私有方法的继承子树,以达到对包私有方法进行重写的目的
18 | *
具体来说,将目标基类传入{@link PackageAccHandler#handle(Class)}方法以后,会依次检查此类型的,每一个父类型中是否存在包私有的方法,
19 | * 若存在包私有方法,那么就会使用这个类的包名对上一层类型继承一次,通过{@link PackageAccHandler#loadClass(ClassInfo, Class)}将这个类加载到同一保护域,
20 | * 此时,此次继承类型即可访问目标类包私有方法,重写并将其访问修饰符提升为{@code protected},如此完成对基类所有超类的遍历后即可访问所有该类层次结构中的包私有方法
21 | *
22 | * 直观的说,这个类做的事情如下:
23 | *
{@code
24 | * 假设有下面几个类:
25 | *
26 | * package pac1;
27 | * public class A{
28 | * void method1(){ //包私有方法
29 | *
30 | * }
31 | *
32 | * public void test(){
33 | * method1();
34 | * }
35 | * }
36 | *
37 | * package pac2;
38 | * import pac1.A;
39 | * public class B extends A{
40 | * void method2(){ //包私有方法
41 | *
42 | * }
43 | *
44 | * @Override
45 | * public void test(){
46 | * super.test();
47 | * method2();
48 | * }
49 | * }
50 | *
51 | * 如果对handle方法传入B类,那么会创建如下两个类型:
52 | *
53 | * package pac2:
54 | * public class B$packageAccess$0 extends B{
55 | * @Override
56 | * protected void method2(){
57 | * super.method2();
58 | * }
59 | * }
60 | *
61 | * package pac1:
62 | * import pac2.B$packageAccess$0;
63 | * public class A$packageAccess$0 extends B$packageAccess$0{
64 | * @Override
65 | * protected void method1(){
66 | * super.method2();
67 | * }
68 | * }
69 | *
70 | * 最后handle方法会将类对象pac1.A$packageAccess$0返回,此时,所有包私有方法都已被提升为protected,其子类对两个包私有方法的重写,在调用test方法时都会生效
71 | * }
72 | * 注意:
73 | * - 以上所示的跨包继承同包类的方法重写实际上在java编译器中是不合法的,但在JVM当中此逻辑有效,上述代码仅作逻辑示意
74 | * - 由于java包命名空间限制的问题,无法正常从外部加载java开他包名的类型,所以开放包私有方法对包名以“java.”开头的类不生效
75 | *
76 | *
77 | * @author EBwilson
78 | * @since 1.6*/
79 | @SuppressWarnings("unchecked")
80 | public abstract class PackageAccHandler {
81 | public static final int PAC_PRI_FLAGS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
82 | public static final ILocal[] A = new ILocal[0];
83 | private final Map, Class>> classMap = new HashMap<>();
84 |
85 | public Class extends T> handle(Class baseClass) {
86 | return (Class extends T>) classMap.computeIfAbsent(baseClass, c -> {
87 | Class> curr = c;
88 | Class> opening = null;
89 |
90 | while (curr != null) {
91 | if (shouldOpen(curr)) {
92 | ClassInfo> ci = makeClassInfo(opening == null ? ClassInfo.asType(curr) : ClassInfo.asType(opening), curr);
93 | opening = loadClass(ci, curr);
94 | }
95 |
96 | curr = curr.getSuperclass();
97 | }
98 |
99 | return opening == null? c: opening;
100 | });
101 | }
102 |
103 | protected boolean shouldOpen(Class> checking){
104 | if (checking.getPackage().getName().startsWith("java.")) return false;
105 |
106 | for (Method method : checking.getDeclaredMethods()) {
107 | if ((method.getModifiers() & PAC_PRI_FLAGS) == 0){
108 | return true;
109 | }
110 | }
111 | return false;
112 | }
113 |
114 | @SuppressWarnings("rawtypes")
115 | protected ClassInfo extends T> makeClassInfo(ClassInfo> superClass, Class> base){
116 | ClassInfo> res = new ClassInfo<>(
117 | Modifier.PUBLIC,
118 | base.getName() + "$packageAccess$" + superClass.name().hashCode(),
119 | superClass
120 | );
121 |
122 | ClassInfo> baseC = ClassInfo.asType(base);
123 |
124 | for (Method method : base.getDeclaredMethods()) {
125 | if ((method.getModifiers() & PAC_PRI_FLAGS) == 0){
126 | IMethod, ?> sup = baseC.getMethod(
127 | ClassInfo.asType(method.getReturnType()),
128 | method.getName(),
129 | Arrays.stream(method.getParameterTypes()).map(ClassInfo::asType).toArray(ClassInfo[]::new)
130 | );
131 |
132 | CodeBlock> code = res.declareMethod(
133 | Modifier.PROTECTED,
134 | method.getName(),
135 | ClassInfo.asType(method.getReturnType()),
136 | Parameter.asParameter(method.getParameters())
137 | );
138 |
139 | ILocal self = code.getThis();
140 | if (method.getReturnType() == void.class){
141 | code.invokeSuper(
142 | self,
143 | sup,
144 | null,
145 | code.getParamList().toArray(A)
146 | );
147 | }
148 | else{
149 | ILocal ret = code.local(ClassInfo.asType(method.getReturnType()));
150 |
151 | code.invokeSuper(
152 | self,
153 | sup,
154 | ret,
155 | code.getParamList().toArray(A)
156 | );
157 | code.returnValue(ret);
158 | }
159 | }
160 | }
161 |
162 | for (Constructor> constructor : superClass.getTypeClass().getDeclaredConstructors()) {
163 | if ((constructor.getModifiers() & PAC_PRI_FLAGS) == 0 && !(base.getPackage().equals(superClass.getTypeClass().getPackage()))) continue;
164 | if ((constructor.getModifiers() & (Modifier.PRIVATE | Modifier.FINAL)) != 0) continue;
165 |
166 | IMethod, ?> su = superClass.getConstructor(Arrays.stream(constructor.getParameterTypes()).map(ClassInfo::asType).toArray(IClass[]::new));
167 |
168 | CodeBlock> code = res.declareConstructor(Modifier.PUBLIC, Parameter.asParameter(constructor.getParameters()));
169 | code.invoke(code.getThis(), su, null, code.getParamList().toArray(A));
170 | }
171 |
172 | return (ClassInfo extends T>) res;
173 | }
174 |
175 | /**将目标{@linkplain ClassInfo 类型信息}加载为与基类型同一保护域的对象,根据目标运行平台实现该方法*/
176 | protected abstract