Beginner Groovy - grails

I'm following the code examples in 'The Definitive Guide to Grails' by Graeme Keith Rocher, and have come across a rather unusual stumbling block.
Essentially, 2 domain classes exist - Bookmark & Tag.
Bookmark:
class Bookmark {
static hasMany = [tags:Tag]
URL url
String title
String notes
Date dateCreated = new Date()
}
Tag:
class Tag{
static belongsTo= Bookmark
Bookmark bookmark
String name
}
I'm instructed to launch the Grails Console (is this the same as the groovy console)and create a new object as follows.
def b = new Bookmark(url: new URL('http://grails.org/'), title:'Grails', notes:'Groovy')
This results in:
Result: Bookmark : null
According to the book, GORM automatically provides an implementation of an addTag method. So I code...
b.addTag( new Tag(name: 'grails'))
Only to get whammed with the error message:
Exception thrown: No such property: b for class: ConsoleScript1
groovy.lang.MissingPropertyException: No such property: b for class: ConsoleScript1 at ConsoleScript1.run(ConsoleScript1:2)
The author hasn't accounted for this in the book. I was wondering if anyone could help me out?
Thanks.

Are you reading the 1st edition of the book? If so it's quite outdated. The add* methods have been deprecated since 0.5. It was replaced by addTo* so do this instead:
b.addToTags( new Tag(name: 'grails'))
Assuming your code example shouldn't have Bookmarks defined twice (copy and paste error?) and Tag might look like this:
class Tag {
String name
}

The groovy console is not the same as the grails console. To access the grails console, type grails console in your application directory - you should get a Java GUI app. It's possible that the example will work then because grails add some stuff to the standard Groovy.
Also, your problem isn't the addTag method, but the item b that you defined which cannot be found. Try entering the whole script into the console at once and executing it, instead of executing it line by line.

Related

Jenkins | Use method from an imported java class in a groovy script

I want to be able to use a method from a Jenkins plugin via its java class
Just to point out I'm not a developer or a groovy/java expert - happy to learn!
The java class that my method is part of is com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator
From this I would like to use the method getRepoOwner()
What I've done is set my import and defined a new call to the class:
import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator
def bbSCMNav = new BitbucketSCMNavigator()
When I run this I get the error below:
org.codehaus.groovy.runtime.metaclass.MethodSelectionException: Could not find which method <init>() to invoke from this list:
public com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator#<init>(java.lang.String)
public com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator#<init>(java.lang.String, java.lang.String, java.lang.String)
I've searched for the error above Could not find which method <init>() to invoke from this list
And I came across this ticket Could not find which method <init>() to invoke from this list on newInstance in groovy closure
Can't say that I entirerly understand the reply if it's helpful to me or not as I say I'm not a developer and groovy and java are relatively new to me but happy to understand if anyone can point me in the right direction with this
The goal of this exercise is to use the method during the run-time of a build to get the output of getRepoOwner() and use that in a variable to construct a URI
This question also seems similar to mine - Calling internal methods of Jenkins plugin (thinBackup)
But I'm not using maven or a pom.xml here
Cheers
Quick Answer
This error Could not find which method < init >() is related to a missing constructor.
Almost all internal jenkins class are ready to use in groovy.
In your case, BitbucketSCMNavigator does not have a default constructor. It have a constructor with one String argument. Check this line
Explanation
I could replicate your error with another internal class org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory:
node {
stage('internal') {
org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory obj =
new org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory();
}
}
hudson.remoting.ProxyException: org.codehaus.groovy.runtime.metaclass.MethodSelectionException: Could not find which method <init>() to invoke from this list:
private org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory#<init>(org.jenkinsci.plugins.workflow.cps.CpsFlowExecution, boolean, java.lang.ClassLoader, java.util.List)
But, reviewing this class CpsFlowExecution I could see that CpsGroovyShellFactory does not have a default constructor. It have a constructor with one argument : CpsGroovyShellFactory(this)
So, If I instance the constructor with one argument, no errors appear.
node {
stage('internal') {
org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory obj =
new org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory(null);
}
}

How to have geb static content recognized form test script

The example:
Page Class
Page TestPage extends Page{
static at = {blah blah....}
static content = {
someVar {$(By.id("someId"))}
}
}
Script:
class Test extends GebReportingSpec{
def "some Feature Methods"(){
when:
def page1 = at TestPage
page1.someVar.click() //In intellij "someVar" shows as unrecognized
}
}
According to what I have read and researched, in the example above, someVar should autocomplete and be recognized, but it is not. the code still runs and works correctly but someVar still comes up as unrecognized by the autocompiler in Intellij.
The only way I can have the variable be recognized is by creating a getter method for someVar
When I see the answer to this question: Geb authoring support within Intellij-IDEA?
I assume that what I am attempting to do should work but it does not. is there a way to have the static content autocomplete without creating getter methods?
Edit:
Also wanted to add that in my case I am getting the page objects from a jar file. Both the binaries and the sources jars are downloaded and recognized.

Object Id set as null when saving - AjaxDependencySelection

So I decided to use AjaxDependencySelection Plugin for Grails, and it has proven to be very useful. However, I am trying to implement autoComplete boxes, and it does not seem to be saving the object id when using an Autocompleted selection. Here is my implementation in my gsp
<g:selectPrimary id="template" name="template"
domain='dms.nexusglobal.Template'
searchField='templateName'
collectField='id'
domain2='dms.nexusglobal.Tag'
bindid="template.id"
searchField2='tagName'
collectField2='id'
hidden="hiddenNew"
noSelection="['': 'Please choose Template']"
setId="tag"
value="${documentPartInstance?.template}"/>
<g:selectSecondary id="tag" name="tag"
domain2='dms.nexusglobal.Subtag'
bindid="tag.id"
searchField2='subtagName'
collectField2='id'
autocomp="1"
noSelection="['': 'Please choose Tag']"
setId="subtag"
value="${documentPartInstance?.tag}"/>
<g:autoCompleteSecondary id="subtag" name="subtagId"
domain='dms.nexusglobal.Subtag'
primarybind='tag.id'
hidden='tag'
hidden2='hidden5'
searchField='subtagName'
collectField='id'
value='${documentPartInstance?.subtag}'/>
<input type=hidden id="hidden5" name="subtagId" value="${documentPartInstance?.subtag}"/>
However, everytime I save it, I am presented with this error Column 'subtag_id' cannot be null . Here is my domain class definition for Subtag
class Subtag {
static scaffold = true
String subtagName
static belongsTo = [tag : Tag]
public Subtag()
{
}
public Subtag(String s)
{
subtagName = s
}
static constraints = {
}
String toString(){
subtagName
}
}
Tag hasMany subtags as well
It seems to be creating new Subtag instances when using the autoselect box (as an error shows up saying Could not find matching constructor for:packagename.Subtag(java.lang.String) Although this is a feature I am looking to implement in my application at later stages (being able to create new Subtags on the fly when creating a document Part), right now, all I would like to be able to do is just choose from my already existing subtags.
When I add in a string constructor, it comes back with the error that Column subtag_id cannot be null
I have developed it so will try help you through your issue.
The problem is that you are trying to push a value from selectSecondary and update the elementId of g:autocomplete which is actually a seperate entity.
I will update the plugin with a new method, need to test it out first.. Also take a look at g:selectAutoComplete. Although this method would only work if your secondary was the primary task... so no good in that case either..
hang on and look out for 0.37 release
Released 0.37 documentation on how to do such a thing here: https://github.com/vahidhedayati/ajaxdependancyselection/wiki/from-selection-to-autocomplete---how-to

Grails: Understanding groovy DomainClass.properties

I'm having a hard time finding information about grails functionality:
DomainClass.properties = params
In my particular case, I have these classes:
class parameterType = {
String name
String desc
static hasMany = [codes : parameterCode]
...
}
class parameterCode = {
String code
String desc
static belongsTo = [parameterType : parameterType]
}
My parameterType/edit.gsp has name, desc and an html table with its list of parameterCodes
At first, I had some variation of the scaffolded controller on the 'update' action. That (I know its wrong but it was a beginners code) it first deleted all the parameterCodes and then reassociated them (or recreated them).
With Ajax I was sending the data in this format:
id=1234&name=paramName&desc=paramDesc&codes[0].code=code1&codes[0].desc=codeDesc1&codes[1].code=code2&codes[1].desc=codeDesc2
And in the controller I had this:
def parameterTypeInstance = ParameterType.get(params.id)
def toDelete = parameterTypeInstance.parameterCodes
parameterTypeInstance.parameterCodes = []
toDelete.each{it.delete(flush: true)}
//And this "magic" line reassociated all the properties in parameterType And Created his parameterCodes in the data base:
parameterTypeInstance.properties = params
I honestly don't how it works, and I just wanted to know if there's a way of doing the same thing without having to previously delete the associated parameterCodes.
Cheers
**Update:**
I just found what I was looking for in these links:
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/
But I had another error.
These talks about LazyList and decorate(), so I just added the next lines to my ParameterType Class:
def List getExpandableCodeList() {
return LazyList.decorate(codes,FactoryUtils.instantiateFactory(ParameterCode.class))
}
But when I do this in my controller update:
parameterTypeInstance.properties = params
I'm getting this error:
groovy.lang.MissingMethodException: No signature of method: static org.apache.commons.collections.list.LazyList.decorate() is applicable for argument types: (org.hibernate.collection.PersistentSet, org.apache.commons.collections.functors.InstantiateFactory) values: [[cE - EE, cA - AA, cC - CC, cD - DD], org.apache.commons.collections.functors.InstantiateFactory#dd768d]
The data is being recieved in the controller this way:
expandableCodeList[0].desc: AA
expandableCodeList[3].code: cE
expandableCodeList[3].id: 35073
expandableCodeList[1].id: 35076
expandableCodeList[0].code: cA
expandableCodeList[2].code: cD
expandableCodeList[1].desc: CC
expandableCodeList[0].id: 35080
expandableCodeList[3].desc: EE
expandableCodeList[2].id: 35075
Any hints on what I'm doing wrong? should I be sending the data in another format?
Any help would be much appreciated. Thanks.
If I not in error .properties is a method added by groovy to the java.lang.Object , look to this javaodc
There is many way to do what you want to do. Please look to grails documentation on data binding .
For example you can do
bindData(parameterTypeInstance, params, [exclude: parameterTypeInstance.parameterCodes])
look here for more info on bindData
Ok, I'm settings this as an answer:
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
At last, lazylist and the decorate() method was what I was looking for. Sadly it takes to take the child collection as a list and it carries out a lot of other issues for me. But its a good solution if anyone needs to make a view with the parent and its child objects the "simple" way.

Grails Blurb Plugin - Unable to resolve class Blurb

I'm working through the book Grails: A Quick-Start Guide and have come upon a problem. The book has me install the Blurb plugin, which seems to work, but states that we will be using it as if it were a domain class and using it a pre-existing controller. The code that I am to add to the controller looks like this
def blurb = Blurb.findByName("custom_${event.id}" )
if (!blurb){
blurb = new Blurb(name:"custom_${event.id}" , content:"" ).save()
}
When I do this I receive the same error in the IDE and the run output
'unable to resolve class Blurb' and I am directed specifically to this line blurb = new Blurb(name:"custom_${event.id}" , content:"" ).save()
Can anyone tell me what might be going wrong? I'm assuming the plugin is installed properly because if I try to access it's controller/action directly 'http://localhost:8080/TekDays/blurb/create' the plugin's provided view renders properly.
Thanks!
--
For reference I am using STS / Grails 1.3.7
Update 2011.05.12 7:45AM CST
I've attached a screenshot showing my project from the STS interface to show how my project is laid out in the event that it is package related as Burt indicated. The issue though is I'm not sure how do to the import statement so perhaps that screenshot will help.
Here is the current code in the Dashboard Controller.
package tekdays
class DashboardController {
...
}
I've tried adding the following lines per Burt's suggestion, but I obviously don't have it right
package tekdays
package my.package <--unexpected token: package
class DashboardController {
I tried changing out my with tekdays and default and both yield the same result.
Am I doing that wrong?
Thanks!
The Blurb class is in the default package, so if your controller is in a package you'll need to use a Groovy trick to access it:
package my.package
import Blurb as Blurb
class MyController {
def action = {
def blurb = Blurb.findByName("custom_${event.id}" )
if (!blurb) {
blurb = new Blurb(name:"custom_${event.id}" , content:"" ).save()
}
}
}

Resources