VS Code + Docker + Gemini CLI で Java 開発(Gradle 版)

に公開

はじめに

この記事は「VS Code の Java プロジェクトを Gemini CLI に対応させよう」の続きです。

前回は、シェルスクリプトで管理するシンプルな Java プロジェクトに Gemini CLI を導入し、GEMINI.md を作成して開発規約を整備していくプロセスを紹介しました。

AI との対話を通じてプロジェクトのルールを整理して明確にすることができましたが、一方で、手動のライブラリ管理や自作スクリプトによるビルドには限界も見えてきました。

そこで今回は、開発体験をさらに一歩進めるため、Gemini との対話を通じて以下の 2 つの改善を行いました。

  1. Gemini CLI が利用可能な開発コンテナ(Dev Container)環境の構築
  2. シェルスクリプトベースのプロジェクトから Gradle プロジェクトへの移行

これにより、プロジェクトのポータビリティとメンテナンス性が大幅に向上しました。この記事では、その具体的なプロセスを追体験していきます。また、Gradle プロジェクトについても簡単に説明します。

動作確認については、Ubuntu Desktop 24.04 と Windows 11 Pro 上で行っています。Windows 上でもターミナルは Git Bash for Windows や WSL Ubuntu を主に使用しているため、コマンドは bash 上で実行する前提で紹介してあります。

なお、今回はデバッグ実行についての設定については、説明が長くなるため省略しています。また別の機会に説明する予定です。

サンプルコード

GitHub にサンプルコードを用意したので、先に紹介しておきます。

java-app002-00 のタグをつけてあります。

タグ 説明
java-app002-00 今回、解説するもの
前回の dvc-java ブランチ 前回のもの(2025-09-13 版)

Gemini CLI 向け Dev Container のセットアップ

これまでの作業では、Gemini CLI をローカルマシンで実行していました。しかし、開発環境の再現性やポータビリティを考えると、Dev Container 内で直接 Gemini CLI を使えるのが理想です。

そこで、Gemini に次のように依頼してみました。

  • このプロジェクトの Dev Container で Gemini CLI を使えるように設定して

すると Gemini は、Gemini CLI の実行に必要なパッケージのインストールと、ホストマシンの認証情報をコンテナに引き継ぐための設定を提案してくれました。

Dev Container による環境構築については、Gemini だけでは難しかったので、主要な部分は自分で作成して、雛形作成や細かい文法チェックの部分を Gemini 担当としました。

最終的に、ここで用意した開発コンテナ用のファイルは次のようになりました。

dvc-java-gemini/
├── .devcontainer/
│   ├── Dockerfile
│   ├── compose.yaml
│   └── devcontainer.json
├── .gemini
└── .gitignore

各ファイルの説明は次のとおりです。

ファイル 説明
.devcontainer/Dockerfile 開発コンテナ用イメージのビルド用ファイル
.devcontainer/compose.yaml 開発コンテナのリソース管理用 Docker Compose 設定ファイル
.devcontainer/devcontainer.json 開発コンテナ設定用ファイル
.gemini/ Gemini CLI 設定ファイル用フォルダ
.gitignore .gemini を Git リポジトリ対象外とするためのファイル

dvc-java-gemini を Git リポジトリとしている場合は、誤って .gemini フォルダをリポジトリへ追加しないように注意してください。そのため、先に .gitignore を作成しておくと良いでしょう。内容は次のようにしておきます。

/.gemini/

なお、この後の説明では、dvc-java-gemini フォルダのパスを ${PROJECT_DIR} と表記します。

devcontainer.json の更新

devcontainer.json は、VS Code が開発コンテナをどのように設定し、起動するかを定義する中心的なファイルです。従来は "image": で開発コンテナ用の単一イメージを指定していましたが、今回は compose.yaml と連携するため、"dockerComposeFile": でコンテナ構成ファイルを指定します。

${PROJECT_DIR}/.devcontainer/devcontainer.json:

devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/java
{
  "name": "dvc-java-gemini",
  "dockerComposeFile": "./compose.yaml",
  "service": "dvc-java-gemini",
  "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
  "customizations": {
    "vscode": {
      "settings": {
        "terminal.integrated.defaultProfile.linux": "bash"
      },
      "extensions": [
        "vscjava.vscode-java-pack",
        "shengchen.vscode-checkstyle",
        "ms-azuretools.vscode-containers",
        "docker.docker",
        "eamodio.gitlens",
        "donjayamanne.githistory",
        "mhutchie.git-graph",
        "google.gemini-code-assist",
        "google.gemini-cli-vscode-ide-companion"
      ]
    }
  }
}

以下に、主要な設定項目について説明します。

name は、開発コンテナに付ける表示名です。VS Code の UI などで表示されます。

dockerComposeFile は、開発コンテナの構成を定義する Docker Compose ファイルへのパスを指定します。

service は、compose.yaml 内で定義されているサービスの中から、開発コンテナとして使用するサービス名を指定します。

workspaceFolder は、開発コンテナ内で VS Code が開くデフォルトのフォルダパスです。${localWorkspaceFolderBasename} は、ホストマシン上のプロジェクトフォルダ名を自動的に展開してくれる便利な変数です。

customizations.vscode.settings というセクションでは、開発コンテナ環境に特化した VS Code の設定を上書きできます。ここでは、Linux コンテナ内のデフォルトターミナルプロファイルを bash に設定しています。

customizations.vscode.extensions というセクションでは、開発コンテナの起動時に自動的にインストールする VS Code 拡張機能のリストを指定できます。ここでは、Java 開発に必要な vscjava.vscode-java-pack や、今回利用する Checkstyle(shengchen.vscode-checkstyle)、Gemini Code Assist (google.gemini-code-assist)、Gemini CLI Companion (google.gemini-cli-vscode-ide-companion) などを追加しています。

compose.yaml の作成

次に compose.yaml で、devcontainer.json で指定した dvc-java-gemini サービスを定義します。build: . で同階層の Dockerfile を参照し、dvc-java-gemini:0.0.1 というイメージをビルドするよう指定しています。

開発コンテナ内では /workspaces/dvc-java-gemini を作業フォルダとするため、Docker ホストのプロジェクトルート (dvc-java-gemini フォルダ) をバインドマウントする必要があります。これは volumes の設定で行います。source: ..compose.yaml の親フォルダ (プロジェクトルート) を指定し、target: でコンテナ内のワークスペースパスを指定することで、ホストとコンテナのファイル共有を実現しています。

volumes: にはもう一つ、# Gemini CLI の設定用フォルダ という指定があります。これは、ホストマシンで gemini init を実行した際に生成される認証情報 (通常 ~/.gemini に保存される) を、開発コンテナ内の node ユーザーが使えるようにするためのものです。これにより、コンテナを起動するたびに認証をやり直す手間が省けます。

${PROJECT_DIR}/.devcontainer/compose.yaml:

compose.yaml
name: dvc-java-gemini
services:
  dvc-java-gemini:
    build: .
    image: dvc-java-gemini:0.0.1
    tty: true
    volumes:
      # 開発コンテナで使う作業用フォルダ
      - type: bind
        source: ..
        target: /workspaces/dvc-java-gemini
      # Gemini CLI の設定用フォルダ
      - type: bind
        source: ../.gemini
        target: /home/node/.gemini

compose.yaml を作成したら、ホスト側の認証情報をコンテナで利用するために ${PROJECT_DIR}/.gemini を用意します。ホストマシンで gemini コマンドの認証が済んでいれば、Linux/WSL Ubuntu であれば ~/.gemini に認証情報が保存されているので、これを ${PROJECT_DIR}/.gemini へコピーします。(Windows 環境については未確認ですが、Git Bash for Windows 上での ~/.gemini に認証情報が保存されるのだと思います。)

これらの作業は、ターミナルで次のように実行できます。

cd ${PROJECT_DIR}
cp -r ~/.gemini ./
rm -fr ./.gemini/tmp

Dockerfile の作成

最後に、今回使用する Docker イメージをビルドするための Dockerfile を作成します。

Dockerfile で使用している主な命令は次のとおりです。

命令 説明
FROM ベースとなる Docker イメージを指定
USER RUNCMDENTRYPOINT 命令を実行するユーザー名または UID を指定
RUN イメージのビルド時に実行するコマンドを指定

USER を指定することで、それ以降の RUNCMDENTRYPOINT 命令を実行するユーザーを切り替えることができます。

今回の Dockerfile では、まず root ユーザーで xdg-utils パッケージをインストールします。その後に node ユーザーへ切り替えて、npm で Gemini CLI 本体をグローバルインストールします。

${PROJECT_DIR}/.devcontainer/Dockerfile:

Dockerfile
FROM hiro345g/dvc:jdk-202507

# パッケージインストールのため root
USER root

# Linux で Gemini CLI を使う場合で、認証時に xdg-utils が必要と
# なることがあるため、インストールしておく。
RUN apt-get update \
    && apt-get install -y xdg-utils \
    && apt-get -y autoremove \
    && apt-get -y clean \
    && rm -rf /var/cache/apt /var/lib/apt/lists

# ここから node ユーザーによる作業
USER node

# gemini-cli を node ユーザーでグローバルインストール
RUN npm install -g @google/gemini-cli

準備ができたら、イメージをビルドします。

cd ${PROJECT_DIR}
docker compose -f .devcontainer/compose.yaml build

これで開発コンテナの準備が整いました。これを使えば、開発コンテナ内で gemini コマンドが使えるようになります。これで、次の Gradle プロジェクトへの移行を進めていきます。

Gradle プロジェクトへの移行

次に、プロジェクトのビルドについて、ビルドツールを採用することで、近代化します。これまでのシェルスクリプトによる手動管理は、依存ライブラリが増えるにつれて煩雑さが増していきます。

そこで、Java 開発で広く使われているビルドツール Gradle へ移行することにしました。

Gradle とは

ここで、Gradle について簡単に触れておきます。

Gradle は、Apache Groovy または Kotlin の DSL (Domain Specific Language) を使ってビルドスクリプトを記述する、オープンソースのビルド自動化ツールです。単なるコンパイルやパッケージングだけでなく、依存関係の管理、テストの実行、静的解析、デプロイまで、ソフトウェア開発のライフサイクル全体を自動化できます。

Java のビルドツールとしては、他に Apache Maven というものが有名です。Maven では、XML による静的な設定ファイルによりビルドを管理しますが、Gradle は Groovy または Kotlin というスクリプト言語によりビルドを管理します。スクリプト言語の柔軟性を活かした、動的で表現力豊かなビルド定義が可能です。

DSL として、Groovy と Kotlin のどちらを選択すると良いかは悩むところですが、筆者は基本は Groovy を採用するようにしています。Groovy の方が Kotlin より歴史があり、資料も豊富だからです。主要な Java の IDE が標準でサポートしているのが Groovy だということも関係しています。Android アプリの開発などで Kotlin を使っていて慣れているなら、Kotlin を採用しても良いでしょう。

Gemini による Gradle への移行

この Gradle への移行も次のように Gemini に依頼しました。

  • java-app001 の Java プロジェクトを Gradle プロジェクトの java-app002 に変換すること。このとき、「ソースコード」や「Checkstyle の設定」は維持すること。

この依頼に対し、Gemini から以下の手順が提案されました。

  1. gradle init タスクを実行して、Gradle プロジェクトの基本的な骨格を生成する。
  2. 既存のソースファイル (App.java, AppTest.java) とリソースファイル (logback.xml) を、Gradle が定める標準的なフォルダ構造 (src/main/java, src/test/java など) に移動する。
  3. build.gradle ファイルを編集し、必要な依存関係 (SLF4J, Logback, JUnit) と Checkstyle プラグインの設定を追加する。

そこで、この提案に従って作業を進めました。

さらに、次の要求を順番に Gemini にすることで、これから紹介する java-app002 という新しい Gradle プロジェクトを完成させることができました。

  • java-app002 を Javadoc 対応とすること
  • ドキュメントについての方針を GEMINI.mdREADME.md へ追加すること
  • java-app002 について、テスト結果のレポート生成に対応すること
  • ドキュメント生成とレポート生成について動作確認すること

なお、プロジェクト作成後、GEMINI.mdREADME.md を Gradle プロジェクトに合わせて修正する作業も Gemini に依頼しました。

フォルダ構成

Gradle を採用することで、プロジェクトの構造が標準化され、ビルドプロセスが自動化されます。その結果、メンテナンス性が劇的に向上します。

ここで、最終的に完成した java-app002 のフォルダ構成は次のようになりました。

${PROJECT_DIR}/java-app002/
├── .gitattributes
├── .gitignore
├── .gradle/              # Gradleが使用するキャッシュやメタデータ
├── GEMINI.md
├── README.md
├── app/                  # アプリケーションのサブプロジェクト
│   ├── build/            # ビルド成果物 (クラスファイル、JARなど)
│   ├── build.gradle      # appサブプロジェクトのビルドスクリプト
│   ├── logs/
│   │   └── app.log
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── internal/
│       │   │       └── dev/
│       │   │           └── App.java
│       │   └── resources/
│       │       └── logback.xml
│       └── test/
│            ├── java/
│            │   └── internal/
│            │       └── dev/
│            │           └── AppTest.java
│            └── resources/
├── google_checks.xml     # Checkstyleのルール定義
├── gradle/
│   ├── libs.versions.toml # 依存ライブラリのバージョンカタログ
│   └── wrapper/          # Gradle Wrapperの設定
├── gradle.properties     # Gradleのビルド環境設定
├── gradlew*              # Gradle Wrapper (Unix/Linux/Mac用)
├── gradlew.bat           # Gradle Wrapper (Windows用)
├── java-app002.code-workspace  # VS Code 用ワークスペースファイル
└── settings.gradle       # プロジェクト構成の定義

gradlewgradlew.batGradle Wrapper と呼ばれるスクリプトです。これを使うことで、開発者のマシンに Gradle がインストールされていなくても、プロジェクトで指定されたバージョンの Gradle を自動的にダウンロードしてビルドを実行できます。これにより、環境によるビルドの差異がなくなり、再現性が高まります。

Gradle プロジェクトでは、「設定より規約」の考え方に基づき、標準的なフォルダ構成が推奨されています。この規約に従うことで、ビルドスクリプトの記述を最小限に抑えることができます。

  • src/main/java: 製品コードの Java ソースファイルを配置
  • src/main/resources: 製品コードで使われるリソースファイル (設定ファイルなど) を配置
  • src/test/java: テストコードの Java ソースファイルを配置
  • src/test/resources: テストコードで使われるリソースファイルを配置

今回のプロジェクト移行では、Gemini がこれらの規約に従ってファイルを移動してくれました。また、src/main/java 以下のフォルダ階層 (internal/dev) は Java のパッケージ構造に対応するため、ソースコードにも package internal.dev; という宣言が追加されています。

app/src/main/java/internal/dev/App.java:

App.java
package internal.dev;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The main application class.
 */
public class App {
  // 略
}

app/src/test/java/internal/dev/AppTest.java:

AppTest.java
package internal.dev;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

/**
 * Test class for the App class.
 */
public class AppTest {
  // 略
}

生成された Gradle プロジェクトの構成

ここでは、Gemini の支援によって生成・編集された主要な Gradle 設定ファイルについて説明します。

settings.gradle

このファイルは、ビルドに含まれるプロジェクトを定義するためのものです。マルチプロジェクトビルドの構成情報を記述します。

  • rootProject.name: ルートプロジェクトの名前を設定
  • include('app'): app という名前のサブプロジェクトをビルドに含めることを宣言
  • plugins: 使用するプラグインについての設定

plugins について、ここでは foojay-resolver-convention プラグインが使われています。これは、開発環境間で JDK のバージョンを自動的に解決し、一貫性を保つためのものです。

settings.gradle
/*
 * This file was generated by the Gradle 'init' task.
 */

plugins {
    id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0'
}

rootProject.name = 'java-app002'
include('app')

app/build.gradle

これは app サブプロジェクトのビルドスクリプトです。プロジェクトのビルド、テスト、依存関係の管理など、具体的なタスクを定義します。

plugins では、applicationcheckstyle のプラグインを使うことを宣言しています。

application プラグインを使うことで、run タスクが追加され、Java アプリケーションとして実行可能になります。

checkstyle プラグインを使うことで、Checkstyle によるコードの静的解析が可能になります。これは、check タスクの一部として実行されるようになります。

repositoriesには、プロジェクトが利用するライブラリをどこからダウンロードするかを設定します。mavenCentral() は、Java の世界で最も一般的に使われるセントラルリポジトリです。

dependencies には、プロジェクトが必要とするライブラリ (依存関係) を定義します。implementation はアプリケーションのソースコードで、testImplementation はテストコードでのみ利用可能な依存関係を示します。libs.guava のような記述は、後述する gradle/libs.versions.toml で定義されたライブラリを参照しています。

testing は、テストの実行に関する設定です。ここでは useJUnit('4.13.2') によって、テストフレームワークとして JUnit 4 を使用することを指定しています。

java は、Java のコンパイルに関する設定です。toolchain を使うことで、プロジェクトで使う JDK のバージョンを 21 に固定しています。

application は、application プラグインの設定です。mainClass で、./gradlew run を実行した際に起動するメインクラスを指定します。

checkstyle は、checkstyle プラグインの設定です。configFile で、使用する Checkstyle のルールセット (google_checks.xml) を指定しています。

app/build.gradle
/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java application project to get you started.
 * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.14.2/userguide/building_java_projects.html in the Gradle documentation.
 * This project uses @Incubating APIs which are subject to change.
 */

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
    // Apply the checkstyle plugin to add support for checking Java code style.
    id 'checkstyle'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use SLF4J for logging
    implementation libs.slf4j.api
    // Use Logback for logging implementation
    implementation libs.logback.classic

    // This dependency is used by the application.
    implementation libs.guava

    // Use Hamcrest for test assertions
    testImplementation libs.hamcrest.core
}

testing {
    suites {
        // Configure the built-in test suite
        test {
            // Use JUnit4 test framework
            useJUnit('4.13.2')
        }
    }
}

// Apply a specific Java toolchain to ease working on different environments.
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

application {
    // Define the main class for the application.
    mainClass = 'internal.dev.App'
}

checkstyle {
    toolVersion = '10.17.0'
    configFile = rootProject.file('google_checks.xml')
}

Gradle 採用のメリットは多くありますが、メンテナンス時に一番効果があるのは dependencies の指定です。ここを見れば、プロジェクトがどのライブラリに依存しているかが一目瞭然です。脆弱性対策が必要な場合に、このプロジェクトが該当するかどうかを確認するときに、ここを見ることから始まります。

また、必要なライブラリについても、ここで指定すれば自動で JAR ファイルをダウンロードし、クラスパスへ追加されるようになります。もう、手動で対応する必要はありません。

gradle/libs.versions.toml

これは Version Catalog という機能で、プロジェクトの依存関係を一元管理するためのファイルです。特にマルチプロジェクト構成の場合に、複数の build.gradle ファイル間でライブラリのバージョンを統一し、管理を容易にする強力な仕組みです。

[versions] セクションでは、ライブラリのバージョン番号を変数として定義します。例えば guava = "33.4.5-jre" と定義することで、複数のライブラリが同じバージョンを使う場合に参照できます。

[libraries] セクションでは、識別子となる各ライブラリの group と name を指定します。また [versions] で定義したバージョンもセットで指定することで、使用するライブラリを定義します。これにより、build.gradle ファイル内では libs.guava のようなタイプセーフなエイリアスで依存関係を記述できるようになります。

この仕組みにより、build.gradle からバージョン番号を分離し、見通しを良くすると同時に、ライブラリのバージョンアップ作業をこのファイル一箇所に集約できます。

gradle/libs.versions.toml
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format

[versions]
guava = "33.4.5-jre"
slf4j = "2.0.17"
logback = "1.5.6"
hamcrest = "1.3"

[libraries]
guava = { module = "com.google.guava:guava", version.ref = "guava" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
hamcrest-core = { module = "org.hamcrest:hamcrest-core", version.ref = "hamcrest" }

この移行により、古いシェルスクリプト (build.sh, test.sh, run.sh) は不要になり、以下の標準的な Gradle コマンドでプロジェクトのライフサイクルを管理できるようになりました。

  • ビルドと Checkstyle 実行: ./gradlew build
  • アプリケーションの実行: ./gradlew run
  • テストの実行: ./gradlew test

テスト結果の可視化

Gradle のもう一つの便利な機能が、テストレポートの自動生成です。./gradlew test を実行すると、単にテストが実行されるだけでなく、結果をまとめた HTML 形式のレポートが app/build/reports/tests/test/index.html に生成されます。

このレポートを開くと、どのテストが成功し、どれが失敗したかが一目でわかります。失敗したテストについては、エラーの詳細やスタックトレースも確認できるため、問題の原因を特定するのに非常に役立ちます。

コンソール出力を確認するよりも、より視覚的にテスト結果の確認ができるため、プログラムの動作確認作業が格段に効率化されます。

Javadoc の生成

Javadoc とは、Java のソースコード内に特定の形式で記述されたコメントから、API 仕様書を HTML 形式で生成するためのツールです。/** ... */ という形式のコメントブロック内に、@param (引数) や @return (戻り値) といったタグを使ってクラスやメソッドの仕様を記述します。詳しくは、Oracle が提供する公式ドキュメントを参照してください。

この仕組みに従ってコードにドキュメントを埋め込んでおくことで、コードそのものがドキュメントとして機能し、いつでも最新の API 仕様書を生成できるようになります。

Gradle は、この Javadoc の生成も簡単に行えます。プロジェクトのルートで次のコマンドを実行するだけです。

./gradlew javadoc

これにより、app/build/docs/javadoc フォルダに HTML 形式の API ドキュメントが生成されます。ソースコードに記述された Javadoc コメントが、整形された見やすいドキュメントとして出力されるため、コードの仕様を共有する際に非常に便利です。

VS Code + Docker + Gradle

VS Code で開発コンテナ(Docker)を使って、Gradle プロジェクトを開いたときの画面について説明します。

VS Code の Dev Containers 機能と Java/Gradle 拡張機能が連携することで、コンテナ内での開発がローカル環境と遜色ない、非常にスムーズな体験になります。

VS Code ワークスペースファイル

最初に、プロジェクト用の VS Code ワークスペースファイル java-app002.code-workspace について説明します。

これは java-app001.code-workspace のものをベースとして、Checkstyle 機能に対応しています。また、build フォルダには Javadoc やテスト結果のレポートが出力されているので、これについて表示するような設定に変更してあります。

実際に用意したワークスペースファイルは次のとおりです。

java-app002.code-workspace
{
  // ワークスペースに含めるフォルダを指定
  "folders": [
    {
      "path": "."
    }
  ],
  // ワークスペース全体に適用する設定
  "settings": {
    // Javaのバージョン設定
    // Dev Container を使っている場合は不要なことが多いですが、明示的に指定する例です
    "java.configuration.runtimes": [
      {
        "name": "JavaSE-21",
        "path": "/usr/local/sdkman/candidates/java/21.0.7-tem", // Dev Container内のJDKパス
        "default": true
      }
    ],
    // ファイル保存時に自動でフォーマットする
    "editor.formatOnSave": true,
    // Checkstyleの設定
    "java.checkstyle.configuration": "${workspaceFolder}/google_checks.xml",
    "java.checkstyle.version": "10.17.0", // Checkstyleのバージョンを指定
    // Lombok などの Java エージェントを使う場合の設定例(必要ならコメント解除)
    // "java.jdt.ls.vmargs": "-noverify -Xmx1G -jar /path/to/lombok.jar -Djava.awt.headless=true",
    // エクスプローラーから直接操作することのないファイル/フォルダを非表示
    "files.exclude": {
      "**/.git": true,
      "**/.svn": true,
      "**/.hg": true,
      "**/CVS": true,
      "**/.DS_Store": true,
      "**/Thumbs.db": true,
      "**/.gradle": true,
      "**/build": false,
      "**/.settings": true, // Eclipse 固有の設定ファイル
      "**/.classpath": true,
      "**/.project": true
    }
  },
  // ワークスペースで推奨する拡張機能
  "extensions": {
    "recommendations": [
      "vscjava.vscode-java-pack",
      "shengchen.vscode-checkstyle", // Checkstyle拡張機能
      "ms-azuretools.vscode-containers",
      "docker.docker",
      "eamodio.gitlens",
      "donjayamanne.githistory",
      "mhutchie.git-graph"
    ]
  }
}

Gradle プロジェクトの VS Code の画面

用意したワークスペースファイルを使って VS Code を開くと次のような画面となります。

/images/20250919_vscode_java_03/01.png
Gradle プロジェクトの VS Code の画面

エクスプローラービュー(左側):

ファイルエクスプローラーには、おなじみのファイルツリーが表示されます。ただし、java-app002.code-workspace で非表示に指定したフォルダは見えません。VS Code での開発作業に必要なファイルだけ表示されるので、作業に集中しやすくなります。

JAVA PROJECTS ビュー(左側、下部):

サイドバーには、「JAVA PROJECTS」という専用のビューも表示されます。ここでは、プロジェクトが Java プロジェクトとして正しく認識され、ソースコード、ライブラリ(依存関係)、ビルドファイルが階層的に整理して表示されます。これにより、プロジェクトの全体像を把握しやすくなります。

Gradle ビュー(左側):

サイドバーには、Gradle ビューを表示することもできます。このビューでは認識された Gradle プロジェクトの一覧が表示されます。

/images/20250919_vscode_java_03/02.png
Gradle の画面

app を展開すると、TasksDependencies といった項目が表示されます。Tasks にはタスクについての情報、Dependencies には依存するライブラリの情報が含まれています。

Tasks に含まれるタスクを開くと、実行可能なタスクの一覧が表示されます。タスク名の右側にある再生ボタン ▶️ をクリックするだけで、ターミナルを開かずにタスクを実行できるため、非常に便利です。たとえば、Java プログラムの実行やテスト実行などができます。

Dependencies に含まれるライブラリを開くと、そのライブラリが依存しているものが辿れます。深い依存関係まで確認することができます。

エディタと統合ターミナル(中央):

中央のメインエリアは、ソースコードや build.gradle ファイルを編集するためのエディタです。Java や Gradle の拡張機能により、シンタックスハイライト、コード補完、エラーチェックなどが強力にサポートされます。

また、Ctrl+@(Windows/Linux)または Cmd+@(Mac)で開く統合ターミナルは、開発コンテナのシェルに直接接続されています。そのため、./gradlew build のようなコマンドを直接実行し、ビルドやテストを行うことも可能です。

ステータスバー(左下):

ウィンドウのステータスバーの左隅は、「開発コンテナー: dvc-java-gemini」のように表示され、現在開発コンテナ内で作業していることが一目でわかります。

このように、VS Code はコンテナ技術を意識させない透過的な UI を提供し、開発者は本来のコーディング作業に集中することができます。

開発コンテナの終了

開発作業が終了したら、開発コンテナを終了します。

今回使用した開発コンテナは WSL Ubuntu の Docker で起動しています。VS Code を終了させてから、WSL Ubuntu のコンソールを使って終了します。

docker compose ls コマンドで Docker Compose プロジェクトの一覧が表示されます。ここで、名前が dvc-java-gemini となっているものが、今回使用した開発コンテナ用のプロジェクトになります。実行例は次のようになります。

$ docker compose ls
NAME                STATUS              CONFIG FILES
dvc-java-gemini     running(1)          (略)

docker compose コマンドでは、操作対象の Docker Compose プロジェクト名をオプション -p で指定できます。そのため、ここでは -p dvc-java-gemini を指定すれば良いということにあります。

開発コンテナを停止するには、docker compose stop コマンドを使います。実行例は次のようになります。

$ docker compose -p dvc-java-gemini stop
[+] Stopping 1/1
 ✔ Container dvc-java-gemini-dvc-java-gemini-1  Stopped (略)

開発を再開する場合は、VS Code から「コンテナーで再度開く」を実行します。もし、停止したものが使われず、新しい開発コンテナが起動してしまう場合は、この後説明する方法で開発コンテナを終了してください。

開発コンテナを終了したい場合は docker compose down コマンドを実行します。実行例は次のようになります。

$ docker compose -p dvc-java-gemini down
[+] Running 2/2
 ✔ Container dvc-java-gemini-dvc-java-gemini-1  Removed (略)
 ✔ Network dvc-java-gemini_default              Removed (略)

まとめ

本記事では、Gemini CLI との対話を通じて、旧来のシェルスクリプトで管理されていた Java プロジェクトを近代化するプロセスを解説しました。

行った改善は、大きく分けて次の 2 点です。

  1. Dev Container への Gemini CLI 統合
  2. Gradle への移行

Dev Container への Gemini CLI 統合については、開発環境をコンテナ化し、どこでも同じ AI 支援開発体験を再現できるようにしました。これにより、プロジェクトのポータビリティ (可搬性) と再現性が大幅に向上しました。

Gradle への移行については、手動でのライブラリ管理や自作ビルドスクリプトを廃止し、モダンで堅牢なビルドシステムを導入しました。これにより、依存関係の解決やビルド、テストといった定型作業が自動化され、プロジェクトのメンテナンス性が劇的に改善されました。

Dockerfile の作成、build.gradle のような構成ファイルの編集、そしてプロジェクト構造の変更といった、とかく面倒で間違いやすい作業も、AI と対話しながら進めることで、驚くほどスムーズかつ正確に完遂できました。

この記事が示すように、AI は単なるコード生成器にとどまりません。開発プロセス全体を支援し、プロジェクトの品質と生産性を向上させる強力なパートナーとなり得るのです。

Discussion