Skip to content

Instantly share code, notes, and snippets.

@faceless2
Last active October 3, 2025 12:50
Show Gist options
  • Save faceless2/9410213ae365da463eef93776343166c to your computer and use it in GitHub Desktop.
Save faceless2/9410213ae365da463eef93776343166c to your computer and use it in GitHub Desktop.
Parse JSON in Java with a single 100-line method and no dependencies.
import java.util.*;
import java.nio.CharBuffer;
import java.nio.BufferUnderflowException;
/**
* A single-method JSON parser in 100 lines of Java.
*
* Returns a String, Boolean, Integer, Long, Double, null, a List of those, or a Map<String,Object> of those.
* Intended to parse input which is expected to be valid. If you want 100% correct error handling, go elsewhere.
* Does not exacly match the JSON parsing rules for numbers.
*
* To parse a String: parseJson(CharBuffer.wrap(string));
*/
public static Object parseJson(CharBuffer in) {
int tell = in.position();
try {
char c;
while ((c=in.get()) == ' ' || c == '\n' || c == '\r' || c == '\t') {
tell++;
}
Object out;
if (c == '{') {
Map<String,Object> m = new LinkedHashMap<String,Object>();
while ((c=in.get()) == ' ' || c == '\n' || c == '\r' || c == '\t');
if (c != '}') {
in.position(in.position() - 1);
do {
String key = (String)parseJson(in);
while ((c=in.get()) == ' ' || c == '\n' || c == '\r' || c == '\t');
if (c == ':') {
m.put((String)key, parseJson(in));
tell = in.position();
} else {
throw new UnsupportedOperationException("expecting colon");
}
while ((c=in.get()) == ' ' || c == '\n' || c == '\r' || c == '\t');
if (c != ',' && c != '}') {
throw new UnsupportedOperationException("expecting comma or end-map");
}
} while (c != '}');
}
out = m;
} else if (c == '[') {
List<Object> l = new ArrayList<Object>();
while ((c=in.get()) == ' ' || c == '\n' || c == '\r' || c == '\t');
if (c != ']') {
in.position(in.position() - 1);
do {
l.add(parseJson(in));
tell = in.position();
while ((c=in.get()) == ' ' || c == '\n' || c == '\r' || c == '\t');
if (c != ',' && c != ']') {
throw new UnsupportedOperationException("expecting comma or end-list");
}
} while (c != ']');
}
out = l;
} else if (c == '"') {
StringBuilder sb = new StringBuilder();
while ((c=in.get()) != '"') {
if (c == '\\') {
c = in.get();
switch (c) {
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
case 'u': c = (char)Integer.parseInt(in.subSequence(0, 4).toString(), 16); in.position(in.position() + 4); break;
}
}
sb.append(c);
}
out = sb.toString();
} else if (c == 't' && in.get() == 'r' && in.get() == 'u' && in.get() == 'e') {
out = Boolean.TRUE;
} else if (c == 'f' && in.get() == 'a' && in.get() == 'l' && in.get() == 's' && in.get() == 'e') {
out = Boolean.FALSE;
} else if (c == 'n' && in.get() == 'u' && in.get() == 'l' && in.get() == 'l') {
out = null;
} else if (c == '-' || (c >= '0' && c <= '9')) {
StringBuilder sb = new StringBuilder();
sb.append(c);
while (in.hasRemaining()) {
if ((c=in.get()) == '.' || c == 'e' || c == 'E' || (c >= '0' && c <= '9')) {
sb.append(c);
} else {
in.position(in.position() - 1);
break;
}
}
String s = sb.toString();
try {
Long l = Long.parseLong(s);
if (l.longValue() == l.intValue()) { // This can't be done with a ternary due to unboxing confusion
out = Integer.valueOf(l.intValue());
} else {
out = l;
}
} catch (Exception e) {
try {
out = Double.parseDouble(s);
} catch (Exception e2) {
throw new UnsupportedOperationException("invalid number: " + s);
}
}
} else {
throw new UnsupportedOperationException("invalid " + (c >= ' ' && c < 0x80 ? "'" + ((char)c) + "'" : "U+" + Integer.toHexString(c)));
}
return out;
} catch (BufferUnderflowException e) {
throw (IllegalArgumentException)new IllegalArgumentException("Parse failed: unexpected EOF").initCause(e);
} catch (ClassCastException e) {
in.position(tell);
throw new IllegalArgumentException("Parse failed at " + in.position() + ": expected string");
} catch (UnsupportedOperationException e) {
in.position(tell);
throw new IllegalArgumentException("Parse failed at " + in.position() + ": " + e.getMessage());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment