Using the Google Gemini Large Language Model APIs in Java

This example is very similar to OpenAI API examples in the previous chapter. We use the Google Developer’s documentation as a reference: https://ai.google.dev/gemini-api/docs. We implement methods for completions and completions also using Google’s search tool.

Architecture diagram

Java Library to Use Google Gemini’s APIs

The library code defined in the directory Java-AI-Book-Code/gemini-llm-client is designed to interact with the Gemini API to accept a prompt string and get a text completion. Here’s a breakdown of what each part of the code does:

CLASS: com.markwatson.gemini.GeminiCompletions

Provides a set of static methods for interacting with the Google Gemini API and for performing related string and file utility operations.

FUNCTION: getCompletion(String prompt)

Sends a text prompt to the Gemini API and returns the generated text completion.

  • INPUT:
    • A String ‘prompt’.
  • REQUIRES:
    • The ‘GOOGLE_API_KEY’ environment variable must be set.
  • ACTION:
    • Constructs an HTTP POST request to the ‘gemini-2.5-flash’ model endpoint.
    • Packages the prompt into the required JSON body.
  • ON SUCCESS:
    • Returns the ‘text’ field from the API’s JSON response as a String.
  • ON FAILURE:
    • Throws an IOException if the API key is not found.

FUNCTION: getCompletionWithSearch(String prompt)

Sends a text prompt to the Gemini API using the search tool and returns the generated text completion.

  • INPUT:
    • A String ‘prompt’.
  • REQUIRES:
    • The ‘GOOGLE_API_KEY’ environment variable must be set.
  • ACTION:
    • Constructs an HTTP POST request to the ‘gemini-2.5-flash’ model endpoint.
    • Packages the prompt into the required JSON body.
  • ON SUCCESS:
    • Returns the ‘text’ field from the API’s JSON response as a String.
  • ON FAILURE:
    • Throws an IOException if the API key is not found.

FUNCTION: readFileToString(String filePath)

Reads the entire contents of a specified file into a single string.

  • INPUT:
    • A String ‘filePath’ pointing to a file.
  • ACTION:
    • Reads all bytes from the file.
    • Escapes all double-quote (“) characters found in the content.
  • ON SUCCESS:
    • Returns the file’s contents as a String.
  • ON FAILURE:
    • Throws an IOException if the file cannot be found or read.

FUNCTION: replaceSubstring(…)

A utility function that replaces all occurrences of a substring within a string.

  • INPUT:
    • An original string.
    • The substring to replace.
    • The replacement string.
  • OUTPUT:
    • Returns the new string with replacements made.

FUNCTION: promptVar(…)

A simple templating utility for substituting a placeholder in a string.

  • INPUT:
    • A template string.
    • A placeholder name to find.
    • The value to substitute.
  • OUTPUT:
    • Returns the new string with the placeholder replaced by the value.

Code Listing

  1 package com.markwatson.gemini;
  2 
  3 import org.json.JSONArray;
  4 import org.json.JSONObject;
  5 
  6 import java.io.IOException;
  7 import java.net.URI;
  8 import java.net.http.HttpClient;
  9 import java.net.http.HttpRequest;
 10 import java.net.http.HttpResponse;
 11 import java.nio.file.Files;
 12 import java.nio.file.Path;
 13 
 14 public class GeminiCompletions {
 15 
 16     private static final String DEFAULT_MODEL = "gemini-2.5-flash";
 17     public static String model = DEFAULT_MODEL;
 18 
 19     public static void main(String[] args) throws Exception {
 20         String prompt = "How much is 11 + 22?";
 21         String completion = getCompletion(prompt);
 22         System.out.println("completion: " + completion);
 23     }
 24 
 25     public static String getCompletion(String prompt) throws Exception {
 26         var jsonBody = buildRequestBody(prompt);
 27         return executeRequest(jsonBody);
 28     }
 29 
 30     public static String getCompletionWithSearch(String prompt) throws Exception {
 31         var textPart = new JSONObject().put("text", prompt);
 32         var parts = new JSONArray().put(textPart);
 33         var content = new JSONObject().put("parts", parts);
 34         var contents = new JSONArray().put(content);
 35 
 36         var googleSearchTool = new JSONObject().put("google_search", new JSONObject());
 37         var tools = new JSONArray().put(googleSearchTool);
 38 
 39         var body = new JSONObject()
 40                 .put("contents", contents)
 41                 .put("tools", tools);
 42 
 43         return executeRequest(body.toString());
 44     }
 45 
 46     private static String buildRequestBody(String prompt) {
 47         var textPart = new JSONObject().put("text", prompt);
 48         var parts = new JSONArray().put(textPart);
 49         var content = new JSONObject().put("parts", parts);
 50         var contents = new JSONArray().put(content);
 51         return new JSONObject().put("contents", contents).toString();
 52     }
 53 
 54     private static String executeRequest(String jsonBody) throws Exception {
 55         String apiKey = System.getenv("GOOGLE_API_KEY");
 56         if (apiKey == null || apiKey.isEmpty()) {
 57             throw new IOException("GOOGLE_API_KEY environment variable not set.");
 58         }
 59 
 60         var uri = URI.create(
 61                 "https://generativelanguage.googleapis.com/v1beta/models/" + model + ":generateContent?key=" + apiKey);
 62 
 63         var request = HttpRequest.newBuilder()
 64                 .uri(uri)
 65                 .header("Content-Type", "application/json")
 66                 .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
 67                 .build();
 68 
 69         HttpResponse<String> response;
 70         try (var client = HttpClient.newHttpClient()) {
 71             response = client.send(request, HttpResponse.BodyHandlers.ofString());
 72         }
 73 
 74         if (response.statusCode() != 200) {
 75             throw new IOException("Gemini API request failed (HTTP %d): %s"
 76                     .formatted(response.statusCode(), response.body()));
 77         }
 78 
 79         var jsonObject = new JSONObject(response.body());
 80         return jsonObject.getJSONArray("candidates").getJSONObject(0).getJSONObject("content").getJSONArray("parts")
 81                 .getJSONObject(0).getString("text");
 82     }
 83 
 84     /***
 85      * Utilities for using the Gemini API
 86      */
 87 
 88     // read the contents of a file path into a Java string
 89     public static String readFileToString(String filePath) throws IOException {
 90         return Files.readString(Path.of(filePath)).replace("\"", "\\\"");
 91     }
 92 
 93     public static String replaceSubstring(String originalString, String substringToReplace, String replacementString) {
 94         return originalString.replace(substringToReplace, replacementString);
 95     }
 96 
 97     public static String promptVar(String prompt0, String varName, String varValue) {
 98         String prompt = replaceSubstring(prompt0, varName, varValue);
 99         return replaceSubstring(prompt, varName, varValue);
100     }
101 }

In the next section we write a unit test for this Java class to demonstrate text completion.

Example Applications

Here are unit tests provided with this library that shows how to call each API:

 1     @Test
 2     @DisplayName("Simple completion returns a non-empty response")
 3     void testCompletion() throws Exception {
 4         String r = GeminiCompletions
 5                 .getCompletion("Translate the following English text to French: 'Hello, how are you?'");
 6         System.out.println("completion: " + r);
 7         assertNotNull(r, "Completion should not be null");
 8         assertFalse(r.isEmpty(), "Completion should not be empty");
 9     }
10 
11     @Test
12     @DisplayName("Two-shot template prompt returns a non-empty response")
13     void testTwoShotTemplate() throws Exception {
14         String input_text = "Mark Johnson enjoys living in Berkeley California at 102 Dunston Street and use mjess@foobar.com for contacting him.";
15         String prompt0 = GeminiCompletions.readFileToString("../prompts/two-shot-2-var.txt");
16         System.out.println("prompt0: " + prompt0);
17         String prompt = GeminiCompletions.promptVar(prompt0, "{input_text}", input_text);
18         System.out.println("prompt: " + prompt);
19         String r = GeminiCompletions.getCompletion(prompt);
20         System.out.println("two shot extraction completion: " + r);
21         assertNotNull(r, "Two-shot completion should not be null");
22         assertFalse(r.isEmpty(), "Two-shot completion should not be empty");
23     }
24 
25     @Test
26     @DisplayName("Summarization prompt returns a non-empty response")
27     void testSummarization() throws Exception {
28         String input_text = "Jupiter is the fifth planet from the Sun and the largest in the Solar System. It is a gas giant with a mass one-thousandth that of the Sun, but two-and-a-half times that of all the other planets in the Solar System combined. Jupiter is one of the brightest objects visible to the naked eye in the night sky, and has been known to ancient civilizations since before recorded history. It is named after the Roman god Jupiter.[19] When viewed from Earth, Jupiter can be bright enough for its reflected light to cast visible shadows,[ and is on average the third-brightest natural object in the night sky after the Moon and Venus.";
29         String prompt0 = GeminiCompletions.readFileToString("../prompts/summarization_prompt.txt");
30         System.out.println("prompt0: " + prompt0);
31         String prompt = GeminiCompletions.promptVar(prompt0, "{input_text}", input_text);
32         System.out.println("prompt: " + prompt);
33         String r = GeminiCompletions.getCompletion(prompt);
34         System.out.println("summarization completion: " + r);
35         assertNotNull(r, "Summarization result should not be null");
36         assertFalse(r.isEmpty(), "Summarization result should not be empty");
37     }
38 
39     @Test
40     @DisplayName("Completion with Google Search grounding returns a non-empty response")
41     void testCompletionWithSearch() throws Exception {
42         String prompt = "What is the current stock price of Google?";
43         String r = GeminiCompletions.getCompletionWithSearch(prompt);
44         System.out.println("Search completion: " + r);
45         assertNotNull(r, "Search completion should not be null");
46         assertFalse(r.isEmpty(), "Search completion should not be empty");
47     }

Sample output is:

 1 $ make
 2 mvn test -q # run test in quiet mode
 3 completion: Here are a few ways to say this in French, depending on the level of formality:
 4 
 5 *   **Formal/Standard:** *Bonjour, comment allez-vous ?*
 6 *   **Informal/Casual:** *Salut, ça va ?*
 7 *   **Neutral:** *Bonjour, comment ça va ?*
 8 
 9 Search completion: As of the market close on December 18, 2025, the stock prices for **Alphabet Inc. (Google)** are as follows:
10 
11 *   **Alphabet Inc. Class A (GOOGL):** ~$302.01
12 *   **Alphabet Inc. Class C (GOOG):** ~$303.29
13 
14 
15 prompt0: Given the two examples below, extract the names, addresses, and email addresses of individuals mentioned later as Process Text. Format the extracted information in JSON, with keys for \"name\", \"address\", and \"email\". If any information is missing, use \"null\" for that field. Be very concise in your output by providing only the output JSON.
16 
17 Example 1:
18 Text: \"John Doe lives at 1234 Maple Street, Springfield. His email is johndoe@example.com.\"
19 Output: 
20 {
21   \"name\": \"John Doe\",
22   \"address\": \"1234 Maple Street, Springfield\",
23   \"email\": \"johndoe@example.com\"
24 }
25 
26 Example 2:
27 Text: \"Jane Smith has recently moved to 5678 Oak Avenue, Anytown. She hasn't updated her email yet.\"
28 Output: 
29 {
30   \"name\": \"Jane Smith\",
31   \"address\": \"5678 Oak Avenue, Anytown\",
32   \"email\": null
33 }
34 
35 Process Text: \"{input_text}\"
36 Output:
37 
38 prompt: Given the two examples below, extract the names, addresses, and email addresses of individuals mentioned later as Process Text. Format the extracted information in JSON, with keys for \"name\", \"address\", and \"email\". If any information is missing, use \"null\" for that field. Be very concise in your output by providing only the output JSON.
39 
40 Example 1:
41 Text: \"John Doe lives at 1234 Maple Street, Springfield. His email is johndoe@example.com.\"
42 Output: 
43 {
44   \"name\": \"John Doe\",
45   \"address\": \"1234 Maple Street, Springfield\",
46   \"email\": \"johndoe@example.com\"
47 }
48 
49 Example 2:
50 Text: \"Jane Smith has recently moved to 5678 Oak Avenue, Anytown. She hasn't updated her email yet.\"
51 Output: 
52 {
53   \"name\": \"Jane Smith\",
54   \"address\": \"5678 Oak Avenue, Anytown\",
55   \"email\": null
56 }
57 
58 Process Text: \"Mark Johnson enjoys living in Berkeley California at 102 Dunston Street and use mjess@foobar.com for contacting him.\"
59 Output:
60 
61 two shot extraction completion: {
62   "name": "Mark Johnson",
63   "address": "102 Dunston Street, Berkeley California",
64   "email": "mjess@foobar.com"
65 }
66 prompt0: Summarize the following text: \"{input_text}\"
67 Output:
68 
69 prompt: Summarize the following text: \"Jupiter is the fifth planet from the Sun and the largest in the Solar System. It is a gas giant with a mass one-thousandth that of the Sun, but two-and-a-half times that of all the other planets in the Solar System combined. Jupiter is one of the brightest objects visible to the naked eye in the night sky, and has been known to ancient civilizations since before recorded history. It is named after the Roman god Jupiter.[19] When viewed from Earth, Jupiter can be bright enough for its reflected light to cast visible shadows,[ and is on average the third-brightest natural object in the night sky after the Moon and Venus.\"
70 Output:
71 
72 summarization completion: Jupiter is the fifth planet from the Sun and the largest in the Solar System. A gas giant named after the Roman god, it is more massive than all other planets combined and stands as the third-brightest natural object in the night sky.

Wrap Up

The Java test code for the Gemini API also contains two more complex examples, similar to what was listed in the last chapter for OpenAI API support.