1

鉴于设置的这种非常简化的再现:

package net.myexample.plugin

class MyExampleService {  
  Map doMunge(Map m) {
    // do stuff to 'm'
    return m
  }
}

/****************************** BREAK: NEXT FILE ******************************/

package net.myexample.plugin

class MyTagLib {
  static namespace = 'p'

  def myExampleService

  def tag = { attrs, body ->
    def m = doMungeAndFilter(attrs.remove('m'))

    out << g.render(template: '/template', plugin: 'my-example-plugin', model: m)
  }

  Map doMungeAndFilter(def m) {
    def mm = myExampleService.doMunge(m)
    // do stuff to 'm'
    return mm
  }
}

/****************************** BREAK: NEXT FILE ******************************/

package net.myexample.app

import net.myexample.plugin.MyExampleService

class MyExampleService extends net.myexample.plugin.MyExampleService {
  def doMunge(def m) {
    def mm = super.doMunge(m)
    // do more stuff to 'mm'
    return mm
  }
}

/****************************** BREAK: NEXT FILE ******************************/

package net.myexample.app

import net.myexample.plugin.MyTagLib

class MyTagLib extends net.myexample.plugin.MyTagLib {
  static namespace = 'a'

  def myExampleService

  def tag = { attrs, body ->
    def m = doMungeAndFilter(attrs.remove('m'))

    out << g.render(template: '/template', plugin: 'my-example-plugin', model: m)
  }

  Map doMungeAndFilter(def m) {
    def mm = super.doMungeAndFilter(m)
   // do more stuff to 'mm'
    return mm
  } 
}

/**
 * But we get an exception that cites that it cannot call 'doMunge' on a null
 * object -- which could only be 'myExampleService'
 */

null当应用程序的标记库上的方法调用其超类(插件上的标记库)时,为什么服务会出现,而后者又调用服务上的方法?

我能想到的最好的理论是该服务实际上并没有在应用程序的 taglib 类中实例化,因为除了def. 我认为是这种情况,因为如果我将所有逻辑从服务类的方法移到 taglib 的方法中,它就会按预期工作。

(为了画全图:MyExampleService.doMunge在其他地方调用,而后面的过滤(in MyTagLib.doMungeAndFilter)只有taglib需要。)

或者:如果我doMungeAndFilter进入另一个服务类,在插件中创建基本版本并在应用程序中扩展它,那效果很好。我认为这是一个可以接受的结论,尽管创建另一个服务类只是为了支持这样的 taglib 感觉有点臃肿。

想法?尖端?明显的错误或遗漏?

4

2 回答 2

1

这只是一个简单的猜测,但您是位于 /grails-app/taglib 下的 taglib 类文件,还是位于 /src 目录的某个位置?我注意到我无法将服务注入(至少是自动地)到位于 /grails-app 文件夹之外的类中。

于 2012-05-25T12:46:08.413 回答
1

def myExampleService从子类 taglib 中删除。Groovy 中的类似属性编译为私有字段以及公共 getter 和 setter,因此在超类 taglib 中隐含

private Object myExampleService;

public void setMyExampleService(Object svc) {
  this.myExampleService = svc;
}
// getter similar

当您myExampleService在子类中再次声明时,子类将获得自己的私有字段(具有相同名称),并且设置器被覆盖以将提供的值存储在此子类字段中,而不是超类字段中。Spring调用setter注入服务,所以最终结果是超类privatemyExampleService永远不会被设置,因此在尝试调用myExampleService.doMunge超类时会出现空指针异常。

子类可以通过继承的 getter 和 setter 访问超类属性,因此不需要重新声明它。

于 2012-11-12T17:57:18.887 回答