在grails脚本中创建域类的实例

时间:2014-04-10 19:00:20

标签: grails dns bootstrapping

我正在尝试在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")

有趣的是,这最后一行并不是barf,这表明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)

1 个答案:

答案 0 :(得分:3)

在运行脚本时,您无需执行所有锅炉板工作来调出环境。 run-script为你做到了。使用grails run-script后,默认情况下会运行目标:checkVersion, configureProxy, bootstrap。最后运行脚本run-script

run-script通过提供GroovyShellApplicationContext绑定到shell来在grailsApplication中运行自定义脚本。所以你最终会得到你的脚本如下所示,好像它是用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

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

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

<强> BUT
由于最新版本的grails中有major bug,您将无法以上述方式运行脚本,因为run-script始终依赖于bootstrap目标,并且始终会尝试tomcat 1}}运行脚本作为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)