How do I use JSON libraries like Jackson or Gson in modern Java?

In modern Java, using JSON libraries like Jackson or Gson is the standard way to handle data exchange, as the Java Standard Library does not include a built-in JSON parser.

With Java 25, you can take advantage of Records for clean data models and Text Blocks for readable JSON strings in your code.

1. Using Jackson (Industry Standard)

Jackson is highly recommended for modern applications, especially within the Spring and Jakarta EE ecosystems.

Maven Dependency:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.18.2</version>
</dependency>

Code Example:

import com.fasterxml.jackson.databind.ObjectMapper;

// 1. Define a Record (Modern Java way)
public record User(Long id, String name) {}

public class JacksonDemo {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        // Serialization (Object to JSON)
        User user = new User(1L, "Duke");
        String json = mapper.writeValueAsString(user);
        System.out.println("JSON: " + json);

        // Deserialization (JSON to Object)
        String inputJson = """
                {
                    "id": 2,
                    "name": "Java"
                }
                """;
        User decodedUser = mapper.readValue(inputJson, User.class);
        System.out.println("User Name: " + decodedUser.name());
    }
}

2. Using Gson (Google’s Library)

Gson is known for its simplicity and ease of use for smaller projects or quick utilities.

Maven Dependency:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.11.0</version>
</dependency>

Code Example:

import com.google.code.gson.Gson;
import com.google.code.gson.GsonBuilder;

public class GsonDemo {
    public static void main(String[] args) {
        // Use GsonBuilder for custom configurations like Pretty Printing
        Gson gson = new GsonBuilder().setPrettyPrinting().create();

        // Serialization
        User user = new User(10L, "Modern Java");
        String json = gson.toJson(user);
        System.out.println(json);

        // Deserialization
        User fromJson = gson.fromJson(json, User.class);
        System.out.println("ID from JSON: " + fromJson.id());
    }
}

Key Comparisons & Tips

  • Records Support: Both Jackson (2.12+) and Gson (2.10+) support Java Records natively. This is the preferred way to create POJOs for data mapping.
  • Immutability: Since Records are immutable, these libraries use reflection or canonical constructors to populate the data, which is much safer than traditional setter-based beans.
  • Performance: Jackson is generally faster and offers more features for complex mapping (like @JsonProperty for renaming fields).
  • Integration: If you are using Spring Boot, Jackson is already included and configured for you.

Integrating with HttpClient

When fetching data from an API using the java.net.http.HttpClient, you typically receive a String which you then pass to these libraries:

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
User user = mapper.readValue(response.body(), User.class);

For more advanced use cases, you can even write a custom BodyHandler that uses Jackson to parse the stream directly, saving memory on large JSON payloads.

How do I use InetAddress to resolve hostnames?

To resolve a hostname to an IP address (or vice versa) in Java, you use the java.net.InetAddress class. This class provides static factory methods to perform DNS lookups.

Here are the most common ways to use it:

1. Resolve a Hostname to an IP Address

Use InetAddress.getByName(String host) to get the primary IP address associated with a domain.

package org.kodejava.net;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class ResolveHost {
    public static void main(String[] args) {
        try {
            // Resolve a domain name to its IP address
            InetAddress address = InetAddress.getByName("www.google.com");

            System.out.println("Host Name: " + address.getHostName());
            System.out.println("IP Address: " + address.getHostAddress());
        } catch (UnknownHostException e) {
            System.err.println("Could not resolve host: " + e.getMessage());
        }
    }
}

2. Resolve All IP Addresses for a Host

Large websites often have multiple IP addresses for load balancing. You can retrieve all of them using getAllByName(String host).

try {
    InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
    for (InetAddress addr : addresses) {
        System.out.println(addr.getHostAddress());
    }
} catch (UnknownHostException e) {
    e.printStackTrace();
}

3. Reverse DNS Lookup (IP to Hostname)

If you have an IP address and want to find the hostname, use getByName() with the IP string and then call getHostName().

try {
    InetAddress address = InetAddress.getByName("8.8.8.8");
    // This triggers a reverse DNS lookup
    System.out.println("The hostname for 8.8.8.8 is: " + address.getHostName());
} catch (UnknownHostException e) {
    e.printStackTrace();
}

Key Methods Summary:

  • getHostAddress(): Returns the IP address string in textual presentation (e.g., “142.250.190.36”).
  • getHostName(): Returns the hostname for this IP address. If the operation is successful, it will perform a reverse lookup.
  • getCanonicalHostName(): Returns the fully qualified domain name (FQDN).

Important Note on Exceptions

Always wrap these calls in a try-catch block for UnknownHostException. This exception is thrown if the DNS server cannot find the host or if the network is unreachable.

How do I implement a simple TCP client and server?

To implement a simple TCP client and server in Java, you use the ServerSocket class for the server and the Socket class for the client.

Here is a straightforward example of both, where they exchange simple text messages.

1. The TCP Server

The server listens on a specific port and waits for a client to connect. Once connected, it opens input and output streams to communicate.

package org.kodejava.net;

import java.io.*;
import java.net.*;

public class SimpleTCPServer {
    public static void main(String[] args) {
        int port = 8080;

        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("Server is listening on port " + port);

            // Wait for a client connection
            try (Socket socket = serverSocket.accept()) {
                System.out.println("Client connected!");

                // Setup streams for communication
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);

                // Read message from a client
                String clientMessage = reader.readLine();
                System.out.println("Received from client: " + clientMessage);

                // Send a response back
                writer.println("Hello from Server!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. The TCP Client

The client connects to the server’s IP address (or localhost) and the same port number.

package org.kodejava.net;

import java.io.*;
import java.net.*;

public class SimpleTCPClient {
    public static void main(String[] args) {
        String hostname = "localhost";
        int port = 8080;

        try (Socket socket = new Socket(hostname, port)) {
            // Setup streams for communication
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            // Send a message to the server
            writer.println("Hello from Client!");

            // Read the server's response
            String response = reader.readLine();
            System.out.println("Server says: " + response);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

How to run it:

  1. Start the Server first: Run SimpleTCPServer. It will sit and wait (“block”) at the accept() method.
  2. Start the Client: Run SimpleTCPClient. It will connect, send the message, and then both programs will finish.

Key Concepts:

  • ServerSocket: Used by the server to “listen” for incoming connection requests.
  • Socket: Represents the actual connection. Both the client and the server use a Socket object to talk to each other once the connection is established.
  • Try-with-resources: Using try (...) ensures that the sockets and streams are automatically closed, even if an error occurs.
  • Blocking: The accept() and readLine() methods are “blocking,” meaning the program pauses there until a connection is made or data is received.

How do I use java.net.URI with Builder API?

Actually, the standard java.net.URI class in the JDK does not have a built-in Builder API. It only provides constructors and the URI.create(String) factory method.

To build URIs using a builder pattern in Java, you have three common options:

1. Using URI Constructors (Standard JDK)

While not a “builder,” the multi-argument constructor is the safest way to build a URI from components because it automatically handles URL encoding (escaping spaces, special characters, etc.).

import java.net.URI;

URI uri = new URI(
    "https",           // Scheme
    "example.com",     // Host
    "/api/search",     // Path
    "q=java builder",  // Query
    null               // Fragment
);

2. Using UriComponentsBuilder (Spring Framework)

If you are working in a Spring environment, this is the most robust and popular builder API.

import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;

URI uri = UriComponentsBuilder.newInstance()
    .scheme("https")
    .host("example.com")
    .path("/api/users/{id}")
    .queryParam("format", "json")
    .buildAndExpand(123) // Replaces {id} with 123
    .toUri();

3. Using HttpUrl (OkHttp Library)

If you use the OkHttp library, it provides a very clean HttpUrl builder.

import okhttp3.HttpUrl;
import java.net.URI;

URI uri = new HttpUrl.Builder()
    .scheme("https")
    .host("example.com")
    .addPathSegment("search")
    .addQueryParameter("q", "java")
    .build()
    .uri(); // Converts to java.net.URI

4. Why not HttpRequest.newBuilder()?

In your context attachments, you see HttpRequest.newBuilder(). Note that this builds an HTTP Request, not the URI itself. You still need to pass a URI object to the .uri() method:

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://example.com")) // Still requires a URI object
    .GET()
    .build();

Summary: If you want a builder API for java.net.URI without adding external dependencies, your best bet is to create a small helper class or use the multi-argument new URI(...) constructor to ensure proper encoding.

How do I fetch JSON using java.net.http.HttpRequest?

To fetch JSON using the Java HTTP Client (java.net.http), you typically send a GET request and process the response body as a String. Since the standard library doesn’t include a JSON parser, you’ll receive the raw JSON string, which you can then parse using a library like Jackson or Gson.

Here is a clean example of how to perform the fetch:

1. Basic JSON Fetch (Java 11+)

This example demonstrates the core steps: creating the client, building the request, and receiving the response.

package org.kodejava.httpclient;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.io.IOException;

public class FetchJsonExample {
    public static void main(String[] args) {
        // 1. Create an HttpClient (try-with-resources available in Java 21+)
        try (HttpClient client = HttpClient.newHttpClient()) {

            // 2. Build the HttpRequest
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
                    .header("Accept", "application/json") // Good practice to request JSON
                    .GET()
                    .build();

            try {
                // 3. Send the request and handle the body as a String
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

                // 4. Check the status code and print the JSON body
                if (response.statusCode() == 200) {
                    System.out.println("JSON Received:");
                    System.out.println(response.body());
                } else {
                    System.err.println("Error: " + response.statusCode());
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2. Fetching Asynchronously

If you don’t want to block the main thread while waiting for the network, use sendAsync. This returns a CompletableFuture:

client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
      .thenApply(HttpResponse::body)
      .thenAccept(System.out::println)
      .join(); // Wait for completion (for demo purposes)

Key Tips for JSON fetching:

  • Headers: Always include .header("Accept", "application/json") so the server knows you expect a JSON response.
  • Parsing: To turn that String into a Java Object, you would typically use a library. For example, with Jackson:
    ObjectMapper mapper = new ObjectMapper();
        MyObject obj = mapper.readValue(response.body(), MyObject.class);
    
  • Timeouts: It’s a “friendly” habit to set a timeout so your application doesn’t hang indefinitely:
    HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .timeout(java.time.Duration.ofSeconds(10))
                .build();