Search code examples
javajsonpretty-print

How to pretty print invalid/incomplete JSON in Java


Assuming an incomplete JSON string (cut off in the middle for e.g.) how can I best pretty print the characters I have? All pretty printing I've come across for JSON involves libraries, but they assume a valid and complete JSON structure.

I'm fine with using a "brute-force" method as described here for XML: How to pretty print XML from Java?

Any ideas for similar handling for JSON?

(I don't want to parse the entire JSON structure since it can be massive, I only want a small part of it printed for logging purposes which I want to be minimal and fast-- and then I want it pretty printed).


Solution

  • This is how I ended up solving this. Not a great solution, but not sure how it could've been done better (given the problematic input restrictions). It's working well however, and attempts to pretty-print json the best it can. It's building on the solution seen here for PHP: https://gist.github.com/GloryFish/1045396

    public String prettyPrintJSONAsString(String jsonString) {
    
        int tabCount = 0;
        StringBuffer prettyPrintJson = new StringBuffer();
        String lineSeparator = "\r\n";
        String tab = "  ";
        boolean ignoreNext = false;
        boolean inQuote = false;
    
        char character;
    
        /* Loop through each character to style the output */
        for (int i = 0; i < jsonString.length(); i++) {
    
            character = jsonString.charAt(i);
    
            if (inQuote) {
    
                if (ignoreNext) {
                    ignoreNext = false;
                } else if (character == '"') {
                    inQuote = !inQuote;
                }
                prettyPrintJson.append(character);
            } else {
    
                if (ignoreNext ? ignoreNext = !ignoreNext : ignoreNext);
    
                switch (character) {
    
                case '[':
                    ++tabCount;
                    prettyPrintJson.append(character);
                    prettyPrintJson.append(lineSeparator);
                    printIndent(tabCount, prettyPrintJson, tab);
                    break;
    
                case ']':
                    --tabCount;
                    prettyPrintJson.append(lineSeparator);
                    printIndent(tabCount, prettyPrintJson, tab);
                    prettyPrintJson.append(character);
                    break;
    
                case '{':
                    ++tabCount;
                    prettyPrintJson.append(character);
                    prettyPrintJson.append(lineSeparator);
                    printIndent(tabCount, prettyPrintJson, tab);
                    break;
    
                case '}':
                    --tabCount;
                    prettyPrintJson.append(lineSeparator);
                    printIndent(tabCount, prettyPrintJson, tab);
                    prettyPrintJson.append(character);
                    break;
    
                case '"':
                    inQuote = !inQuote;
                    prettyPrintJson.append(character);
                    break;
    
                case ',':
                    prettyPrintJson.append(character);
                    prettyPrintJson.append(lineSeparator);
                    printIndent(tabCount, prettyPrintJson, tab);
                    break;
    
                case ':':
                    prettyPrintJson.append(character + " ");
                    break;
    
                case '\\':
                    prettyPrintJson.append(character);
                    ignoreNext = true;
                    break;
    
                default:
                    prettyPrintJson.append(character);
                    break;
                }
            }
        }
    
        return prettyPrintJson.toString();
    }
    
    private void printIndent(int count, StringBuffer stringBuffer, String indent) {
        for (int i = 0; i < count; i++) {
            stringBuffer.append(indent);
        }
    }