Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GSON an Java Throwable

I have an object that contains a piece of data and associated exception.

Public class MyBean{
  Private String data;
  Private Exception problem;
.
.
.
}

When I try to GSON.toJSON(object) it gives me a circular references error complaining about the "problem" field.

Is there a way to for GSON to handle such objects ?

like image 669
Ben Avatar asked Nov 16 '11 11:11

Ben


1 Answers

Gson does indeed complain about a circular reference error when attempting to serialize a data structure as described in the original question.

The following example demonstrates this point.

import com.google.gson.Gson;

public class GsonFoo
{
  public static void main(String[] args)
  {
    MyBean bean = new MyBean();
    bean.data = "some data";
    bean.problem = new RuntimeException("Ack!");

    System.out.println(new Gson().toJson(bean));
  }
}

class MyBean
{
  public String data;
  public Exception problem;
}

This example results in the following exception and message from Gson.

Exception in thread "main" java.lang.IllegalStateException: circular reference error
  Offending field: cause

  Offending object: preserveType: false, type: class java.lang.Throwable, obj: java.lang.RuntimeException: Ack!
    at com.google.gson.CircularReferenceException.createDetailedException(CircularReferenceException.java:43)
    at com.google.gson.JsonSerializationVisitor.visitObjectField(JsonSerializationVisitor.java:117)
...

Gson similarly chokes when attempting something as simple as the following.

System.out.println(new Gson().toJson(new RuntimeException("Ack!")));

Gson does not currently have a configuration available to simply resolve this problem. I recommend logging an issue at http://code.google.com/p/google-gson/issues/list.

If an object with an Exception reference must be serialized and if Gson must be used, then custom serialization processing for the Exception reference must be implemented. Following is one such example.

import java.lang.reflect.Type;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class GsonFoo
{
  public static void main(String[] args)
  {
    MyBean bean = new MyBean();
    bean.data = "some data";
    bean.problem = new RuntimeException("Ack!");

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Exception.class, new ExceptionSerializer());
    Gson gson = gsonBuilder.create();

    System.out.println(gson.toJson(bean));
  }
}

class ExceptionSerializer implements JsonSerializer<Exception>
{
  @Override
  public JsonElement serialize(Exception src, Type typeOfSrc, JsonSerializationContext context)
  {
    JsonObject jsonObject = new JsonObject();
    jsonObject.add("cause", new JsonPrimitive(String.valueOf(src.getCause())));
    jsonObject.add("message", new JsonPrimitive(src.getMessage()));
    return jsonObject;
  }
}

class MyBean
{
  public String data;
  public Exception problem;
}

output:

{"data":"some data","problem":{"cause":"null","message":"Ack!"}}

For what it's worth, Jackson does not similarly choke when attempting to serialize the same data structure. Jackson serializes a MyBean instance to JSON as follows.

{
  "data":"some data",
  "problem":
  {
    "cause":null,
    "message":"Ack!",
    "localizedMessage":"Ack!",
    "stackTrace":
    [
      {
        "className":"com.stackoverflow.q8151082.JacksonFoo",
        "fileName":"JacksonFoo.java",
        "lineNumber":11,
        "methodName":"main",
        "nativeMethod":false
      }
    ]
  }
}
like image 172
Programmer Bruce Avatar answered Sep 28 '22 11:09

Programmer Bruce