Gradle 在missingProperty之前调用类加载器

Gradle 在missingProperty之前调用类加载器,gradle,groovy,Gradle,Groovy,假设我有一个名为Utils.groovy的脚本: package hello def testMethod() { log.info("hello world") } def propertyMissing(String name) { System.out.println("Loading ${name}.groovy") GroovyScriptEngine gse = new GroovyScriptEngine(&quo

假设我有一个名为
Utils.groovy
的脚本:

package hello

def testMethod() {
    log.info("hello world")
}

def propertyMissing(String name) {
    System.out.println("Loading ${name}.groovy")
    GroovyScriptEngine gse = new GroovyScriptEngine("vars")
    gse.loadScriptByName("${name}.groovy").newInstance()
}

package hello

class Main {
    static void main(String... args) {
        GroovyScriptEngine gse = new GroovyScriptEngine("src")
        Class<Script> scriptClass = gse.loadScriptByName("hello/Utils.groovy")
        def utils = scriptClass.newInstance()

        //def utils = new Utils()

        utils.testMethod()
    }
}
它引用了一个不存在的属性,
log
。但是,
log
作为一个类存在,将由Groovy脚本引擎加载:

void info(Object message) {
    println(message)
}
如果GroovyScript引擎加载了
Utils.groovy
本身,它将调用
propertyMissing
方法并动态加载
log.groovy

下面是加载
Utils.groovy
的示例代码:

package hello

def testMethod() {
    log.info("hello world")
}

def propertyMissing(String name) {
    System.out.println("Loading ${name}.groovy")
    GroovyScriptEngine gse = new GroovyScriptEngine("vars")
    gse.loadScriptByName("${name}.groovy").newInstance()
}

package hello

class Main {
    static void main(String... args) {
        GroovyScriptEngine gse = new GroovyScriptEngine("src")
        Class<Script> scriptClass = gse.loadScriptByName("hello/Utils.groovy")
        def utils = scriptClass.newInstance()

        //def utils = new Utils()

        utils.testMethod()
    }
}
现在,让我们实例化
Utils.groovy
的一个新实例并直接执行它,而不是由GSE加载(通过注释掉上面示例中的前三行并取消注释下一行):

不过。我注意到,如果我将
log
属性的名称更改为类路径上不存在的名称(
loggy.info
,例如,并保持
log.groovy
文件名不变),它最终会调用
propertyMissing
方法(但由于找不到不存在的脚本而失败):

因此,看起来只有在1时才会调用
属性missing
方法。脚本直接实例化,它引用了一个缺少的属性,该属性的名称不在类路径或2上。该脚本由GSE加载

所以我的问题是,Groovy为什么会尝试首先定位类,而不是为GSE未加载的对象调用
propertyMissing
?有没有办法改变这种行为

注意:
vars
src
都在项目的类路径中。
另请注意:我运行这些文件时,首先通过
groovyc
运行它们,然后使用
java
运行它们。如果“log”是一种类型,则在编译过程中会将其解析为log。如果希望“log.info(…)”始终尝试动态属性,可以编写“this.log.info(…)”。Groovy允许您编写更短的类文本,因此“log”被解释为“log.class”,这解释了对“info”的静态方法搜索。

如果在类路径中有一个名为log的类,这是非常合乎逻辑的。java/groovy试图加载这个类。我的意思是类加载器总是在属性丢失之前运行。在一种情况下,您不在类路径中记录类。如果出现错误,类路径中会有一个类日志。不一定。对于直接实例化的类,类加载器只在前面。如果它是由GSE加载的,则首先是propertyMissing。如果您尝试
String.format()
-您没有实例化它-groovy应该如何确定String是类而不是属性?我相信classloader总是第一位的。我在谈论Main.groovy中的行。如果直接实例化对象(
def utils=new utils()
),则不会首先调用该对象的
propertyMissing
方法,因为缺少与类路径上的类名称匹配的属性。如果通过GSE实例化对象,则首先调用其propertyMissing`方法。很高兴您“相信”类加载器是第一位的,但我的示例显示了另一种情况。
Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: static log.info() is applicable for argument types: (java.lang.String) values: [hello world]
Possible solutions: info(java.lang.Object), find(), any(), find(groovy.lang.Closure), is(java.lang.Object), any(groovy.lang.Closure)
    at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1518)
    at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1504)
    at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:52)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
    at hello.Utils.testMethod(Utils.groovy:4)
    at hello.Utils$testMethod.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
    at hello.Main.main(Main.groovy:11)
Loading loggy.groovy
Exception in thread "main" groovy.util.ResourceException: Cannot open URL: file:/home/wlaw/test/vars/loggy.groovy
    at groovy.util.GroovyScriptEngine.getResourceConnection(GroovyScriptEngine.java:408)
    at groovy.util.GroovyScriptEngine.loadScriptByName(GroovyScriptEngine.java:552)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrap.invoke(PojoMetaMethodSite.java:213)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
    at hello.Utils.propertyMissing(Utils.groovy:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
    at groovy.lang.MetaClassImpl.invokeMissingProperty(MetaClassImpl.java:890)
    at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1854)
    at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3773)
    at groovy.lang.GroovyObjectSupport.getProperty(GroovyObjectSupport.java:38)
    at groovy.lang.Script.getProperty(Script.java:58)
    at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:310)
    at hello.Utils.testMethod(Utils.groovy:4)
    at hello.Utils$testMethod.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
    at hello.Main.main(Main.groovy:11)