I am trying to create an instance of a domain class inside a grails 2.3.6 script:
def player = new Player(name:"Bob")
player.save()
But I keep getting an exception
java.lang.NoClassDefFoundError: gaming/Player
I've tried all the different bootstrapping tricks I've managed to find on the internet but they don't really change the result:
I've tried importing:
import gaming.Player
I've tried loading the bootstrap script:
includeTargets << grailsScript("_GrailsBootstrap")
I've tried depending on every task I managed to find:
depends(configureProxy, packageApp, classpath, loadApp, configureApp, compile, bootstrap)
I've even tried loading the class at runtime:
ApplicationHolder.application.getClassForName("gaming.Player")
Interestingly enough, this last line doesn't barf which suggests that grails can find my class, but chooses to ignore the find when I actually go to use it.
Edit. As requested, here is the current version of the script
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)
You do not have to do all the boiler plate effort to bring up the environment while running your script. run-script
does that for you. When grails run-script
is used following targets are run by default: checkVersion, configureProxy, bootstrap
. And finally the script run-script
is run.
run-script runs your custom script in GroovyShell
by providing ApplicationContext
and grailsApplication
as bindings to shell. So what you would end up with your script is shown below as if it is written in Groovy console/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)
}
}
And then use run-script
as below:
grails run-script scripts/player/PlayerScript.groovy
which would by default run the script in dev environment. If you want for other envirnments then use as
grails test run-script scripts/player/PlayerScript.groovy
BUT
Due to a major bug in latest version of grails, you won't be able to run script the above mentioned way because run-script
always depends on bootstrap
target and would always try to bring tomcat
up while running script as the plugin scope in build
which would result in Error loading plugin manager: TomcatGrailsPlugin . The workaround is also mentioned in the defect but here is a groovier implementation. Change in BuildConfig.groovy
as:
plugins {
if ( !System.getProperty("noTomcat") ) {
build ":tomcat:7.0.52.1"
}
....
}
and then issue run-script command as:
grails -DnoTomcat=true run-script scripts/player/PlayerScript.groovy
On a side note, the reason your script was not running is that the class Player
will not be loaded at this time while running script, for use. It has to be loaded manually using classLoader
and then create an instance off of it. Something like:
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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.