rithyskun / google-gson

Automatically exported from code.google.com/p/google-gson
0 stars 0 forks source link

Circular relationship gives stack overflow #530

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
I had some problems with models having a circular relationship.
It resulted in a stackoverflow error when marshalling to Json.
Making the relationship uni-directional solved the problem.
Unfortunately, this is not always possible.

Original issue reported on code.google.com by roger.la...@gmail.com on 12 Aug 2013 at 9:46

GoogleCodeExporter commented 9 years ago
I faced (probably) same error when trying to serialize object created by Gradle 
convention mapping mechanism used in my Gradle plugin

Sort of example flow/steps to create such object in Gradle plugin (Groovy)

MyType myObject = (org.gradle.internal.reflect.)Instantiator.newInstance(MyType)

project.plugins.withType(JavaBasePlugin) {
    myObject.conventionMapping.with {
        fieldInsideMyObject = { project.sourceCompatibility }
    }
}

and when I try to do

(com.google.gson.)Gson.toJson(myObject)

I get following exception

Caused by: java.lang.StackOverflowError
        at com.google.gson.stream.JsonWriter.newline(JsonWriter.java:569)
        at com.google.gson.stream.JsonWriter.beforeName(JsonWriter.java:586)
        at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:401)
        at com.google.gson.stream.JsonWriter.beginObject(JsonWriter.java:307)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:190)
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
        at com.google.gson.internal.bind.ObjectTypeAdapter.write(ObjectTypeAdapter.java:107)
        ...
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
        at com.google.gson.internal.bind.ObjectTypeAdapter.write(ObjectTypeAdapter.java:107)

It happens because Gradle is kind enough to decorate MyType object with 
additional fields so it looks like this (dump from Eclipse debugger)

[0] MyType_Decorated  (id=118)  
    dynamicObjectHelper AsmBackedClassGenerator$MixInExtensibleDynamicObject  (id=134)  
    fieldInsideMyObject "1.5" (id=137)     <---- the only original field from my class
    fieldInsideMyObjectSet  false   
    mapping ConventionAwareHelper  (id=145) 
    metaClass   MetaClassImpl  (id=149) 

Of course such decorated object is useless for purpose of serialization into 
json because those additional fields are not marked as transient, and the only 
elegant solution here is usage of copying constructor, but still it is a pity 
that Gson fails with StackOverflow in such case.

Original comment by przemek....@gmail.com on 29 May 2014 at 3:12

GoogleCodeExporter commented 9 years ago
I forgot to mention it occurs on Gson 2.2.4

Original comment by przemek....@gmail.com on 29 May 2014 at 3:17

GoogleCodeExporter commented 9 years ago
I'd say that producing StackOverflow is rather reasonable as long as there's no 
support for circular references.

Assuming that MyType_Decorated extends MyType directly, you can work around 
with ExclusionStrategy.shouldSkipField:
- determine if it's a generated class
- if so, return true the field is declared in the class directly (rather than 
inherited)

Original comment by Maaarti...@gmail.com on 1 Jun 2014 at 10:16