16

Is it possible, in Java 7, to convert an Exception object into Json?

example:

try {      
    //something
} catch(Exception ex) {     
    Gson gson = new Gson();
    System.out.println(gson.toJson(ex));
}
zmo
  • 24,463
  • 4
  • 54
  • 90
user2803095
  • 347
  • 1
  • 4
  • 16
  • I'm thinking this question is too broad, because you ask something that you can obviously and objectively do, but you do not ask about your *real* problem, so any answer is actually acceptable to your first question… whereas your second answer is obviously "yes". – zmo Mar 08 '14 at 15:25
  • I was ask about conversation, Exception object into Json, i did not ask for alternative way how get some property of Exception object and put the values into Json. I accepted the answer as a way, but i didn't say that is the right solution for my question. – user2803095 Mar 08 '14 at 16:35
  • At the end I asked is it possible? – user2803095 Mar 08 '14 at 16:37

3 Answers3

8

well, it is possible to do something like that, though you don't want to convert the exception object itself, but rather the message it has within, with a format you design, something like:

// […]
} catch (Exception ex) {
    Gson gson = new Gson();
    Map<String, String> exc_map = new HashMap<String, String>();
    exc_map.put("message", ex.toString());
    exc_map.put("stacktrace", getStackTrace(ex));
    System.out.println(gson.toJson(exc_map));
}

with getStackTrace() defined as suggests that answer:

public static String getStackTrace(final Throwable throwable) {
     final StringWriter sw = new StringWriter();
     final PrintWriter pw = new PrintWriter(sw, true);
     throwable.printStackTrace(pw);
     return sw.getBuffer().toString();
}
BVB
  • 5,380
  • 8
  • 41
  • 62
zmo
  • 24,463
  • 4
  • 54
  • 90
  • 2
    (to accept an answer, do not comment saying "accepted" just hit the checkmark next to the vote score) ;-) – zmo Mar 08 '14 at 15:27
7

In theory, you could also iterate over the elements in a stack trace and generate something that looks like:

{ "NullPointerException" :
    { "Exception in thread \"main\" java.lang.NullPointerException",
        { 
          "Book.java:16" : "com.example.myproject.Book.getTitle",
          "Author.java:25" : "at com.example.myproject.Author.getBookTitles",
          "Bootstrap.java:14" : "at com.example.myproject.Bootstrap.main()"
        }
    },
  "Caused By" :
    { "Exception in thread \"main\" java.lang.NullPointerException",
        { 
          "Book.java:16" : "com.example.myproject.Book.getTitle",
          "Author.java:25" : "at com.example.myproject.Author.getBookTitles",
          "Bootstrap.java:14" : "at com.example.myproject.Bootstrap.main()"
        }
    }
}

You can iterate the exception like this:

catch (Exception cause) {
    StackTraceElement elements[] = cause.getStackTrace();
    for (int i = 0, n = elements.length; i < n; i++) {       
        System.err.println(elements[i].getFileName()
            + ":" + elements[i].getLineNumber() 
            + ">> "
            + elements[i].getMethodName() + "()");
    }
}
djangofan
  • 28,471
  • 61
  • 196
  • 289
  • But I don't need to go through for loop. `Gson gson = new Gson(); StackTraceElement elements[] = ex.getStackTrace(); System.out.println(gson.toJson(elements));` – user2803095 Mar 08 '14 at 18:26
  • 1
    Yes, and if the stack trace is a chain, then you can put multiple gson traces into one single JSon object. There are way too many ways to do this. – djangofan Mar 08 '14 at 18:27
  • 1
    It would be far better to use a JSON array than members of the object. If you have a second "caused by" you would have no place to put it. The chain of causes can be any length, and the name of the exception class can be repeated. You should simply have an array. – AgilePro May 02 '19 at 18:55
4

Below is the routine to convert an Exception to JSON in a standardized way:

public static JSONObject convertToJSON(Throwable e, String context) throws Exception {
    JSONObject responseBody = new JSONObject();
    JSONObject errorTag = new JSONObject();
    responseBody.put("error", errorTag);

    errorTag.put("code", 400);
    errorTag.put("context", context);

    JSONArray detailList = new JSONArray();
    errorTag.put("details", detailList);

    Throwable nextRunner = e;
    List<ExceptionTracer> traceHolder = new ArrayList<ExceptionTracer>();
    while (nextRunner!=null) {
        Throwable runner = nextRunner;
        nextRunner = runner.getCause();

        detailObj.put("code", runner.getClass().getName());
        String msg =  runner.toString();
        detailObj.put("message",msg);

        detailList.put(detailObj);
    }

    JSONArray stackList = new JSONArray();
    for (StackTraceElement ste : e.getStackTrace()) {
        stackList.put(ste.getFileName() + ": " + ste.getMethodName()
               + ": " + ste.getLineNumber());
    }
    errorTag.put("stack", stackList);

    return responseBody;
}

You can find the complete open source library that implements this at: Purple JSON Utilities. This library supports the JSON Objects as well as the exceptions.

This produces a JSON structure of this form:

{
   "error": {
      "code": "400",
      "message": "main error message here",
      "target": "approx what the error came from",
      "details": [
         {
            "code": "23-098a",
            "message": "Disk drive has frozen up again.  It needs to be replaced",
            "target": "not sure what the target is"
         }
      ],
      "innererror": {
         "trace": [ ... ],
         "context": [ ... ]
      }
   }
}

This is the format proposed by the OASIS data standard OASIS OData and seems to be the most standard option out there, however there does not seem to be high adoption rates of any standard at this point.

The details are discussed in my blog post on Error Handling in JSON REST API

AgilePro
  • 5,588
  • 4
  • 33
  • 56