NewDev
NewDev

Reputation: 91

Grails stack overflow error when trying to serialize domain class to JSON

More beginner problems for me with Groovy/Grails.

Groovy version 2.4.8 Grails version 2.5.1

I have tried multiple ways to serialize an instance of one of my domain classes or an ArrayList of instances of that domain class.

When trying to serialize a single instance I get a stack overflow error.

The code and stack trace is shown below

def getAdvisors(String keystrokes, String firm) {
    def advisors = priceBlotterService.advisorsForKeystrokes(keystrokes, "", 30)
    def a1 = advisors[0]
    def json = JsonOutput.toJson(a1)
}

Caused by InvocationTargetException: null
->>  198 | doFilter  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     63 | doFilter  in grails.plugin.cache.web.filter.AbstractFilter
|   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
|    615 | run       in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run . . . in java.lang.Thread
Caused by StackOverflowError: null
->>  100 | invoke    in org.codehaus.groovy.reflection.CachedMethod
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     62 | getProperty in groovy.lang.MetaBeanProperty
|     42 | getValue  in groovy.lang.PropertyValue
|    388 | getProperties in     org.codehaus.groovy.runtime.DefaultGroovyMethods
|    290 | writeObject in groovy.json.JsonOutput
|    329 | writeArray in     ''
|    286 | writeObject in     ''
|    424 | writeMap  in     ''
|    294 | writeObject in     ''
|    329 | writeArray in     ''
|    286 | writeObject in     ''
|    424 | writeMap  in     ''

Advisor, Case, and Firm Classes:

class Advisor {
    String firstName
    String lastName
    String fullName
    String city
    String state
    Firm firm
    static belongsTo = [Case, Firm]
    static hasMany = [cases:Case]
    static constraints = {
    }
}


class Case {
   String caseCode
   String internalComment
   String externalComment
   Date dateCreated
   String createdBy
   Date dateUpdated
   String updatedBy

   static belongsTo = [owner:User, caseStatusType:CaseStatusType]
   static hasMany = [advisor:Advisor]
   static mapping = {
       dateCreated sqlType: "date"
       dateUpdated sqlType: "date"
   }
   static constraints = {
       dateCreated(nullabe: false)
       dateUpdated(nullable: false)
   }
}

class Firm {
    String name
    static constraints = {
    }
}

Edit:

I found a fundamental problem with my domain class/table that could have something to do with this and needs to be resolved.

I try to do a simple get from the user table and I get an error message indicating there is no id field. Having a hard time figuring out what is going on. Some details are below.

line of code

User[] users = User.findAll()

error message

org.springframework.jdbc.BadSqlGrammarException: Hibernate operation: could not extract ResultSet; bad SQL grammar [n/a]; nested exception is org.postgresql.util.PSQLException: ERROR: column this_.id does not exist Position: 8

User class

class User {
    String firstName
    String lastName

    static constraints = {
    }
}

ddl for user table

CREATE TABLE "user"
(
    id BIGINT DEFAULT nextval('user_id_seq'::regclass) PRIMARY KEY NOT NULL,
    first_name VARCHAR(30),
    last_name VARCHAR(30),
    version BIGINT
);
CREATE UNIQUE INDEX user_id_uindex ON "user" (id);

Edit:

Fixed issuer with User table/class. User is a keyword in Postresql so I just refactored to EndUser.

Upvotes: 0

Views: 1747

Answers (2)

burns
burns

Reputation: 1121

I can't find this documented anywhere, but don't use JsonOutput for domain objects.

I just ran into a similar issue. DomainObject instances have this "neat" property called all which will return every instance of the domain object.

When JsonOutput tries to serialize your object, it uses DefaultGroovyMethods.getProperties, which includes the all property. This means that your code will cause hibernate to load EVERY copy of your Advisor class into memory.

In my case I ran out of memory. My system got stuck in garbage collection loops.

In your case, when your a1 class is being rendered, it is including the 'all' property, which is the full list of all Advisors. Each Advisor also has an "all" property so it tries to render every advisor. And so on. Eventually giving you your stack overflow.

Upvotes: 0

LeslieV
LeslieV

Reputation: 765

I suspect there is some issue with the data structure you have, which is causing the JSON builder to go into an infinite loop.

You may want to review this for info on issues with dates: https://issues.apache.org/jira/browse/GROOVY-7682

This may work instead:

import grails.converters.JSON
def json = new JSON(a1)

Upvotes: 1

Related Questions