grails: findallbyidinlist method - grails

In my grails project, I've used the method Object.findAllByIdInList(), passing a list as parameter.
The code used is the following:
def allSelectedIds = ReceiptItem.findAllByIdInList(par)
In which the ReceiptItem is a domain class defined as follows:
class Receipt {
double totalAmount;
Date releaseDate;
int vatPercentage;
int discount;
Boolean isPayed;
Boolean isInvoice;
static belongsTo = [patient:Patient]
static hasMany = [receiptItems:ReceiptItem]
static constraints = {
receiptItems(blank: false)
patient(blank: false)
totalAmount(blank: false)
vatPercentage(blank: false, nullable: false)
}
}
and par is the list of ids defined as follows:
def par = params.list("receiptItemsSelected")
receiptItemsSelected is defined in the gsp page into the remoteFunction() as follows:
params: '\'receiptItemsSelected=\' + jQuery(this).val()'
The problem is that the line above throws the following exception:
java.lang.String cannot be cast to java.lang.Long. Stacktrace follows:
Message: java.lang.String cannot be cast to java.lang.Long
I don't understand why it is throwing this exception.
Thanks for your help

Probably list par has ids as String. Generally id for domain objects is stored as Long. Try this instead
ReceiptItem.findAllByIdInList(par*.toLong())
*Also make sure that id represented as string isNumber().
assert !'C'.isNumber()
assert '4'.isNumber()

Related

String constant reference as value of Annotation attribute causes compile error

I am using my properties file to get the values for #Scheduled annotation attributes.I am able to get the values from properties file but when I tries to pass String constant reference to Annotation attribute then compile time exception is raised.
#Slf4j
#CompileStatic
class TestJobService {
static lazyInit = false
public static String jobInterval = getSomePropertiesFileValues?.fixedRateInMS instanceof String? getSomePropertiesFileValues.fixedRateInMS:'10000'
#Scheduled(fixedDelayString = TestJobService.jobInterval)
void executeEveryTenSeconds() {
def date = new Date()
println date.format('yyyy/MM/dd HH:mm', TimeZone.getTimeZone('IST'))
}
}
Attribute 'fixedDelayString' should have type 'java.lang.String'; but
found type 'java.lang.Object' in
#org.springframework.scheduling.annotation.Scheduled
Then I tried to use String to pass like:
#Slf4j
#CompileStatic
class TestJobService {
static lazyInit = false
#Scheduled(fixedDelayString = '${getSomePropertiesFileValues.fixedRateInMS}')
void executeEveryTenSeconds() {
def date = new Date()
println date.format('yyyy/MM/dd HH:mm', TimeZone.getTimeZone('IST'))
}
}
OR
public static final String jobInterval = getSomePropertiesFileValues?.fixedRateInMS instanceof String? getSomePropertiesFileValues.fixedRateInMS:'10000'
prevents the variable from being treated as an inline constant and compiler complains of not being inline constant.
I understand that using single quote '${getSomePropertiesFileValues.fixedRateInMS}'we can get compiler to know that I want GString behaviour. But I don't know is this a bug in Groovy or its a functionality which I need to implement in some other way to pass the string values as annotation attributes. Any lead or any help is highly appreciable.

Grails data binding: creating instances of an abstract class with a Map hasMany

Similar to my last question (Grails databinding: creating instances of an abstract class), I want to use data binding with a class that contains a collection of abstract classes with a hasMany relationship, but in this case, instead of using a List, I'm using a Map.
I created a smalll project with a failing integration test to show the problem that can be found in Github, run it with:
grails test-app -integration -echoOut DataBinding
Anyway, I'll explain the problem by describing the classes and the test here:
class LocalizableContent {
Map contentByLocale = [:].withDefault { locale -> new Text() }
static hasMany = [ contentByLocale : Content ]
}
abstract class Content {
static belongsTo = [ localizableContent : LocalizableContent ]
static constraints = {
localizableContent nullable:true
}
}
class Text extends Content {
String text
}
As you can see, I'm already using the withDefault trick, but apparently it's not being called by Grails / Spring (I even tried to throw an exception in the default closure to verify that the code is not executed).
For the sake of the test, I also created a LocalizableContentController which is empty. With all that, the following integration test then fails:
void testMapDatabinding() {
def rawParams = [ 'contentByLocale[en].text': 'Content' ]
def controller = new LocalizableContentController()
controller.request.addParameters(rawParams)
controller.request.setAttribute(GrailsApplicationAttributes.CONTROLLER, controller)
def localizableContent = new LocalizableContent(controller.params)
assert localizableContent?.contentByLocale['en']?.text == 'Content'
}
It says that localizableContent.contentByLocale is a map which looks like ['en': null], so apparently the data binding is understanding the map syntax and trying to create an entry for the 'en' key. But is not trying first to get the entry for that key, since the withDefault is not being called.
The following one tests that the withDefault works fine, and it passes:
void testMapByDefaultWithNoDatabinding() {
assert new LocalizableContent().contentByLocale['en']?.getClass() == Text
}
What am I missing here?
withDefault is nothing but a pattern to provide a valid value if you face an unknown key. For example, consider the below use case:
def map = [:].withDefault{k->
println k //Should print 'a'
10
}
map.test = 32
assert map.test == 32
assert map.a == 10
It takes the unknown key as the parameter, you cannot pass in any value to it, which is kind of logical, because it provides a default value instead of a value being provided.
In your case, the data binding would work if set the value to Text like:
Map contentByLocale = [:].withDefault { locale ->
//locale is the key. 'en' in this case
new Text(locale: locale, text: 'Content')
}
provided you have your Text class defined as
class Text extends Content{
String locale
String text
}

Using Custom Validator on List

I have a Command Object as follows :
class TestCreationCommand {
String title
List testItems = [].withLazyDefault {new VocabQuestion()}
static constraints = {
title(blank:false,maxLength:150)
testItems( validator: { ti ->
ti.each {it.validate()}
} )
}
}
Test Items is a list of VocabQuestion objects. VocabQuestion is as follows :
class VocabQuestion {
static constraints = {
question(blank:false,maxLength:150)
answer(blank:false,maxLength:40)
}
static belongsTo = [vocabularyTest: VocabularyTest]
String question
String answer
}
I'm attempting to validate the constraints on the VocabQuestion using a custom vaildator ( in the constraints of the Command class above ), but I keep getting the following error message.
Return value from validation closure [validator] of property [testItems] of class [class vocabularytest.TestCreationCommand] is returning a list but the first element must be a string containing the error message code
I have had many different attempts at this .....
I am not sure what the message is telling me or how to go about debugging what the return value from the closure is.
Can anyone provide me any pointers?
You are not returning what Grails understands. You can't expect to just return anything and have Grails know what to do with it. Return a boolean or an error string.
static constraints = {
title(blank:false,maxLength:150)
testItems( validator: { ti ->
Boolean errorExists = false
ti.each {
if (!it.validate()) {
errorExists = true
}
}
errorExists
})
}
Check out this SO question It might be the format of the validator you need.
The .every will return a boolean.

Instantiated a class, but it appears referenced to null

I'm trying to instantiate an object and set a single attribute on it, which comes from a request parameter, like so :
println "Question text from the request :" + params.question
def question = new SurveyQuestion()
question.question = params.question
println "this is our question" + question
This is my output in the console :
Question text from the request :test this is our
questionroosearch.SurveyQuestion : null
And this is the SurveyQuestion class :
class SurveyQuestion {
String question
static hasMany = [responses : SurveyQuestionResponse]
static belongsTo = [survey: Survey]
static constraints = {
}
}
The above seems to compile ok, however I get further classcast exceptions when I do a redirect at the end of my action, I believe this is due to the instantiating and setting of that SurveyQuestion, as if I comment out the above I don't get this failure behaviour.
Am I instantiating the SurveyQuestion object correctly? Why does it display as null when I print it to the console? Is that normal behaviour? At the least I'd expect it to print the object reference as Java would?
Thanks
The default toString() method on a domain instance will return a string which looks like class.name: id. As your newly created domain instance doesn't have id set is shows null.
Try overriding toString() in your SurveyQuestion domain:
String toString() {
return question
}

Grails Build Test Data Plugin - MissingMethodException when calling DomainObject.build()

The Crux
I am getting the following error in my unit test when calling MyDomainObject.build() via the Build Test Data plugin:
The Exception
groovy.lang.MissingMethodException: No signature of method: us.maponline.pesticide.PesticideProfile.addToApplicators() is applicable for argument types: (us.maponline.pesticide.PesticideApplicator) values: [us.maponline.pesticide.PesticideApplicator : null]
Possible solutions: getApplicators()
at grails.buildtestdata.handler.NullableConstraintHandler.addInstanceToOwningObjectCollection(NullableConstraintHandler.groovy:121)
at grails.buildtestdata.handler.NullableConstraintHandler.populateDomainProperty(NullableConstraintHandler.groovy:88)
at grails.buildtestdata.handler.NullableConstraintHandler.handle(NullableConstraintHandler.groovy:17)
at grails.buildtestdata.DomainInstanceBuilder.createMissingProperty(DomainInstanceBuilder.groovy:187)
at grails.buildtestdata.DomainInstanceBuilder.populateInstance(DomainInstanceBuilder.groovy:147)
at grails.buildtestdata.DomainInstanceBuilder.build(DomainInstanceBuilder.groovy:124)
at grails.buildtestdata.DomainInstanceBuilder.build(DomainInstanceBuilder.groovy:123)
at grails.buildtestdata.BuildTestDataService$_addBuildMethods_closure1.doCall(BuildTestDataService.groovy:25)
at us.maponline.pesticide.PesticideLogServiceTests.testSaveLog(PesticideLogServiceTests.groovy:20)
| Completed 1 unit test, 1 failed in 5289ms
per the stack trace, this is happening within the buildtestdata plugin code. It seems that my class, PesticideApplicator, is null when it is being added to the PesticideProfile class.
How is it possible that the class I'm asking to be built is null when being passed to the PesticideProfile?
Source Code
Test Case
#TestFor(PesticideLogService)
#Build([PesticideLog,PesticideApplicator,PesticideProfile])
class PesticideLogServiceTests
{
void testSaveLog() {
PesticideApplicator applicator = PesticideApplicator.build()
def result = service.createLog(applicator, new Date())
result.errors.each {
log.info "got an error. field = $it.field, message:$it.defaultMessage, rejected value = $it.rejectedValue "
}
assert result: 'no result returned'
assert result.success: 'save failed'
assert result.result instanceof PesticideLog: "result was not PesticideLog"
assert applicator.user.pesticideLogs.size() > 0 : 'expected at least on log to be created.'
}
}
PesticideProfileLog
class PesticideProfile
{
def User user
String companyName
static constraints = {
}
static belongsTo = User
static hasMany = [sites: PesticideSite, applicators: PesticideApplicator]
}
PesticideApplicator
class PesticideApplicator
{
String firstName
String lastName
String company
PesticideApplicatorLicense licenseType
Phone phoneNumber
static belongsTo = [profile:PesticideProfile]
static constraints = {
company blank: false, maxSize: 55
firstName blank: false, maxSize: 55
lastName blank: false, maxSize: 100
phoneNumber nullable: true
}
static mapping = {
licenseType length: 55
}
def getUser(){
profile?.user
}
}
Thanks for all your help!
The issue is caused by the build test data plugin attempting to set the value of the user in the PesticideApplicator. The problem is that getUser() isn't a field, it's just a utility helper:
...
def getUser(){
profile?.user
}
...
Removing getUser() from the PesticideApplicator solved the problem.
That said, I'd still like a helper method to access the user (good to not let my code know about the innards of another class). Marking the method #Transient didn't work; the error still appeared. Short of renaming the method, how can I instruct the build test data plugin to ignore this getter?
Thanks!

Resources