Gemma 4 with Java: Build a Powerful AI Chatbot using Gemma 4 and Java

If you are looking for a practical way to use Gemma 4 in Java, this project is a strong place to begin. It shows how to connect a Java application to a powerful generative AI model, keep conversation history, stream responses in real time, and build a modern chatbot experience—without heavy frameworks.

Gemma 4 with Java

This guide is designed for developers searching for:

  • Gemma 4 Java tutorial
  • Gemma 4 with Maven
  • how to use Gemma 4 in Java
  • Google GenAI Java SDK example
  • build AI chatbot in Java

📌 What You’ll Learn

  • What Gemma 4 is and why it matters
  • Why Java is a strong choice for AI
  • Maven dependencies used
  • Full source code structure
  • Streaming chat implementation
  • Conversation history handling
  • Running the project locally
  • Extending into real applications

💡 Why Gemma 4 Is Interesting for Java Developers

Gemma 4 gives access to a powerful modern model that integrates directly into real-world applications.

With Java, this unlocks:

  • AI-powered assistants
  • Enterprise chatbots
  • Documentation tools
  • Code helpers
  • Support systems
  • Research assistants

Instead of Python-only workflows, this brings AI into enterprise-ready Java ecosystems.

🛠️ What This Project Builds

This project creates a terminal-based AI chatbot using:

String model = "gemma-4-31b-it";

Features included:

  • Interactive console input
  • Real-time streaming output
  • Conversation memory
  • Command handling
  • API key via .env
  • Optional Google Search tool

👉 This is not just a demo—it’s a real chatbot architecture.

⚙️ Why Use Java for Gemma 4?

Java is still one of the best choices for production AI systems:

  • Stable and scalable
  • Strong ecosystem (APIs, DBs, queues)
  • Maven dependency management
  • Clean architecture
  • Easy enterprise integration

If you’re already using Java → no need to switch to Python.

📦 Maven Dependencies

Paste this inside your pom.xml:

<dependencies>

<!-- Google GenAI SDK -->
<dependency>
  <groupId>com.google.genai</groupId>
  <artifactId>google-genai</artifactId>
  <version>1.10.0</version>
</dependency>

<!-- Guava -->
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>33.4.0-jre</version>
</dependency>

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

<!-- DotEnv -->
<dependency>
  <groupId>io.github.cdimascio</groupId>
  <artifactId>dotenv-java</artifactId>
  <version>3.2.0</version>
</dependency>

</dependencies>

🔍 What Each Dependency Does

1. google-genai

Main SDK → connects Java to Gemma 4

2. guava

Used for clean immutable data structures

3. gson

Handles JSON (useful for AI responses)

4. dotenv-java

Loads API keys securely from .env

▶️ Maven Run Plugin

<build>
  <plugins>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <version>3.5.0</version>
      <configuration>
        <mainClass>com.gangforcode.Main</mainClass>
      </configuration>
    </plugin>
  </plugins>
</build>

☕ Java Version

<properties>
  <maven.compiler.source>21</maven.compiler.source>
  <maven.compiler.target>21</maven.compiler.target>
</properties>

👉 Uses Java 21 (modern + recommended)

🔐 Environment Setup

Create a .env file:

GEMINI_API_KEY=your_api_key_here

✔ Keeps secrets safe
✔ Works in dev + production


🧠 Core Concepts in Code

API Key Loading

Dotenv dotenv = Dotenv.configure().load();
String apiKey = dotenv.get("GEMINI_API_KEY");

Client Initialization

Client client = Client.builder().apiKey(apiKey).build();

Model Selection

String model = "gemma-4-31b-it";

Streaming Responses

client.models.generateContentStream(...)

👉 Output appears live (like ChatGPT typing)

Chat Memory

List<Content> chatHistory = new ArrayList<>();

👉 Enables context-aware conversations

Complete Java Code (Main.Java)

package com.gangforcode;

import com.google.common.collect.ImmutableList;
import com.google.genai.Client;
import com.google.genai.ResponseStream;
import com.google.genai.types.*;
import io.github.cdimascio.dotenv.Dotenv;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

    private static final String PROMPT_PREFIX = "\n\033[34mYou\033[0m> ";
    private static final String TYPING_INDICATOR = "\033[90mGemini is thinking...\033[0m\n";
    private static final String ASSISTANT_PREFIX = "\033[32mGemini\033[0m> ";
    private static final String ERROR_PREFIX = "\033[31m[ERROR]\033[0m ";
    private static final String INFO_PREFIX = "\033[36m[INFO]\033[0m ";
    private static final String SUCCESS_PREFIX = "\033[32m[OK]\033[0m ";
    
    private static int messageCount = 0;
    private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");

    public static void main(String[] args) {
        // Load environment variables from .env file
        Dotenv dotenv = Dotenv.configure()
                .directory(System.getProperty("user.dir"))
                .ignoreIfMissing()
                .load();

        String apiKey = dotenv.get("GEMINI_API_KEY");
        if (apiKey == null || apiKey.isEmpty()) {
            apiKey = System.getenv("GEMINI_API_KEY");
        }

        if (apiKey == null || apiKey.isEmpty()) {
            System.err.println(ERROR_PREFIX + "GEMINI_API_KEY is not set in .env file or environment variables.");
            System.exit(1);
        }

        Client client = Client.builder().apiKey(apiKey).build();
        String model = "gemma-4-31b-it";

        List<Tool> tools = new ArrayList<>();
        tools.add(
            Tool.builder()
                .googleSearch(
                    GoogleSearch.builder().build()
                )
                .build()
        );

        GenerateContentConfig config =
            GenerateContentConfig
                .builder()
                .tools(tools)
                .build();

        // Maintain conversation history
        List<Content> chatHistory = new ArrayList<>();

        Scanner scanner = new Scanner(System.in);

        // Display welcome message
        displayWelcome();

        while (true) {
            System.out.print(PROMPT_PREFIX);
            String userInput = scanner.nextLine().trim();

            if (userInput.isEmpty()) {
                continue;
            }

            // Handle special commands
            if (handleCommand(userInput, chatHistory)) {
                continue;
            }

            // Regular chat message
            messageCount++;
            
            // Build user content for this turn
            Content userContent = Content.builder()
                    .role("user")
                    .parts(ImmutableList.of(Part.fromText(userInput)))
                    .build();

            // Add to history
            chatHistory.add(userContent);

            System.out.print(TYPING_INDICATOR);
            System.out.print(ASSISTANT_PREFIX);

            try {
                ResponseStream<GenerateContentResponse> responseStream = client.models.generateContentStream(model, chatHistory, config);

                StringBuilder fullResponse = new StringBuilder();
                boolean hasContent = false;

                for (GenerateContentResponse res : responseStream) {
                    if (res.candidates().isEmpty() || res.candidates().get().get(0).content().isEmpty() || res.candidates().get().get(0).content().get().parts().isEmpty()) {
                        continue;
                    }

                    List<Part> parts = res.candidates().get().get(0).content().get().parts().get();
                    for (Part part : parts) {
                        var textObj = part.text();
                        String text = (textObj != null && textObj.isPresent()) ? textObj.get() : null;
                        if (text != null && !text.isEmpty()) {
                            System.out.print(text);
                            fullResponse.append(text);
                            hasContent = true;
                        }
                    }
                }

                responseStream.close();

                if (hasContent && fullResponse.length() > 0) {
                    // Add assistant response to history
                    Content assistantContent = Content.builder()
                            .role("model")
                            .parts(ImmutableList.of(Part.fromText(fullResponse.toString())))
                            .build();
                    chatHistory.add(assistantContent);
                } else {
                    System.out.print("\033[90m(No response available)\033[0m");
                }

                System.out.println();

            } catch (Exception e) {
                System.out.println("\n" + ERROR_PREFIX + e.getMessage());
            }
        }
    }

    /**
     * Display welcome banner and instructions
     */
    private static void displayWelcome() {
        System.out.println("\033[1;36m╔═══════════════════════════════════════════════════════════╗");
        System.out.println("║       Gemini AI - Fully Interactive Terminal Chatbot       ║");
        System.out.println("║            Powered by Google Generative AI                ║");
        System.out.println("╚═══════════════════════════════════════════════════════════╝\033[0m");
        System.out.println();
        System.out.println("\033[1;33mCommands:\033[0m");
        System.out.println("  \033[1m/help\033[0m         - Show this help message");
        System.out.println("  \033[1m/clear\033[0m        - Clear conversation history");
        System.out.println("  \033[1m/stats\033[0m        - Show conversation statistics");
        System.out.println("  \033[1m/history\033[0m      - Show conversation history summary");
        System.out.println("  \033[1m/exit or /quit\033[0m - Exit the chatbot");
        System.out.println();
        System.out.println("\033[90mStarting interactive session...\033[0m");
        System.out.println();
    }

    /**
     * Handle special commands
     * @return true if a command was handled, false otherwise
     */
    private static boolean handleCommand(String input, List<Content> chatHistory) {
        String command = input.toLowerCase();

        if (command.equals("/exit") || command.equals("/quit")) {
            System.out.println("\033[1;33m👋 Goodbye! Thank you for chatting with Gemini AI.\033[0m");
            System.exit(0);
            return true;
        }

        if (command.equals("/clear")) {
            chatHistory.clear();
            messageCount = 0;
            System.out.println(SUCCESS_PREFIX + "\033[90mConversation cleared. Ready for new chat!\033[0m");
            return true;
        }

        if (command.equals("/help")) {
            displayWelcome();
            return true;
        }

        if (command.equals("/stats")) {
            displayStats(chatHistory);
            return true;
        }

        if (command.equals("/history")) {
            displayHistorySummary(chatHistory);
            return true;
        }

        return false;
    }

    /**
     * Display conversation statistics
     */
    private static void displayStats(List<Content> chatHistory) {
        System.out.println("\n" + INFO_PREFIX + "\033[1mConversation Statistics\033[0m");
        System.out.println("  Total Messages: " + (messageCount > 0 ? messageCount : 0));
        System.out.println("  Total Exchanges: " + (chatHistory.size() / 2));
        System.out.println("  User Messages: " + countMessagesByRole(chatHistory, "user"));
        System.out.println("  Assistant Messages: " + countMessagesByRole(chatHistory, "model"));
        System.out.println("  Current Time: " + LocalDateTime.now().format(timeFormatter));
        System.out.println();
    }

    /**
     * Display conversation history summary
     */
    private static void displayHistorySummary(List<Content> chatHistory) {
        if (chatHistory.isEmpty()) {
            System.out.println(INFO_PREFIX + "\033[90mNo conversation history yet.\033[0m\n");
            return;
        }

        System.out.println("\n" + INFO_PREFIX + "\033[1mConversation History\033[0m");
        int count = 1;
        try {
            for (Content content : chatHistory) {
                String role = content.role().orElse("unknown");
                String roleDisplay = role.equals("user") ? "\033[34m[You]\033[0m" : "\033[32m[Gemini]\033[0m";
                System.out.println("  " + count++ + ". " + roleDisplay + " (message)");
            }
        } catch (Exception e) {
            System.out.println(INFO_PREFIX + "Could not display full history: " + e.getMessage());
        }
        System.out.println();
    }

    /**
     * Count messages by role
     */
    private static int countMessagesByRole(List<Content> chatHistory, String role) {
        return (int) chatHistory.stream()
                .filter(content -> content.role().orElse("unknown").equals(role))
                .count();
    }
}

💬 Commands Supported

  • /help → show commands
  • /clear → reset chat
  • /stats → conversation stats
  • /history → summary
  • /exit → quit

▶️ How to Run

mvn compile exec:java

Or you can directly compile and run Main.java file

Gemma 4 with java

Gemma 4

Gemma 4 with java in working

Gemma 4 in working

🔥 Why This Project Matters

This project demonstrates real-world AI patterns:

  • Secure config handling
  • Model usage
  • Streaming UX
  • Stateful chat
  • Clean architecture

👉 It’s a production-ready foundation


🚀 How You Can Extend It

Turn this into:

  • Spring Boot API
  • Web chatbot (Next.js frontend 👀)
  • Desktop app
  • Internal company assistant
  • Multi-tool AI agent

🎯 Takeaway

This project proves:

  • Gemma 4 works in Java
  • Maven setup is simple
  • Streaming is possible
  • Chat memory works
  • You can build real AI apps

❓ FAQ

Can I use Gemma 4 in Java?

Yes, via Google GenAI SDK.

What dependency is required?

com.google.genai:google-genai:1.10.0

Is Java good for AI chatbots?

Yes—especially for backend + enterprise systems.

Does it support streaming?

Yes, using generateContentStream().

Can I build a web app from this?

Yes—use it as backend for:

  • Spring Boot
  • Next.js
  • Desktop UI

See Also

Leave a Comment