Skip to content

JSON Repair — Java source

Fix broken JSON - trailing commas, single quotes, unquoted keys, comments, Python constants, BOM and truncated documents - and get clean pretty-printed JSON plus a list of every repair applied. Runs entirely in your browser.

This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.

// JSON repair pipeline — Java (17+) port of the json-repair tool: excerpt of
// the 7-pass pipeline in typescript.ts / go.go (quote, Python-constant,
// trailing comma, truncation repair passes).
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class JsonRepair {
    static final Pattern STRINGS = Pattern.compile("\"(?:[^\"\\\\]|\\\\.)*\"");
    static final Pattern PY = Pattern.compile("\\b(True|False|None)\\b");
    static final Map<String, String> PY_MAP = Map.of("True", "true", "False", "false", "None", "null");
    static final Pattern TRAILING = Pattern.compile(",(\\s*[}\\]])");
    // Single-quoted strings -> double-quoted: escape inner double quotes,
    // collapse \' to ', keep every other escape; double-quoted copy verbatim.
    static String singleToDoubleQuotes(String text) {
        StringBuilder out = new StringBuilder();
        int i = 0;
        while (i < text.length()) {
            char c = text.charAt(i);
            if (c != '\'') { out.append(c); i++; continue; }
            out.append('"');
            i++;
            while (i < text.length() && text.charAt(i) != '\'') {
                char d = text.charAt(i);
                if (d == '\\' && i + 1 < text.length()) {
                    out.append(text.charAt(i + 1) == '\'' ? '\'' : "" + d + text.charAt(i + 1));
                    i += 2;
                } else if (d == '"') { out.append("\\\""); i++; }
                else { out.append(d); i++; }
            }
            out.append('"');
            i++;
        }
        return out.toString();
    }
    static String outsideStrings(String text, Function<String, String> map) { // outside "..." only
        Matcher m = STRINGS.matcher(text);
        StringBuilder out = new StringBuilder();
        int last = 0;
        while (m.find()) {
            out.append(map.apply(text.substring(last, m.start()))).append(m.group());
            last = m.end();
        }
        return out.append(map.apply(text.substring(last))).toString();
    }
    static String fixPythonConstants(String t) { return outsideStrings(t, s -> PY.matcher(s).replaceAll(m -> PY_MAP.get(m.group()))); }
    // Commas followed only by whitespace and a closing } or ] — dropped.
    static String stripTrailingCommas(String t) { return outsideStrings(t, s -> TRAILING.matcher(s).replaceAll(m -> m.group(1))); }
    // Recover truncated JSON: close an unterminated string, drop a dangling
    // comma, give a dangling colon a null value, then close open brackets.
    static String closeTruncated(String text) {
        ArrayDeque<Character> stack = new ArrayDeque<>();
        boolean inString = false;
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            if (inString) {
                if (c == '\\') i++; // skip the escaped character
                else if (c == '"') inString = false;
            } else if (c == '"') inString = true;
            else if (c == '{' || c == '[') stack.addLast(c);
            else if (c == '}' || c == ']') { if (!stack.isEmpty()) stack.removeLast(); }
        }
        String out = (inString ? text + "\"" : text).replaceAll("[\\s,]+$", "");
        if (out.endsWith(":")) out += " null";
        StringBuilder closers = new StringBuilder();
        while (!stack.isEmpty()) closers.append(stack.removeLast() == '{' ? '}' : ']');
        return out + closers;
    }
    // The canonical repair() also reports which passes fired and pretty-prints.
    static String repair(String text) {
        return List.<Function<String, String>>of(JsonRepair::singleToDoubleQuotes,
                JsonRepair::fixPythonConstants, JsonRepair::stripTrailingCommas,
                JsonRepair::closeTruncated)
            .stream().reduce(text, (work, pass) -> pass.apply(work), (a, b) -> a);
    }
    public static void main(String[] args) {
        // {"name": "Ada", admin: true, tags: ["x", "y"]}
        System.out.println(repair("{'name': 'Ada', admin: True, tags: ['x', 'y',],"));
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →