【问题标题】:Why doesn't a Groovy closure have access to injected class member?为什么 Groovy 闭包不能访问注入的类成员?
【发布时间】:2016-12-01 16:14:00
【问题描述】:

我们在一个项目中使用 Groovy 和 Guice,我遇到了以下错误:

groovy.lang.MissingPropertyException:没有这样的属性:myService 类:com.me.api.services.SomeService$$EnhancerByGuice$$536bdaec

花了一点时间才弄明白,但这是因为我引用了一个私有类成员,该成员是在闭包内注入的。谁能解释为什么会发生这种情况?

另外,有没有更好的方法呢?

这是该类的外观的 sn-p:

import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class MyService extends BaseService<Thing> {

    @Inject
    private ThingDao thingDao

    @Inject
    private OtherService<Thing> otherService

    @Override
    List<Thing> findAll() {
        List<Thing> things = this.dao.findAll()

        things.each { 
            //Note: This doesn't work!
            otherService.doSomething()
        }

        things
    }

我要么必须使用标准 for 循环,要么不使用注入的成员,这往往会导致代码重复。

【问题讨论】:

  • 与 Guice 无关。该字段是 private,因此 Groovy 不会为其生成访问器。
  • 在普通的 Groovy 中,私有类字段可以从闭包中访问。但是,请记住,私有字段被注入到 class 实例中,而不是闭包中。闭包的解决/委托策略开始发挥作用,需要在闭包中查找某些内容。尝试发布一个更彻底地展示您的问题的示例。

标签: groovy closures guice


【解决方案1】:

TLDR;

要么声明otherService public(删除private 修饰符)或添加getter OtherService&lt;Thing&gt; getOtherService(){otherService}

如果您绝对希望避免通过属性公开该字段,则可以执行以下技巧:在引用您的服务的闭包范围之外创建一个局部变量:

OtherService<Thing> otherService=this.otherService
things.each { 
        //Note: This will work! Because now there is a local variable in the scope. 
        //This is handled by normal anonymous inner class mechanisms in the JVM.
        otherService.doSomething()
}

说明

在幕后,您的闭包是匿名类的对象,而不是具有您的私有字段 otherService 的对象。

这意味着它无法解析对该字段的直接引用。访问闭包内的符号将首先查看局部变量,如果没有找到匹配项,则会调用Closure 中的getProperty() 方法来查找属性,具体取决于您定义的解析策略。默认情况下,这是OWNER_FIRST

如果你看Closure#getProperty的代码:

        switch(resolveStrategy) {
            case DELEGATE_FIRST:
                return getPropertyDelegateFirst(property);
            case DELEGATE_ONLY:
                return InvokerHelper.getProperty(this.delegate, property);
            case OWNER_ONLY:
                return InvokerHelper.getProperty(this.owner, property);
            case TO_SELF:
                return super.getProperty(property);
            default:
                return getPropertyOwnerFirst(property);
        }

您看到所有者、委托和声明对象需要具有匹配的属性

在 groovy 中,如果您声明一个字段 private,您将不会获得自动生成的访问器方法,因此不会为外部对象公开任何属性。

【讨论】:

    猜你喜欢
    • 2015-07-30
    • 2019-10-20
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    相关资源
    最近更新 更多