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();
    

How do I use WebSocket with HttpClient?

To use WebSockets with the Java native HttpClient (introduced in Java 11 and fully supported in Java 25), you use the WebSocket.Builder.

The process involves three main steps:
1. Create an HttpClient (or use an existing one).
2. Implement a WebSocket.Listener to handle incoming messages and events.
3. Build and open the connection using HttpClient.newWebSocketBuilder().

Here is a complete example of a simple WebSocket client:

package org.kodejava.httpclient;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.nio.ByteBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

public class WebSocketExample {

    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        // 1. Build the WebSocket connection
        CompletableFuture<WebSocket> wsFuture = client.newWebSocketBuilder()
                .buildAsync(URI.create("wss://echo.websocket.org"), new EchoListener());

        // 2. Use the WebSocket instance to send data
        wsFuture.thenAccept(webSocket -> {
            System.out.println("Connected!");
            webSocket.sendText("Hello, WebSocket!", true);

            // Keep the connection open for a bit to receive the echo
            try { Thread.sleep(2000); } catch (InterruptedException e) { }

            webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "Done");
        }).join();
    }

    // 3. Implement the Listener to handle events
    private static class EchoListener implements WebSocket.Listener {

        @Override
        public void onOpen(WebSocket webSocket) {
            System.out.println("WebSocket opened");
            WebSocket.Listener.super.onOpen(webSocket);
        }

        @Override
        public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
            System.out.println("Received message: " + data);
            // Request the next message
            webSocket.request(1);
            return null; // Returning null means we're done with this message
        }

        @Override
        public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
            System.out.println("Closed: " + statusCode + " " + reason);
            return null;
        }

        @Override
        public void onError(WebSocket webSocket, Throwable error) {
            System.err.println("Error occurred: " + error.getMessage());
        }
    }
}

Key Concepts:

  • buildAsync(URI, Listener): This starts the opening handshake. It returns a CompletableFuture<WebSocket> because the handshake is asynchronous [1].
  • Backpressure (request(n)): By default, the client doesn’t automatically pull all messages from the server. In onText or onBinary, you usually call webSocket.request(1) to tell the client you are ready to receive the next message [2].
  • The last parameter: If a message is very large, it might be delivered in chunks. The last boolean flag tells you if the current chunk is the end of the message.
  • CompletionStage<?>: Listener methods return a CompletionStage. If you return a CompletableFuture, the client will wait for it to complete before calling that listener method again, which is useful for processing messages asynchronously without blocking the network thread [4].