简体   繁体   中英

GSON causing StackOverFlow Error when running toJSON

Before I begin with the question, I know there are lots of similar questions to this but I have no control of the objects I turn into JSON therefore I can't simply exclude fields that reference the same object.

I found that explaining the structure of my applications help people understand my question more, so here I go!

I have 2 applications, a Logic application (where all the heavy operations take place) and a Instrumented application (an application which is injected into an old game and has to be kept light).

The 2 applications communicate via RMI (Remote Method Invocation).

The Instrumented Application sends Objects that are fetched from the old game using the Reflection API to the Logic Application (via RMI as that's how the 2 communicate).

Most of the objects are Un-serializable (Do not implement Serializable, and can't be serialized except by using BCL libraries which I don't want to do as it's bad practice to force-serialize objects as they may cause problems(security) serialized).

As mentioned in the above paragraph, due to them being un-serializable I can't just turn them into byte arrays and send so I've went through and used GSON which doesn't require the objects to implement Serializable.

When I first tried out serializing the objects, it worked except a couple of objects printed out Stack overflow errors when trying to serialize them (toJSON).

Why I think the error occurred: The object has a superclass.. The object contains references of itself (Fields)

I can't show the object itself as it's in a game and its obfuscated, but I can show my wrapper to it which shows the fields and their types.

The Object Itself (The one causing Stack Overflow errors when toJSON is executed upon it):

public class NPC extends Model {

    //The Class itself contains 1 field which is "Composite"

    public NPC(Object object) {
        super(object);
    }

    public NPCComposite getComposite() {
        return new NPCComposite(getFieldValue("Npc.composite", object));
    }
}

The Object above contains only 1 Field and it's "Composite", here's the wrapper for NPCComposite:

public class NPCComposite extends Wrapper {

    //Contains 3 Fields: String[], String, int (Nothing out of the ordinary)
    
    public NPCComposite(Object object) {
        super(object);
    }

    public String[] getActions() {
        return (String[]) getFieldValue("NpcComposite.actions", object);
    }

    public int getID() {
        return (int) getFieldValue("NpcComposite.id", object);
    }

    public String getName() {
        return (String) getFieldValue("NpcComposite.name", object);
    }
}

If you have noticed, the Object itself (NPC) has a superclass, this is the superclass's wrapper: I have added a comment next to field getters that have unapparent return types.

public class Model extends Render {

    public Model(Object object) {
        super(object);
    }

    public int getFineX() {
        return (int) getFieldValue("Model.localX", object);
    }

    public int getFineY() {
        return (int) getFieldValue("localY", object);
    }

    public int getAnimation() {
        return (int) getFieldValue("animation", object);
    }

    public int getAnimationDelay() {
        return (int) getFieldValue("animationDelay", object);
    }

    public int getCombatTime() {
        return (int) getFieldValue("combatTime", object);
    }

    public int getStandAnimation() {
        return (int) getFieldValue("standAnimation", object);
    }

    public int getFrameOne() {
        return (int) getFieldValue("frameOne", object);
    }

    public int getFrameTwo() {
        return (int) getFieldValue("Model.frameTwo", object);
    }

    public Object getHealthBars() { //Returns a Health Bar Object
        return getFieldValue("Model.healthBars", object);
    }

    public Object getHitCycles() { //Returns an Integer 1D Array
        return getFieldValue("Model.hitCycles", object);
    }

    public Object getHitDamages() { //Returns an Integer 1D Array
        return getFieldValue("Model.hitDamages", object);
    }

    public Object getHitTypes() { //Returns an Integer 1D Array
        return getFieldValue("Model.hitTypes", object);
    }

    public int getInteracting() {
        return (int) getFieldValue("Model.interacting", object);
    }

    public Object getMessage() { //Returns a String
        return getFieldValue("Model.message", object);
    }

    public int getOrientation() {
        return (int) getFieldValue("Model.orientation", object);
    }

    public int getQueueSize() {
        return (int) getFieldValue("Model.queueSize", object);
    }

    public Object getQueueTraversed() { //Returns a byte 1D array
        return getFieldValue("Model.queueTraversed", object);
    }

    public Object getQueueX() { //Returns a 1D int array
        return getFieldValue("Model.queueX", object);
    }

    public Object getQueueY() { //Returns a 1D int array
        return getFieldValue("Model.queueY", object);
    }

    public int getRuntimeAnimation() {
        return (int) getFieldValue("Model.runtimeAnimation", object);
    }

}

Main method:

    Gson g = new Gson();
    String res = g.toJson(NPCObject);

Error:

java.rmi.ServerError: Error occurred in server thread; nested exception is: 
    java.lang.StackOverflowError
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:303)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:279)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:163)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:235)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:180)
    at com.sun.proxy.$Proxy0.getGSONValue(Unknown Source)
    at main.Instance.test(Instance.java:29)
Caused by: java.lang.StackOverflowError
    at java.lang.AbstractStringBuilder.append(Unknown Source)
    at java.lang.StringBuffer.append(Unknown Source)
    at java.io.StringWriter.write(Unknown Source)
    at com.google.gson.stream.JsonWriter.string(JsonWriter.java:590)
    at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:401)
    at com.google.gson.stream.JsonWriter.value(JsonWriter.java:526)
    at com.google.gson.internal.bind.TypeAdapters$11.write(TypeAdapters.java:311)
    at com.google.gson.internal.bind.TypeAdapters$11.write(TypeAdapters.java:296)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245)
    at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:1027)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245)

My question is: Is there anyway to solve this error? or is there any other JSON library that can serialize such objects? any answer is appreciated!

Thank you!

I have successfully solved this by using XStream and adding the class path of the objects to it.

I don't think there's a way around it except using BCEL libraries and changing circular fields to transient or making the class Serializable and its contents..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM