Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StackOverflow when serializing object of complicated generic type #98

Open
kerler opened this issue Jul 6, 2016 · 6 comments
Open

StackOverflow when serializing object of complicated generic type #98

kerler opened this issue Jul 6, 2016 · 6 comments

Comments

@kerler
Copy link

kerler commented Jul 6, 2016

Dear Sir,

There is StackOverflow when genson serialize object of complicated generic type. The complete project for test cases is at https://github.com/kerler/testgenson.

In testgenson project, the test case source code is in https://github.com/kerler/testgenson/tree/master/src/test/java/org/testgenson/GensonGenericTest.java.

StackOverflow occurs when genson serialize object of class org.openehr.rm.datatypes.quantity.datetime.DvDateTime. DvDateTime is in jar /testlibs/openehr-rm-core-1.0.5-SNAPSHOT.jar in testgenson project, and its source code is in sub project openehr-rm-core of https://github.com/openEHR/java-libs, i.g. https://github.com/openEHR/java-libs/blob/master/openehr-rm-core/src/main/java/org/openehr/rm/datatypes/quantity/datetime/DvDateTime.java

By setting a breakpoint in IDE, StackOverflow can be seen at line 29 throw couldNotSerialize(th) in com.owlike.genson.reflect.PropertyAccessor.java::serialize(...), where 'th' is:

Method threw 'java.lang.StackOverflowError' exception. Cannot evaluate java.lang.StackOverflowError.toString().

Thanks,
Baogang

@EugenCepoi
Copy link
Contributor

Hi Baogang,

Thanks for reporting this and taking the time to build a test project.
I tried to run it but instead of stackoverflow error I get this

com.owlike.genson.JsonBindingException: Failed to serialize object of type class org.openehr.rm.datatypes.quantity.datetime.DvDateTime
    at com.owlike.genson.Genson.serialize(Genson.java:277)
    at com.owlike.genson.Genson.serialize(Genson.java:170)
    at org.testgenson.GensonGenericTest.should_find_addresses(GensonGenericTest.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:377)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: com.owlike.genson.JsonBindingException: Could not serialize property 'diffType' from class org.openehr.rm.datatypes.quantity.datetime.DvTemporal
    at com.owlike.genson.reflect.PropertyAccessor.couldNotSerialize(PropertyAccessor.java:46)
    at com.owlike.genson.reflect.PropertyAccessor.serialize(PropertyAccessor.java:29)
    at com.owlike.genson.reflect.BeanDescriptor.serialize(BeanDescriptor.java:92)
    at com.owlike.genson.convert.ClassMetadataConverter.serialize(ClassMetadataConverter.java:83)
    at com.owlike.genson.convert.RuntimeTypeConverter.serialize(RuntimeTypeConverter.java:43)
    at com.owlike.genson.convert.NullConverterFactory$NullConverterWrapper.serialize(NullConverterFactory.java:69)
    at com.owlike.genson.Genson.serialize(Genson.java:274)
    ... 45 more
Caused by: com.owlike.genson.JsonBindingException: Could not serialize property 'classLoader' from class java.lang.Class
    at com.owlike.genson.reflect.PropertyAccessor.couldNotSerialize(PropertyAccessor.java:46)
    at com.owlike.genson.reflect.PropertyAccessor.serialize(PropertyAccessor.java:29)
    at com.owlike.genson.reflect.BeanDescriptor.serialize(BeanDescriptor.java:92)
    at com.owlike.genson.convert.ClassMetadataConverter.serialize(ClassMetadataConverter.java:83)
    at com.owlike.genson.convert.RuntimeTypeConverter.serialize(RuntimeTypeConverter.java:43)
    at com.owlike.genson.convert.NullConverterFactory$NullConverterWrapper.serialize(NullConverterFactory.java:69)
    at com.owlike.genson.reflect.PropertyAccessor.serialize(PropertyAccessor.java:27)
    ... 50 more
Caused by: com.owlike.genson.JsonBindingException: Failed to serialize object of type class sun.misc.Launcher$AppClassLoader
    at com.owlike.genson.Genson.serialize(Genson.java:277)
    at com.owlike.genson.convert.RuntimeTypeConverter.serialize(RuntimeTypeConverter.java:41)
    at com.owlike.genson.convert.NullConverterFactory$NullConverterWrapper.serialize(NullConverterFactory.java:69)
    at com.owlike.genson.reflect.PropertyAccessor.serialize(PropertyAccessor.java:27)
    ... 55 more
Caused by: com.owlike.genson.JsonBindingException: Could not serialize property 'assertionLock' from class java.lang.ClassLoader
    at com.owlike.genson.reflect.PropertyAccessor.couldNotSerialize(PropertyAccessor.java:46)
    at com.owlike.genson.reflect.PropertyAccessor.serialize(PropertyAccessor.java:29)
    at com.owlike.genson.reflect.BeanDescriptor.serialize(BeanDescriptor.java:92)
    at com.owlike.genson.convert.ClassMetadataConverter.serialize(ClassMetadataConverter.java:83)
    at com.owlike.genson.convert.RuntimeTypeConverter.serialize(RuntimeTypeConverter.java:43)
    at com.owlike.genson.convert.NullConverterFactory$NullConverterWrapper.serialize(NullConverterFactory.java:69)
    at com.owlike.genson.Genson.serialize(Genson.java:274)
    ... 58 more
Caused by: java.lang.UnsupportedOperationException: Serialization of type Object is not supported by default serializers.
    at com.owlike.genson.convert.DefaultConverters$UntypedConverterFactory$UntypedConverter.serialize(DefaultConverters.java:1002)
    at com.owlike.genson.convert.ClassMetadataConverter.serialize(ClassMetadataConverter.java:83)
    at com.owlike.genson.convert.RuntimeTypeConverter.serialize(RuntimeTypeConverter.java:43)
    at com.owlike.genson.convert.NullConverterFactory$NullConverterWrapper.serialize(NullConverterFactory.java:69)
    at com.owlike.genson.reflect.PropertyAccessor.serialize(PropertyAccessor.java:27)
    ... 63 more

However if we exclude methods using GensonBuilder (your commented code) the serialization doesn't fail with an error. The resulting JSON I get looks like this

{
  "@class":"org.openehr.rm.datatypes.quantity.datetime.DvDateTime",
  "accuracy":null,
  "dateTime":{
    "@class":"org.joda.time.DateTime",
    "iChronology":{
      "@class":"org.joda.time.chrono.ISOChronology",
      "iBase":{
        "@class":"org.joda.time.chrono.ZonedChronology",
        "iBase":{
          "@class":"org.joda.time.chrono.ISOChronology",
          "iBase":{
            "@class":"org.joda.time.chrono.GregorianChronology",
            "iBase":null,
            "iMinDaysInFirstWeek":4,
            "iParam":null
          },
          "iParam":null
        },
        "iParam":{
          "@class":"org.joda.time.tz.FixedDateTimeZone",
          "iID":"+08:00",
          "iNameKey":null,
          "iStandardOffset":28800000,
          "iWallOffset":28800000
        }
      },
      "iParam":null
    },
    "iMillis":1467809263316
  },
  "fractionalSecKnown":true,
  "isPartial":false,
  "magnitudeStatus":null,
  "minuteKnown":true,
  "normalRange":null,
  "normalStatus":null,
  "otherReferenceRanges":null,
  "secondKnown":true,
  "value":"2016-07-06T20:47:43.316+08:00"
}

when we try to deserialize this json back, then it fails with the following error Caused by: com.owlike.genson.JsonBindingException: No constructor has been found for type class org.joda.time.chrono.ISOChronology. Even though you have enabled the use of constructors with arguments, the problem is that the only one from ISOChronology has a parameter named "base" while in the json what we have is "iBase", so the matching fails and no constructor is found.

Do you have the same results as me or are you encountering another error? I didn't get any stackoverflow.

@kerler
Copy link
Author

kerler commented Jul 11, 2016

Hi Eugen,

I did not meet the exception as you. And, if I use gradle build in command line instead of setting breakpoint in IDEA, I got the result as the attached file gradle-build-result-of-testgenson.txt.

gradle-build-result-of-testgenson.txt

The version of JDK and gradle on my computer is as below. And, file build.gradle in testgenson project take use of testCompile("com.owlike:genson:1.4").

` .

C:\Program Files (x86)\PowerCmd>java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

C:\Program Files (x86)\PowerCmd>gradle -v

Gradle 2.2.1

Build time:   2014-11-24 09:45:35 UTC
Build number: none
Revision:     6fcb59c06f43a4e6b1bcb401f7686a8601a1fb4a

Groovy:       2.3.6
Ant:          Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM:          1.8.0_45 (Oracle Corporation 25.45-b02)
OS:           Windows 7 6.1 amd64

C:\Program Files (x86)\PowerCmd

`

If I uncomment line //.useMethods(false), I got the same result as you.

For the issue ISOChronology has no default constructor, do you think we can use objenesis http://objenesis.org/ to instantiate a new object of a particular class? http://stackoverflow.com/questions/4133709/is-it-possible-in-java-to-create-blank-instance-of-class-without-no-arg-constr has some discussion.

@EugenCepoi
Copy link
Contributor

Yes we can definitely use this or just directly sun.misc.unsafe to generate a no arg constructor. But this would require a bit of work. I am not sure that in your case you want to serialize this object "deeply" like this. Perhaps you should just use a custom converter for that type?

On Jul 11, 2016, at 1:19 AM, kerler [email protected] wrote:

Hi Eugen,

I did not meet the exception as you. And, if I use gradle build in command line instead of setting breakpoint in IDEA, I got the result as the attached file gradle-build-result-of-testgenson.txt.

gradle-build-result-of-testgenson.txt

The version of JDK and gradle on my computer is:

`
C:\Program Files (x86)\PowerCmd>java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

C:\Program Files (x86)\PowerCmd>gradle -v

Gradle 2.2.1

Build time: 2014-11-24 09:45:35 UTC
Build number: none
Revision: 6fcb59c06f43a4e6b1bcb401f7686a8601a1fb4a

Groovy: 2.3.6
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_45 (Oracle Corporation 25.45-b02)
OS: Windows 7 6.1 amd64

C:\Program Files (x86)\PowerCmd>
`

If I uncomment line //.useMethods(false), I got the same result as you.

For the issue ISOChronology has no default constructor, do you think we can use objenesis http://objenesis.org/ to instantiate a new object of a particular class? http://stackoverflow.com/questions/4133709/is-it-possible-in-java-to-create-blank-instance-of-class-without-no-arg-constr has some discussion.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

@kerler
Copy link
Author

kerler commented Jul 12, 2016

Yeah, in most cases a custom converter is good especially for implementing JSON REST API. I just want to test the extreme capability of genson in case that maybe in the future I want to persist some kinds of data into NoSQL db with JSON format .

@EugenCepoi
Copy link
Contributor

As it is now there are two major things that you won't be able to do with genson: serialize objects with cyclic references in them (this is probably what happened in the original scenario with the stackoverflow error) and deserialize classes that don't have a no arg constructor or no constructor that matches with the property names. Both are new features that I would like to add to Genson or even better see them being contributed as a pull request.

@EugenCepoi
Copy link
Contributor

I am closing this issue in favor of #59 and #100.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants