JSON.simple: Read and Write JSON in Java (and Alternatives)

JSON.simple examples to read and write JSON files in Java, its status since 2012, common pitfalls, and the same code with Jackson and Gson.

JSON.simple mapping JSON to JSONObject and JSONArray with casts, compared with Jackson and Gson mapping JSON to a typed Song record

JSON.simple is a small Java library that reads and writes JSON with two classes, JSONObject (a HashMap) and JSONArray (an ArrayList), plus JSONParser for parsing. It has no dependencies, but its last release, 1.1.1, dates from March 2012, so new projects use Jackson or Gson instead.

We still meet JSON.simple in older codebases, in small tools and in coding exercises, so it helps to know how it works and where it fails. This guide shows the json-simple code for writing and reading JSON, and the same tasks with Jackson and Gson for migration.

The following example builds a song as JSON with json-simple 1.1.1 and parses it back.

JSONObject song = new JSONObject();
song.put("title", "Yesterday");
song.put("seconds", 125);
String json = song.toJSONString();               // {"seconds":125,"title":"Yesterday"}

JSONObject parsed = (JSONObject) new JSONParser().parse(json);
String title = (String) parsed.get("title");     // "Yesterday"
long seconds = (Long) parsed.get("seconds");     // 125

Notice the casts on every get() call and that the number comes back as a Long, although we put in an int. We cover the library status first, followed by writing and reading files, the pitfalls that cause bugs in production, and the Jackson and Gson versions of the same code.

1. Is JSON.simple Still Maintained?

The json-simple project (com.googlecode.json-simple:json-simple) released version 1.1.1 in 2012, and Maven Central has no newer version. The library still compiles and runs on Java 25, because it uses only basic JDK classes, but it gets no fixes for bugs or security issues. For example, toJSONString() calls itself for each nesting level, so deeply nested data ends in a StackOverflowError.

A second library with a similar name, Clifton Labs json-simple (com.github.cliftonlabs:json-simple), is a rewrite with a different API, namely Jsoner, JsonObject and JsonArray. Code written for one does not compile with the other.

JSON.simple mapping JSON to JSONObject and JSONArray with casts, compared with Jackson and Gson mapping JSON to a typed Song record
JSON.simple returns untyped maps and lists that need casts, whereas Jackson and Gson bind JSON to typed classes
LibraryLatest versionTyped binding to classesPretty printingStreaming API
JSON.simple1.1.1 (2012)NoNoLimited (ContentHandler)
Jackson2.22.3 (2.x), 3.2.3 (3.x)Yes, including recordsYesYes
Gson2.14.0Yes, including recordsYesYes
Jakarta JSON ProcessingAPI 2.1.3, Parsson 1.1.9Through Jakarta JSON BindingYesYes

Use Jackson or Gson for new code, and keep JSON.simple only where replacing it costs more than it saves. Spring Boot already ships Jackson, so in a Spring Boot application the switch adds no dependency.

2. JSON.simple Features

The design of JSON.simple is to reuse the Java collections. A JSON object is a Map, a JSON array is a List, and the values are String, Long, Double, Boolean or null.

  • It encodes and decodes JSON following RFC 4627, the JSON specification of 2006.
  • It has no external dependencies, and the jar is about 23 KB.
  • The JSONObject and JSONArray classes extend HashMap and ArrayList as raw types, so the code needs casts and gets unchecked warnings.
  • It can write JSON to any Writer with writeJSONString().
  • It has no mapping to Java classes, no annotations and no pretty printing.

3. Maven Dependency

Version 1.1.1 of the original library declares JUnit 4.10 as a compile dependency by mistake, so we exclude it to keep JUnit off the runtime classpath.

<dependency>
    <groupId>com.googlecode.json-simple</groupId>
    <artifactId>json-simple</artifactId>
    <version>1.1.1</version>
    <exclusions>
        <exclusion>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </exclusion>
    </exclusions>
</dependency>

4. Write JSON to a File

To write JSON, we fill a JSONObject with put() and a JSONArray with add(), nest them as needed, and write the result. The writeJSONString(Writer) method writes to the stream, so the JSON text is not built as one big String first.

The following example writes a playlist with two songs to playlist.json. Each song is an object, and the playlist holds the songs in an array.

@SuppressWarnings("unchecked")
static JSONObject song(String title, String artist, int seconds) {
    JSONObject song = new JSONObject();
    song.put("title", title);
    song.put("artist", artist);
    song.put("seconds", seconds);
    return song;
}
JSONArray songs = new JSONArray();
songs.add(song("Bohemian Rhapsody", "Queen", 354));
songs.add(song("Yesterday", "The Beatles", 125));
JSONObject playlist = new JSONObject();
playlist.put("name", "Road trip");
playlist.put("songs", songs);
try (Writer out = Files.newBufferedWriter(Path.of("playlist.json"))) {
    playlist.writeJSONString(out);
}
long size = Files.size(Path.of("playlist.json"));   // 150 bytes, written on one line

The file content has no line breaks or indentation, and the keys appear in HashMap order, not in the order of the put() calls.

{"songs":[{"seconds":354,"artist":"Queen","title":"Bohemian Rhapsody"},{"seconds":125,"artist":"The Beatles","title":"Yesterday"}],"name":"Road trip"}

5. Read JSON from a File

To read JSON, we create a JSONParser and pass it a Reader. The parse() method returns Object, which is a JSONObject, JSONArray, String, Number, Boolean or null depending on the JSON, so we cast to the type we expect.

JSONObject root;
try (Reader in = Files.newBufferedReader(Path.of("playlist.json"))) {
    root = (JSONObject) new JSONParser().parse(in);
}
String name = (String) root.get("name");                 // "Road trip"
JSONArray list = (JSONArray) root.get("songs");
int count = list.size();                                 // 2
JSONObject first = (JSONObject) list.get(0);
String artist = (String) first.get("artist");            // "Queen"
long length = (Long) first.get("seconds");               // 354
Object missing = first.get("album");                     // null

A missing key returns null, the same as a key with a JSON null value, so containsKey() is the only way to tell the two apart. Invalid JSON makes parse() throw org.json.simple.parser.ParseException, which reports the position of the problem.

String error;
try {
    new JSONParser().parse("{\"title\": }");
    error = "valid";
} catch (ParseException e) {
    error = e.getClass().getSimpleName() + ": " + e;
}
String message = error;   // "ParseException: Unexpected token RIGHT BRACE(}) at position 10."

6. Pitfalls of JSON.simple

Most bugs with JSON.simple come from its loose typing. The compiler accepts any value in put() and any cast after get(), so the errors show up at runtime.

6.1. Numbers Are Long or Double

The parser returns every whole number as Long and every decimal number as Double. Casting to Integer throws ClassCastException, which is a frequent json-simple question on Stack Overflow.

JSONObject track = (JSONObject) new JSONParser().parse("{\"seconds\":125,\"rating\":4.5}");
Integer wrong = (Integer) track.get("seconds");             // ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer
int seconds = ((Number) track.get("seconds")).intValue();   // 125
double rating = ((Number) track.get("rating")).doubleValue(); // 4.5

Casting to Number and calling intValue() or doubleValue() works for both Long and Double values.

6.2. Unknown Objects Produce Invalid JSON

When a value is not a type that JSON.simple knows, toJSONString() writes its toString() output without quotes. A Java record, a LocalDate or an enum ends up as broken JSON that other parsers reject.

record Album(String name) {}
JSONObject bad = new JSONObject();
bad.put("album", new Album("Help!"));
String invalid = bad.toJSONString();                        // {"album":Album[name=Help!]}

6.3. Silent Failures and Escaped Slashes

The shortcut JSONValue.parse() returns null for invalid input instead of throwing an exception, so a corrupt file looks like an empty one. The writer also escapes every forward slash, which is valid JSON but makes URLs harder to read in logs.

Object nothing = JSONValue.parse("[1, 2");                 // null, no exception
String url = JSONValue.toJSONString("https://example.com/a"); // "https:\/\/example.com\/a"

7. Migrating from JSON.simple to Jackson or Gson

A music app stores user playlists as JSON files and reads them with JSON.simple. Every new field means more casts, and a ClassCastException from a Long broke the import once already. Binding the JSON to a typed record removes the casts and catches type errors in one place.

The following examples use the same playlist.json file and two records that describe its structure.

record Song(String title, String artist, int seconds) {}
record Playlist(String name, List<Song> songs) {}

7.1. Jackson

Jackson 2.22 maps JSON to records and classes with ObjectMapper. Jackson is also the default JSON library of Spring Boot, and Spring Boot 4 ships Jackson 3, which uses the new tools.jackson packages and JsonMapper, but the reading and writing calls stay the same.

ObjectMapper mapper = new ObjectMapper();
Playlist trip = mapper.readValue(Path.of("playlist.json").toFile(), Playlist.class);
String firstTitle = trip.songs().get(0).title();         // "Bohemian Rhapsody"
int total = trip.songs().stream().mapToInt(Song::seconds).sum();   // 479

String pretty = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(trip.songs().get(1));
List<String> prettyLines = pretty.lines().toList();      // [{,   "title" : "Yesterday",,   "artist" : "The Beatles",,   "seconds" : 125, }]

When the structure is not known in advance, mapper.readTree() returns a JsonNode tree, which is the closest Jackson equivalent to a JSONObject and still has typed getters such as asInt().

JsonNode tree = new ObjectMapper().readTree(Path.of("playlist.json").toFile());
int secondsOfFirst = tree.get("songs").get(0).get("seconds").asInt();   // 354

7.2. Gson

Gson 2.14 does the same with a smaller API and no dependencies, which suits Android apps and small tools. Records are supported since Gson 2.10.

Gson gson = new GsonBuilder().create();
Playlist fromGson;
try (Reader in = Files.newBufferedReader(Path.of("playlist.json"))) {
    fromGson = gson.fromJson(in, Playlist.class);
}
String lastArtist = fromGson.songs().get(1).artist();    // "The Beatles"
String compact = gson.toJson(new Song("Help!", "The Beatles", 139));   // {"title":"Help!","artist":"The Beatles","seconds":139}

The mapping from JSON.simple calls to Jackson and Gson is mostly one to one.

TaskJSON.simpleJacksonGson
Parse to a treenew JSONParser().parse(reader)mapper.readTree(reader)JsonParser.parseReader(reader)
Parse to a classNot supportedmapper.readValue(reader, Song.class)gson.fromJson(reader, Song.class)
Create an objectnew JSONObject()mapper.createObjectNode()new JsonObject()
Write to a Stringobj.toJSONString()mapper.writeValueAsString(obj)gson.toJson(obj)
Pretty printNot supportedwriterWithDefaultPrettyPrinter()new GsonBuilder().setPrettyPrinting()

For a deeper look at the replacement libraries, see converting JSON to a Map with Jackson and parsing JSON arrays with Gson.

8. JSON.simple FAQs

Finding JSON.simple in an old project raises two questions, whether it is safe to keep and how its output differs from other libraries.

8.1. Is JSON.simple deprecated?

JSON.simple is not formally deprecated, but it has had no release since 1.1.1 in 2012. It works on current Java versions, and for new code Jackson, Gson or Jakarta JSON Processing are the maintained choices.

8.2. Why are the keys in a different order than I added them?

JSONObject extends HashMap, which has no defined order. JSON objects are unordered by definition, so the output is valid, but if the order matters for people reading it, Jackson with a record or a LinkedHashMap keeps the declaration or insertion order.

8.3. How do I pretty print JSON with JSON.simple?

JSON.simple has no pretty printer. We parse the text with Jackson and write it with writerWithDefaultPrettyPrinter(), or use Gson with setPrettyPrinting(), as shown in pretty printing JSON with Gson.

8.4. How do I convert a JSONObject to a Java object?

JSON.simple cannot do it, so we copy the values field by field with casts. A better way is to pass obj.toJSONString() to Jackson’s readValue() or Gson’s fromJson() with the target class, or to replace the parsing step completely.

8.5. Can JSON.simple parse a JSON array at the top level?

Yes. The parse() method returns a JSONArray when the text starts with [, so we cast the result to JSONArray instead of JSONObject.

9. Conclusion

JSON.simple turns JSON into HashMap and ArrayList objects and back with very little code. The price is casts on every value, numbers that come back as Long or Double, random key order, no pretty printing and invalid output for unknown types.

The library has had no release since 2012, so it belongs in maintenance work only. Jackson and Gson read the same files into typed records, write them with pretty printing, and are maintained, which makes either of them the better choice for new code.

10. References

Happy Learning !!

Source Code on Github

Leave a Comment

  1. I have followed exactly as you have mentioned in the article . but was getting errors. following is the code snippet

    
    public class WriteJsonExample {
    
    	@SuppressWarnings("unchecked")
    	public static void main(String[] args) {
    		//first employee
    		JSONObject employeeDetails= new JSONObject();
    		employeeDetails.put("firstName", "Sonal");
    		employeeDetails.put("lastName", "Gupta");
    		employeeDetails.put("company","TCS");
    		
    		JSONObject employeeObject= new JSONObject();
    		employeeObject.put("employee", employeeObject);
    		
    		//second employee
    		JSONObject employeeDetails2 = new JSONObject();
    		employeeDetails2.put("firstName", "Harsh");
    		employeeDetails2.put("lastName", "Vardhhan");
    		employeeDetails2.put("company", "Infosys");
    		
    		JSONObject employeeObject2= new JSONObject();
    		employeeObject2.put("employee", employeeObject2);
    		
    		//Add employees to list
    		JSONArray employeeList= new JSONArray();
    		employeeList.add(employeeObject);
    		employeeList.add(employeeObject2);
    		
    		//WriteJsonFile
    		try(FileWriter file = new FileWriter("employees.json")){
    			file.write(employeeList.toJSONString());
    			file.flush();
    			
    		}catch(IOException e){
    			e.printStackTrace();
    		}
    
    	}
    
    }
    
    

    following are the error logs

    Exception in thread “main” java.lang.StackOverflowError
    at java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:748)
    at java.base/java.lang.StringBuffer.append(StringBuffer.java:424)
    at org.json.simple.JSONValue.escape(JSONValue.java:266)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:116)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:108)
    …..
    and similar long list of errors

  2. Had to make some changes for it to compile, namely:

                Object obj = jsonParser.parse(reader);
                JSONArray userList = new JSONArray();
                userList.add(obj);
    

    instead of directly casting like shown in the example here

                Object obj = jsonParser.parse(reader);
                JSONArray employeeList = (JSONArray) obj;
    
  3. Hi,

    I followed the example above but the JSON wrote to file does not have indentations. Am I doing something wrong?

    Thank you so much!

  4. Hello,
    How can I update just one entity value in json file?
    For example,
    I have a json file with all the data in it and
    I have to a change “firstname”: “lokesh”
    to some other value which is stored in a string.
    How can I just write this value into my json file using java
    Please help.
    Thanks

  5. How can you parse a FileReader object? What is a FileReader object?
    In comparison, I want to get a JSON file read in, then make it to string, then I know how to deal with it, but my parse method won’t take a FileReader.

Comments are closed.

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.