1. Introduction
In this quick tutorial, we're going to create methods able to read JSON data from any URL. We'll start with core Java classes. Then, we'll use a few libraries to make our code simpler.
2. Using Core Java Classes
One of the simplest ways to read data from a URL in Java is using the URL class. To use it, we open an input stream to a URL, create an input stream reader, then read all characters. We'll append these characters to a StringBuilder and then return it as a String:
public static String stream(URL url) {
try (InputStream input = url.openStream()) {
InputStreamReader isr = new InputStreamReader(input);
BufferedReader reader = new BufferedReader(isr);
StringBuilder json = new StringBuilder();
int c;
while ((c = reader.read()) != -1) {
json.append((char) c);
}
return json.toString();
}
}
Consequently, the code includes a lot of boilerplate. Moreover, it would also require even more code if we wanted to convert our JSON into a map or a POJO. Even using the new Java 11 HttpClient, it's a lot of code for a simple GET request. Also, it doesn't help with converting the response from strings to POJO. So, let's explore simpler ways to do this.
3. Using commons-io and org.json
A very popular library is Apache Commons IO. We'll use IOUtils to read a URL and get a String back. Then, to convert it to a JSONObject, we'll use the JSON-Java (org.json) library. This is a reference implementation for Java from json.org. Let's combine them in a new method:
public static JSONObject getJson(URL url) {
String json = IOUtils.toString(url, Charset.forName("UTF-8"));
return new JSONObject(json);
}
With JSONObject, we can call get() for any properties and get an Object. There are similarly named methods for specific types. For example:
jsonObject.getString("stringProperty");
4. Less Code With Jackson and the ObjectMapper
There are many solutions for converting JSON into POJO and vice-versa. But, Jackson is widely used in projects like Jersey and other JAX-RS implementations. Let's add the dependency we need to our pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
With this, not only can we effortlessly read JSON from a URL, but we can also convert it to a POJO at the same time.
4.1. Deserializing to a Generic Object
Most of the action in Jackson comes from the ObjectMapper. The most common scenario for ObjectMapper is to give it a String input and get an object back. Luckily, ObjectMapper can also read input straight from an internet URL:
public static JsonNode get(URL url) {
ObjectMapper mapper = new ObjectMapper();
return mapper.readTree(url);
}
With readTree(), we get a JsonNode, which is a tree-like structure. We read properties with its get() method:
json.get("propertyName");
Therefore, we don't need to map our response to a specific class if we don't want to.
4.2. Deserializing to a Custom Class
But, for more complex objects, it's helpful to create a class that represents the JSON structure we expect. We can use generics to create a version of our method capable of mapping the response to any class we want with readValue():
public static <T> T get(URL url, Class<T> type) {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(url, type);
}
Then, as long as our object's properties and structure match, we'll get a new instance filled with values from the JSON response.
5. Conclusion
In this article, we learned how to make requests to a URL and get a JSON string back. Then, we used a few libraries to simplify our code. In the end, we read a JSON response while mapping it to a POJO in a couple of lines.
And as always, the source code is available over on GitHub.
Course – LS (cat=JSON/Jackson) res – REST with Spring (eBook) (everywhere)