2016-12-01 5 views
1

Мы используем Groovy и Guice на проекте, и я наткнулся на следующую ошибку:Почему закрытие Groovy не имеет доступа к введенному члену класса?

groovy.lang.MissingPropertyException: No such property: myService for class: com.me.api.services.SomeService$$EnhancerByGuice$$536bdaec

Потребовалось немного, чтобы выяснить, но это потому, что я ссылки членом частного класса, который был введен, внутри замыкания. Может ли кто-нибудь пролить свет на то, почему это происходит?

Кроме того, есть ли лучший способ сделать это?

Вот фрагмент того, что класс выглядит следующим образом:

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 
    } 

я либо должен использовать стандартный цикл или не использовать впрыскивается элемент, который затем стремится привести к дублированию кода.

+2

Ничего общего с Guice. Поле 'private', поэтому Groovy не создает для него аксессор. –

+1

В простом Groovy поля частного класса доступны из закрытий. Но имейте в виду, что частное поле вводится в экземпляр * class *, а не закрывается. Стратегия разрешения/делегирования закрытия вступает в игру, и что-то нужно искать в закрытии. Попробуйте опубликовать пример, который продемонстрировал вашу проблему более тщательно. –

ответ

1

TLDR;

Либо объявить otherService общественность (удалить private модификатор) или добавить геттер OtherService<Thing> getOtherService(){otherService}

Если вы абсолютно wnat, чтобы избежать воздействия на поле через свойство, вы можете сделать следующий трюк: создать локальную переменную за пределами Закрытие сфера, которая ссылается на вашу службу:

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.

Это означает, что он не может разрешить прямую ссылку на поле. Доступ к символу внутри закрытия сначала будет искать локальные переменные, и если совпадение не найдено, метод getProperty() в Closure будет вызван, чтобы найти свойство, в зависимости от стратегии разрешения, которую вы определили. По умолчанию это 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, вы не получите автоматические методы доступа, поэтому никакие свойства не будут публично выставлены для внешних объектов.

+0

Большое вам спасибо за ответ. Это действительно помогает прояснить ситуацию. Оглядываясь назад, это должно было быть очевидным. ;) –