更新日:2026年7月23日
28分で読めます
このチュートリアルでは、的を絞ったテスト修正から始めて品質ゲートを整備し、開発ライフサイクルのコンテキスト、テスト結果、レビューのエビデンスを踏まえながらコードを変更していく流れを解説します。

「Java 8をJava 21にモダナイズする」と言うと、単一のタスクのように聞こえます。しかし実際はそうではありません。ビルド、ランタイム、依存関係、API、並行処理、テスト、コンテナ、本番環境での挙動など、複数の要素が同時に絡み合う作業です。これらすべてを1つのプロンプトでエージェントに任せてしまうと、誰も安全にレビューできないほど巨大なマージリクエストができあがってしまいます。
AIコーディングエージェントであるCursorは、こうした問題のうち焦点を絞った部分を得意としています。失敗しているテストや範囲が限定されたイシューを1つ渡せば、実装を調査し、何が問題だったのかを説明し、修正案を提示し、開発フローから離れることなくテストを実行できます。しかし、複数ステップにわたる移行全体で「安全」が何を意味するかは、Cursorが単独で判断できるものではありません。
ここで登場するのがGitLabです。Duo Agent Platformがソフトウェアライフサイクルの残りの部分でAIワークフローをオーケストレーションし、コーディングエージェントの作業を検証できるよう設計されています。エピックによるイシューの階層構造により、計画は永続的でレビュー可能なものになります。GitLab Model Context Protocol(MCP)サーバーは、こうしたソフトウェア開発ライフサイクルのコンテキストをCursorに取り込みます。CI/CD、セキュリティスキャン、コードレビュー、影響分析、そしてサービス横断的なテストが、本番環境での挙動を変更する前に必要となるエビデンスを提供します。
このチュートリアルでは、CursorとGitLabを使った3つのユースケースを解説します。
この進め方には意味があります。まず小さく始め、プロジェクトのコンテキストを加え、そのうえで1つの境界をモダナイズする。Cursorはその境界の中で高速に動きます。そのスピードを安全に保っているのが、Code Review Flow、Developer Flow、CI/CD、コードオーナーの承認、そして影響分析です。これらは省略可能なチェックポイントではなく、エージェントが作成したすべてのマージリクエストを他と同じ基準に保つための仕組みです。
3つのユースケースすべてで、Tanuki IoT PlatformのJava HTTPメトリクスコレクターを使用します。このコレクターはHTTPエンドポイントをチェックし、レスポンスステータスや応答時間などのメトリクスを記録して、Rustメトリクスバックエンドに読み取り値を送信します。これにより、モダナイズ対象となる目に見えるアプリケーション境界と、検証すべき実際のバックエンド契約が得られます。以前、Codex and GitLabのチュートリアルでこのRustバックエンドを構築しており、現在は本番アーキテクチャの一部として機能しています。
flowchart LR
subgraph sources["HTTP metric sources"]
direction TB
health["Health endpoint"]
maintenance["Maintenance endpoint"]
end
java["Java HTTP metrics collector"]
rust[("Rust metrics-store backend")]
java -->|"GET"| health
java -->|"GET"| maintenance
java -->|"POST /api/metrics"| rust
rust -->|"HTTP response"| java
classDef source fill:#f8fafc,stroke:#64748b,stroke-width:2px,color:#0f172a
classDef focus fill:#dcfce7,stroke:#16a34a,stroke-width:3px,color:#0f172a
classDef backend fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0f172a
class health,maintenance source
class java focus
class rust backend
自分の環境でこのワークフローを再現したい場合は、まずプロジェクトをインポート・クローンし、Cursorでプロジェクトを開くところから始めます。
git clone https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector.git
cd java-http-metrics-collector
cursor .
このプロジェクトには、リポジトリの指示とMavenコマンドが記載されたAGENTS.mdファイルが含まれています。Cursorはこのローカルの指示を利用して、プロジェクトの構成や変更のテスト方法を理解できます。

このコレクターでは、エンドポイントから期待するHTTPステータスコードをユーザーが設定できます。しかし実装上は、すべての2xxレスポンスを成功として扱ってしまい、503エラーは期待どおりに設定されていても常に失敗として扱われていました。
エンドツーエンドテストはすでにこの不整合を検出していますが、CI/CDジョブは失敗が許容される設定になっています。そのため、本来役立つはずのシグナルが、当たり前に受け入れられる背景ノイズになってしまっていました。

この問題はローカル環境で再現できます。Cursor IDEで新しいチャットを開き、まずはプロンプトで観測された問題を直接説明することから始めます。
Can you help me fix the end-to-end tests in this project? Please create an analysis first, then fix it, and run the tests again.
Cursorはまず、エンドポイントの設定をHttpCollectorと失敗しているエンドツーエンドテストまで遡って調査し、根本原因を特定します。

対象のテストとMavenのテストスイート全体が通過したら、ブランチとマージリクエストを作成します。これまで失敗が許容されていたエンドツーエンドジョブは、決定的に成功する状態になれば、必須ジョブに変更できます。
Can you create a git branch and merge request?
マージリクエストを作成すると、CI/CDのビルドとテスト、セキュリティスキャンが自動的にトリガーされます。

続いて、GitLab Duo Code Reviewが、プロジェクト固有のJavaレビュー指示に基づいて、対象の変更をレビューします。

レビューで具体的な問題が指摘された場合は、マージする前にDeveloper Flowを通じて対応します。ここが重要なポイントです。Code Review Flowは、Cursorがどれだけ速く生成したものであっても、エージェントが作成したすべてのマージリクエストが他と同じ基準を満たすことを保証します。マージリクエストは、あくまでコラボレーションと意思決定の場であり続けます。

この修正により、動作面のベースラインが得られます。ランタイムの移行と混在させることなく、実際のバグを修正できたことで、テストは今後のモダナイズ作業を通じて期待ステータスの契約を守ってくれます。
Cursorが期待どおりのエンドツーエンドテストをどのように調査・修正するかは、以下の動画で確認できます。
最初の修正は、リポジトリのコンテキストだけで完結しました。次のリクエストははるかに大規模です。コレクターをJava 8からJava 21へモダナイズすることです。
この作業については、すでにJavaモダナイズのエピックに計画のコンテキストがそろっています。子の作業アイテム、チームでの議論、マージリクエストを伴う調査、パイプラインの履歴、依存関係、セキュリティの検出結果などです。これらの詳細はローカルのチェックアウトには存在しません。そのすべてを1つの巨大なプロンプトにコピーするのではなく、MCPを使ってGitLabのコンテキストをCursorに取り込むことができます。
GitLab MCPサーバーが、自分のインスタンスまたはトップレベルグループで有効化されていることを確認してください。Cursorは、追加の依存関係なしに直接接続できるHTTPトランスポートを使用します。
CursorをGitLab MCPサーバーに接続するには、以下の手順に従います。
mcp.jsonファイルのmcpServersキーに、以下の定義を追加します。GitLab.comの場合は<gitlab.example.com>をgitlab.comに置き換えてください。GitLab Self-ManagedまたはDedicatedの場合は、自分のGitLabインスタンスのURLを使用してください。 {
"mcpServers": {
"GitLab": {
"type": "http",
"url": "https://<gitlab.example.com>/api/v4/mcp"
}
}
}

これで新しいチャットを開始し、利用可能なGitLab MCPツールに基づいて質問できるようになります。
CursorがGitLab MCPで認証すると、既存のGitLabアイデンティティとして動作します。アクセスできるのは、自分がすでにアクセス権を持つプロジェクトやリソースに限られます。MCPは承認済みのコンテキストをIDEに取り込むものであり、GitLabの権限をバイパスするものではありません。
Java 8から21へのモダナイズのエピックでは、必要な計画がより小さなイテレーションに分割されており、各成果物と変更がそれぞれ単独でテスト可能になっています。

最初のステップは、CI/CDインフラでJava 8と21の両方を並行してテストできるようにすることです。各モダナイズタスクの開始時点からテストカバレッジを高めていくことも必須です。
Cursor IDEを開き、以下のプロンプトを使って計画のコンテキストを取得します。
Please help me modernize this sensor from Java 8 to 21. We want to start with the base line for CI/CD builds in work item 14, and then also look into test coverage from 21. Start the implementation in a new Git branch called `maint-java-21` so we can continue testing different scenarios.
CIビルドの可視化に関するイシューの作業が完了したら、Cursorはcreate_workitem_noteのMCPツールを使って、イシューに要約コメントを追加することもできます。

新しいマージリクエストは、CI/CDパイプラインとCode Review Flowの両方をトリガーします。Code Review Flowは、開発スタイルガイドが要求するドキュメント化についてコメントを残します。

Developer Flowのサービスアカウントにメンションすることで、GitLabのUI上でフィードバックにすぐ対応できます。
@duo-developer-<group-name> Can you help address the review feedback?
このプロンプトによって新しいバックグラウンドセッションが開始されるため、その間は他のタスクに集中できます。あるいは、Cursor IDEに戻り、チャットでマージリクエストのレビューフィードバックに対応するよう指示することもできます。

Cursorは変更を実装し、create_merge_request_noteのMCPツールを使って、マージリクエストのスレッドにコメントを追加します。

この変更では、一時的なJava 8のベースラインを維持しつつ、Java 21向けの独立したビルドとテスト検証を追加します。これにより、ソースコードがJava 21専用のAPIを使い始める前の段階で、互換性がパイプライン上で可視化されます。こうした品質ゲートが整えば、以降のエージェント主導のすべての変更は、レビューされ、テストされ、追跡可能になります。これは他のマージリクエストと同じ基準であり、だからこそCursorを安心して高速に動かせるのです。
CursorがGitLab MCPを使って品質ゲートを準備し、コードレビューのフィードバックに対応する様子は、以下の動画で確認できます。
Java HTTPメトリクスコレクターは現在、Java 8の従来型APIHttpURLConnectionを使用しています。Java 21ではHTTPライブラリがjava.net.http.HttpClientにモダナイズされましたが、これは単なる機械的なリネームではありません。リダイレクト、制限付きヘッダー、タイムアウトの範囲、レスポンスボディ、割り込み、接続の再利用など、挙動が異なりうる要素は多岐にわたります。だからこそ、この実装は1つの範囲が限定された作業アイテム、Replace HttpURLConnection with java.net.http.HttpClientに閉じています。実際にやってみましょう。
Cursor IDEで新しいチャットを開き、変更の実装を依頼します。
注: このユースケースでは、変更の検証にローカルのDocker Compose環境を使用します。この挙動を再現したい場合はDockerとDocker Composeをインストールしてください。不要な場合は2つ目のプロンプトを省略してください。
We want to continue modernizing the app to Java 21 - use the same maint-java-21 branch, and start implementing issue 16.
Verify the changes locally using the docker compose setup, after making the changes.
GitLab MCPサーバーは、イシューのコンテキスト、受け入れ基準、依存関係、関連する議論を提供します。最初のコードモダナイズのイシューは、意図的に同期的かつ限定的な範囲にとどめています。HttpURLConnectionを、再利用可能な1つのHttpClientに置き換えるだけで、仮想スレッドの追加や時間モデルの変更、関連のない依存関係の修正は行いません。これらは価値のあるフォローアップですが、一緒に行ってしまうと、挙動の変更を切り分けてレビューし、ロールバックすることが難しくなります。
対象を絞ったローカルのHTTPサーバーテストでは、メソッド、ヘッダー、期待されるステータスコードと想定外のステータスコード、リダイレクト、タイムアウト、レスポンスのメタデータ、接続の失敗、割り込みをカバーします。

続いてDocker Composeの機能テストにより、認証済みの読み取り値がrust-metrics-storeバックエンドに引き続き到達することを確認します。

変更後にCI/CDパイプラインが失敗している場合は、GitLab MCPサーバーのツールを活用し、コンテキストを切り替えることなくCursor IDE上で直接調査・修正できます。

GitLabのUIでは、Fix CI/CD Pipeline Flowを使用するか、CI Expertエージェントに助けを求めることができます。
GitLab CI/CD、GitLab Duo Code Review、セキュリティスキャン、そしてAIによる影響分析が、マージリクエストにおける最終的なエビデンスとなります。それでも、微妙な境界においては人によるレビューが最も重要です。意図的な挙動の違いは、デプロイ後に発覚するのではなく、マージリクエストの時点で明示されているべきです。

CursorとGitLabがコレクターのHTTPライブラリをJava 21にどのようにモダナイズするかは、以下の動画で確認できます。
CursorとGitLabを組み合わせて使うためのヒントを紹介します。
3つ目のユースケースでは、Developer Flowが破壊的変更の影響分析を行う様子を紹介しました。このワークフローは、マージリクエストの準備が整ったとき、あるいはパイプラインが正常なときにトリガーされる自動化されたカスタムフローに変えることができます。追加のコンテキストは、コード、作業アイテム、マージリクエスト、脆弱性などを横断するコンテキストグラフを提供するGitLab Orbitから取得できます。
サンプルのフローは、AI CatalogのMR Impact analysis (Orbit)から確認できます。着想をくれたチームメイトのFatima Sarah Kalidに感謝します。カスタムフローはGitLab 19.2で一般提供されています。


AGENTS.mdファイルは、プロジェクトのアーキテクチャ、コマンド、コードスタイル、テストに関する期待、境界をCursorや他のコーディングエージェントが理解する助けとなります。こうした指示はコードのそばに置き、検証できる程度に具体的にしておきましょう。
Java HTTPメトリクスコレクタープロジェクトのAGENTS.mdからの例です。
# Java HTTP Metrics Collector - Agent Instructions
## Overview
The Java HTTP Metrics Collector is a REST API metrics collection sensor for the Tanuki IoT Platform. It monitors HTTP endpoints, collects performance metrics (response time, status codes, content length), and exports them in Prometheus text format. The application runs continuously with configurable collection intervals and supports concurrent endpoint monitoring.
## Code Style and Standards
### Java 8 Compatibility
- Do not modernize Java 8 code to Java 11+ features unless there is a GitLab issue or task specifically requesting modernization
- Target Java 8 for source and compilation: `maven.compiler.source=1.8` and `maven.compiler.target=1.8`
- Use Java 8 compatible patterns (e.g., anonymous inner classes instead of lambdas where appropriate)
### Documentation
- All public classes must have Javadoc describing purpose and usage
- All public methods must have Javadoc with `@param` and `@return` tags
- Include code examples in main class Javadoc
### Class Organization
- **Main entry point**: `HttpMetricsCollector` - orchestrates configuration loading, metric collection, and export
- **Collector**: `HttpCollector` - performs HTTP requests and collects metrics
- **Exporter**: `PrometheusExporter` - exports metrics in Prometheus text format
- **Models**: `CollectorConfig`, `EndpointConfig`, `HttpMetric` - data transfer objects
### Dependency Management
- Always use Maven for dependency management
- Use property-based version management for dependencies (e.g., `${jackson.version}`)
- Keep dependencies up-to-date in `pom.xml`
### Error Handling
- Use try-catch blocks with proper resource management (try-with-resources where applicable)
- Log errors using SLF4J Logger
- Gracefully handle configuration loading failures
- Implement proper shutdown hooks for resource cleanup
### Concurrency
- Use `ExecutorService` for concurrent HTTP requests
- Thread pool size is limited to the minimum of endpoint count and 10
- Properly shutdown executor service with timeout handling
- Use `Future` objects to collect results from concurrent tasks
GitLab Duo Code Review Flowは、スタイルガイドと境界を維持する助けとなります。そのためには、.gitlab/duo/mr-review-instructions.yamlファイルに具体的な指示が必要です。例えばJava向けは次のとおりです。
# Custom instructions for GitLab Duo Code Review
instructions:
# General guidelines
- name: Code Review
instructions: |
1. Focus on correctness and performance
2. Ensure code comments and documentation are clear and concise
3. Be respectful and constructive in comments
- name: CI/CD Configuration
fileFilters:
- ".gitlab-ci.yml"
instructions: |
1. Do not use YAML anchors
2. Always use rules in jobs, avoid using `only`
# Java style guide
- name: Java Style Guide
fileFilters:
- "**/*.java"
instructions: |
1. Do not modernize Java 8 code to Java 11+ features, unless there is a GitLab issue or task specifically requesting modernization
2. All public classes must have Javadoc describing purpose and usage
3. All public methods must have Javadoc with @param and @return tags
4. Include code examples in main class Javadoc
5. All public methods must have at least one test case
6. Use httpbun.com for test endpoints (status codes, delays, JSON responses)
コードのモダナイズを進める過程で、Java 8の強制に関する最初のガイドラインは更新が必要になります。
専門的なワークフローが繰り返し使えるようになったら、それをエージェントスキルとして記録します。スキルはオンデマンドで読み込まれ、デフォルトではコンテキストウィンドウを占有しません。
エージェントスキルが、未検証の計画ではなく実証済みの実践を反映したものになるよう、まずは動作するCI/CD、テスト、レビュー済みの意思決定から始めましょう。モダナイズのエピックにおけるイシュー24は、このアプローチを、範囲を絞ったJava 21以降向けのモダナイズ用エージェントスキルとしてまとめています。これは、現在のマージリクエストを超えた価値をもたらします。今後のエージェントセッションは、過去の議論から再構築するのではなく、同じ安全境界を再利用できるのです。
既存のJava 8 Maven保守スキルに着想を得た、以下のサンプルスキル実装を試してみてください。
---
name: java21-modernization
description: >-
Guide incremental Java 8 to Java 21+ modernization for the HTTP metrics
collector. Use when a GitLab work item asks for Java 21 CI visibility,
runtime/image upgrades, HttpClient migration, dependency or source API
modernization, or review of maint-java-21 style merge requests. Do not use
for routine Java 8 maintenance; prefer java8-maven-maintenance instead.
compatibility: Requires Maven, Docker Compose, and access to the owning GitLab work item.
---
# Java 21 Modernization
## Overview
Modernize in small, reviewable steps. The owning work item is authoritative.
Preserve collector → Rust metrics-store behavior unless the issue says otherwise.
Companion skill: `skills/java8-maven-maintenance/` for the Java 8 default path.
## Before editing
1. Read the owning issue/epic, `AGENTS.md`, `.gitlab-ci.yml`, `pom.xml`,
`Dockerfile`, and affected tests.
2. Record the current baseline:
- `maven.compiler.source` / `target`
- default CI image vs any `*:java-21` jobs
- container base image
- observable CLI/Compose behavior
3. Classify the change into **one** lane:
- CI visibility only
- runtime / image switch
- source / API modernization
- dependency upgrade
- tests / contract checks
Do not combine lanes in one MR unless the work item explicitly requires it.
## Workflow
Copy and track:
```text
Modernization progress:
- [ ] Baseline recorded
- [ ] Scoped to owning work item
- [ ] Target-JDK CI evidence available before JDK-only APIs
- [ ] Java 8 lane preserved until exit criteria say otherwise
- [ ] Unit / IT / Compose checks run
- [ ] MR documents risks, rollback, human decisions
```
## Guardrails
- Do not remove Java 8 compatibility unless the work item authorizes it.
- Do not introduce Java 21-only APIs before target-JDK CI evidence exists.
- Do not mix runtime upgrades with unrelated refactors.
- Do not claim performance wins without measurements.
- Preserve the Java → Rust API and authentication contract.
- Stop for a human decision when support policy, rollback, data format, or downstream compatibility is unclear.
## Validation
```bash
mvn -Dmaven.repo.local=.m2/repository test
mvn -Dmaven.repo.local=.m2/repository clean package
```
If Compose or container files change:
```bash
docker compose config --quiet
TANUKI_INGESTION_TOKEN=replace-me docker compose up -d --build
# confirm metric_sample logs and authenticated ingest still work
docker compose down -v
```
## Completion report
In the MR description, include:
1. Baseline before the change
2. Lane changed (CI / runtime / source / deps / tests)
3. Evidence run (commands + CI jobs)
4. Remaining risks and rollback
5. Human decisions still open
## Out of scope
- Broad "modernize everything to Java 21" prompts
- HTTP endpoint semantics unrelated to the JDK migration
(use `skills/http-endpoint-collector-behavior/`)
- Security triage unrelated to the migration slice
(use `skills/security-triage-java-sensor/`)
このチュートリアルで紹介した3つのユースケースは、それぞれが積み重なっています。まずCursorは、リポジトリのコンテキストだけを使って、受け入れられていたエンドツーエンドテストの失敗を修正しました。次にGitLab MCPサーバーがモダナイズ計画を取り込み、Cursorは品質ゲートを整備しつつ、IDEから直接Duoのレビューフィードバックへの対応を完結させることができました。そして最後に、CursorはHttpURLConnectionを再利用可能なHttpClientに置き換えるという、1つの範囲が限定されたJava 21の変更を行い、対象を絞ったテスト、サービス横断的な取り込みの実行、パイプライン、セキュリティスキャン、ソフトウェア部品表、レビューのエビデンス、影響分析によって裏付けました。
レガシーなJava 8のコードベースは、エージェントがコードを書いているからといって、モダナイズが安全になるわけではありません。安全になるのは、すべての変更が範囲を限定され、レビューされ、Java 8とJava 21の両方に対してテストされ、その背後にある意思決定とエビデンスとともに作業アイテムまで追跡できるからです。実装を担うのはCursorです。そして、その証明を担うのがGitLabです。両者が組み合わさることで、この移行はチームが信頼できるものになります。
このワークフローを試してみたい場合は、レガシーなアプリケーションで受け入れられている失敗を明らかにする1つのテストから始めてください。そのテストを信頼できるものにし、より大きなモダナイズ計画をGitLabに記録し、独立して変更・証明できる1つの境界を選びます。そうすることで、エージェントには焦点を絞ったタスクが、チームにはレビューできるエビデンスが与えられます。
もしまだGitLab Duo Agent Platformを利用していない場合は、無料トライアルから始められます。
すでに無料プランでGitLabを利用している場合は、簡単な手順に沿って、GitLab Duo Agent Platformに申し込めます。
そして、すでにGitLab PremiumまたはUltimateをご利用中の場合は、Duo Agent Platformを有効化するだけで、サブスクリプションに含まれているGitLabクレジットを使い始められます。
このブログ記事を楽しんでいただけましたか?ご質問やフィードバックがあればお知らせください。GitLabコミュニティフォーラムで新しいトピックを作成してあなたの声を届けましょう。
フィードバックを共有する