Search code examples
grailsgroovygrails-orm

Groovy List of domain object not saved and not sorted in controller


I have a groovy domain class. Fields are not mapped to database. Controller creates a list of such object and sort it before send to the view.

instances = instances.sort() { it.part_number }

It didn't sort. And print members of the list returns 0 for integer field, null for String field.

Printing the first element

println instances[0]

resulted in

mypackage.Order : (unsaved)

Why it is unsaved? And not sortable?

It would work if I move my domain class to src/groovy as POGO class. But only when I declareed part_number as String. If part_number is Integer. It would crash.

| Error 2015-01-15 09:17:14,771 [http-bio-8080-exec-2] ERROR errors.GrailsExceptionResolver  - GroovyCastException occurred when processing request: [GET] myapp/showInstances - parameters:
sort: part_number
order: asc
Cannot cast object '259042' with class 'groovy.util.slurpersupport.NodeChildren' to class 'java.lang.Integer'. Stacktrace follows:
Message: Cannot cast object '259042' with class 'groovy.util.slurpersupport.NodeChildren' to class 'java.lang.Integer'

Solution

  • mypackage.Order : (unsaved) is the result of the implementation of toString() that Grails adds to domain classes - it's the full class name with package and the id, or the string (unsaved) if it's not a persistent instance. But other than telling you the class name and that there's no id, it doesn't indicate anything about the contents of other fields and properties.

    The list is very likely sorted, but you're not displaying relevant data from that instance. Try this instead:

    println instances[0].dump()
    

    or more directly

    println instances[0].part_number
    

    Also consider implementing a toString() method that displays class data, e.g.

    String toString() {
       part_number
    }
    

    Note that Grails domain classes abuse the "domain" concept a bit and are always persistent. If you have a POGO class that you want to use as part of your application domain (in the general sense) those should be in src/groovy (or POJOs in src/java). When you change to that, there won't be any Grails-added toString() method so you'll get the default implementation that all classes get (e.g. something like mypackage.Order@48c02bce, the class name with package and hashCode value in hex form)

    EDIT - update based on updated question

    Your XML parsing code is bad. You're storing a groovy.util.slurpersupport.NodeChildren instance which has a toString() result of "259042", but that's neither an Integer nor a String - just an object with data that can be converted to both. The reason it works when you define the property type as String is that anything can be stored by Groovy in a String property - it just calls toString() on it. But there's no support in Groovy for automagically converting a NodeChildren instance that happens to have a stringified number to that number - you need to do that yourself. That's independent of the sorting issue though, so that would need to be discussed in a separate question.