【问题标题】:Intercept all method calls for all metaclasses in groovy拦截groovy中所有元类的所有方法调用
【发布时间】:2018-06-08 00:43:40
【问题描述】:

我正在尝试拦截在 Java 环境中运行的 Groovy 脚本中的所有方法调用。

特别想检查所有方法调用的返回类型,如果是X我想用Y替换。

我知道您可以在 MetaClass 上使用 invokeMethod 进行拦截,但我只能对我编译的脚本类执行此操作。如果脚本依次调用A 类上的方法,那么它将创建一个新的MetaClass[A],如果不早先从注册表中手动获取该 MetaClass 并使用元方法覆盖它,我将无法拦截它。

我曾尝试使用GroovySystem.getMetaClassRegistry() 在创建元类时添加侦听器,在其中添加元方法,但它似乎永远不会触发。

我希望这是自动的,并且不必事先为我应该转换的方法添加注释,或者知道我想要转换哪些类的方法。所有返回X 的方法都应该返回Y

我可以全局拦截所有方法调用吗?

我可以拦截 MetaClass 的创建吗?

我可以添加自动 AST 转换吗?

【问题讨论】:

    标签: java groovy


    【解决方案1】:

    事实证明这是可能的。您需要调用 GroovySystem.getMetaClassRegistry().setMetaClassCreationHandle 来替换 MetaClassCreationHandle。

    由于基类MetaClassCreationHandle 是包私有的,因此从ExpandoMetaClassCreationHandle 扩展可能更容易。但请考虑到,对于您最常见的需求,让您的所有课程都基于ExpandoMetaClass 可能有点过头了。所以我所做的是这样的:

    GroovySystem.getMetaClassRegistry().setMetaClassCreationHandle(new ExpandoMetaClassCreationHandle() {
    
        @Override
        protected MetaClass createNormalMetaClass(Class theClass, MetaClassRegistry registry) {
    
            final List<Method> propertyMethods = new ArrayList<>();
            for (Method method : theClass.getDeclaredMethods()) {
                if (method.getReturnType() == TheMethodReturnTypeYouCareAbout.class) {
                    propertyMethods.add(method);
                }
            }
    
            final MetaClass mc;
            if (propertyMethods.isEmpty() == false) {
    
                final ExpandoMetaClass expando = new ExpandoMetaClass(theClass, true, true);
                for (Method mm : propertyMethods) {
                    final ClassInfo ci = ClassInfo.getClassInfo(mm.getDeclaringClass());
                    expando.addMetaMethod(new MetaMethod() {
    
                        @Override
                        public int getModifiers() {
                            return mm.getModifiers();
                        }
    
                        @Override
                        public String getName() {
                            return mm.getName();
                        }
    
                        @Override
                        public Class getReturnType() {
                            return mm.getReturnType();
                        }
    
                        @Override
                        public CachedClass getDeclaringClass() {
                            return ci.getCachedClass();
                        }
    
                        @Override
                        protected Class[] getPT() {
                            return mm.getParameterTypes();
                        }
    
                        @Override
                        public Object invoke(Object object, Object[] arguments) {
                            try {
                                final Object value = mm.invoke(object, arguments);
                                // Do whatever you need with the value.
                                return value;
                            } catch (Exception ex) {
                                throw new RuntimeException(ex);
                            }
                        }
                    });
                }
    
                mc = expando;
            } else if (GeneratedClosure.class.isAssignableFrom(theClass)) {
                mc = new ClosureMetaClass(registry, theClass);
            } else {
                mc = new MetaClassImpl(registry, theClass);
            }
    
            return mc;
        }
    });
    

    这意味着我们只会为那些需要添加元方法的类创建 Expando 类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 2019-10-05
      • 2010-11-16
      • 2021-12-19
      相关资源
      最近更新 更多