【问题标题】:Creating an instance of a domain class inside a grails script在 grails 脚本中创建域类的实例
【发布时间】:2014-04-10 19:00:19
【问题描述】:

我正在尝试在 grails 2.3.6 脚本中创建域类的实例:

def player = new Player(name:"Bob")
player.save()

但我不断收到异常

java.lang.NoClassDefFoundError: gaming/Player

我已经尝试了我在互联网上找到的所有不同的引导技巧,但它们并没有真正改变结果:

我尝试过导入:

import gaming.Player

我已经尝试加载引导脚本:

includeTargets << grailsScript("_GrailsBootstrap")

我已根据我设法找到的每项任务进行了尝试:

depends(configureProxy, packageApp, classpath, loadApp, configureApp, compile, bootstrap)

我什至尝试在运行时加载类:

ApplicationHolder.application.getClassForName("gaming.Player")

有趣的是,最后一行并没有表明 grails 可以找到我的类,但在我实际使用它时选择忽略该查找。

编辑。根据要求,这是脚本的当前版本

import gaming.Player

import org.codehaus.groovy.grails.commons.ApplicationHolder

includeTargets << grailsScript("_GrailsInit")
includeTargets << grailsScript("_GrailsBootstrap")
includeTargets << grailsScript("_GrailsClasspath")

def handleHeaderLine(line) {
    def retval = []
    line.each {
        if(!it.equals("Game Name") && !it.equals("Total # of Copies")) {
            println("Creating Player: " + it)
            def player = new Player(name:it)
            player.save 
            retval << it
        } else {
            retval << null
        }
    }
    return retval;
}

def handleGameLine(header, line) {
    println("Creating Game: " + line[0])
    for(int i = 1; i < line.length - 1; i++) {
        if(!header[i].equals("Total # of Copies")) {
            def count = line[i] == "" ? 0 : Integer.parseInt(line[i]);
            for(int j = 0; j < count; j++) {
                println "Creating copy of " + line[0] + " owned by " + header[i]
            }
        }
    }
}

target(loadAssets: "The description of the script goes here!") {
    depends(configureProxy, packageApp, classpath, loadApp, configureApp, compile, bootstrap)

    ApplicationHolder.application.getClassForName("gaming.Player")

    def tsv = new File("...")

    def header = null;
    tsv.eachLine {
        def line = it.split("\t")
        if(header == null) {
            header = handleHeaderLine(line)
            println header
        } else {
            handleGameLine(header, line)
        }
    }
}

setDefaultTarget(loadAssets)

【问题讨论】:

  • 尝试添加 includeTargets
  • 它已经存在(作为 grails create-script 的一部分)。
  • 能否提供您的Gant 脚本

标签: grails dns bootstrapping


【解决方案1】:

在运行脚本时,您不必做所有的样板工作来调出环境。 run-script 为您做到这一点。当使用grails run-script 时,默认运行以下目标:checkVersion, configureProxy, bootstrap。最后运行脚本run-script

run-script 通过提供ApplicationContextgrailsApplication 作为对shell 的绑定,在GroovyShell 中运行您的自定义脚本。所以你最终得到的脚本如下所示,就好像它是用 Groovy 控制台/shell 编写的一样:

//scripts/player/PlayerScript.groovy
def handleHeaderLine(line) {
    def retval = []
    line.each {
        if(!it.equals("Game Name") && !it.equals("Total # of Copies")) {
            println("Creating Player: " + it)
            def player = new Player(name: it)
            player.save(flush: true) 
            retval << it
        } else {
            retval << null
        }
    }
    return retval
}

def handleGameLine(header, line) {
    println("Creating Game: " + line[0])
    for(int i = 1; i < line.length - 1; i++) {
        if(!header[i].equals("Total # of Copies")) {
            def count = line[i] == "" ? 0 : Integer.parseInt(line[i]);
            for(int j = 0; j < count; j++) {
               println "Creating copy of " + line[0] + " owned by " + header[i]
            }
        }
    }
}

def tsv = new File("...")
def header = null
tsv.eachLine {
    def line = it.split("\t")
    if(header == null) {
        header = handleHeaderLine(line)
        println header
    } else {
        handleGameLine(header, line)
    }
}

然后使用run-script如下:

grails run-script scripts/player/PlayerScript.groovy

默认情况下会在开发环境中运行脚本。如果您想用于其他环境,请使用 as

grails test run-script scripts/player/PlayerScript.groovy

但是
由于最新版本的 grails 中存在 major bug,您将无法以上述方式运行脚本,因为 run-script 始终依赖于 bootstrap 目标,并且在运行脚本时始终尝试将 tomcat 启动为build 中的插件范围,这将导致 加载插件管理器时出错:TomcatGrailsPlugin。缺陷中也提到了解决方法,但这里有一个更规范的实现。将BuildConfig.groovy 更改为:

plugins {
    if ( !System.getProperty("noTomcat") ) {
        build ":tomcat:7.0.52.1"
    }
    ....
}

然后发出 run-script 命令为:

 grails -DnoTomcat=true run-script scripts/player/PlayerScript.groovy

附带说明,您的脚本未运行的原因是在运行脚本时不会加载类Player 以供使用。它必须使用classLoader 手动加载,然后创建一个实例。比如:

includeTargets << grailsScript("_GrailsInit")
includeTargets << grailsScript("_GrailsBootstrap")

target(playerScript: "The description of the script goes here!") {
    depends configureProxy, packageApp, classpath, loadApp, configureApp

    def playerClass = classLoader.loadClass("gaming.Player")

    //Skeptical about how a domain class would behave
    //But a normal POGO should be good being used this way
    def player = playerClass.newInstance([[name: "Bob"]] as Object[])
    player.save(flush: true)

    println player
}

setDefaultTarget(playerScript)

【讨论】:

    猜你喜欢
    • 2015-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多