はじめに
Amazon Q Developerには.NETやJavaのコードをアップグレードする機能があります。
docs.aws.amazon.com
Javaにおいては、Javaのバージョンアップのほか、ライブラリやフレームワークのバージョンアップにも対応しています。全量は以下の公式ページに掲載があります。
docs.aws.amazon.com
対応しているライブラリやフレームワークを眺めているとSpring BootやSpring Framework、Spring Securityだけでなく、junitやMockitoなどテスト関係のライブラリが含まれています。そこで今回は、Spring BootとSpring Securityを使った簡単なWebアプリを対象に実際に動かしてみました。
変換元アプリ
わかりやすいようにSpring Bootのバージョンは2.7.18としました。このバージョンにした理由は、このバージョンに関連するSpring Securityに対して大きな変更が加わっているからです。詳細は以下のブログを参照してください。
spring.io
実装コードは以下の通り。すでに廃止されたWebSecurityConfigurerAdapterを使ったものとしています。
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
 認証設定 - インメモリでユーザーを定義
     
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user")
            .password(passwordEncoder().encode("password"))
            .roles("USER")
            .and()
            .withUser("admin")
            .password(passwordEncoder().encode("admin"))
            .roles("USER", "ADMIN");
    }
    
 認可設定 - Spring Security 5.3の古い方式
     
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            
            .authorizeRequests()
                .antMatchers("/", "/login", "/css/**", "/js/**").permitAll()
                .antMatchers("/h2-console/**").permitAll() 
                .anyRequest().authenticated()
                .and()
            
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/todos", true)
                .permitAll()
                .and()
            
            .logout()
                .logoutSuccessUrl("/login?logout")
                .permitAll()
                .and()
            
            .csrf().ignoringAntMatchers("/h2-console/**")
                .and()
            .headers().frameOptions().sameOrigin();
    }
}
ちなみにプロジェクトをVisual Studio Codeで開くと、多くの警告メッセージが出ます。

プロジェクト全体のコード行数は以下となります(clocを使って計測)。
github.com/AlDanial/cloc v 2.06  T=0.04 s (1004.0 files/s, 114786.4 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
HTML                             8            170              2           1667
Java                             9            111             94            454
Bourne Shell                     2             60            170            316
DOS Batch                        2             45              2            236
CSS                              2             51              0            207
JavaScript                       1             48              2            168
XML                              3              4              0            126
Maven                            1             10              5             84
Gradle                           2              5              0             32
Markdown                         1              7              0             23
Properties                       4              0              1             12
JSON                             1              0              0              4
-------------------------------------------------------------------------------
SUM:                            36            511            276           3329
-------------------------------------------------------------------------------
前提
Amazon Q Developerの変換機能にはいくつか前提があります。全量は以下の公式ページを参照してください。
docs.aws.amazon.com
主だったところは、以下かなと思います。
- Javaのバージョンは8以上
- Mavenでビルドできること(pom.xmlが存在していること)
- Gradleはダメです。実際にやってみると、セットアップ時に怒られます。
 

build.gradleからpom.xmlへの変換はAmazon Q Developerに依頼すると変換してくれるので、あまり障壁ではないですがちょっと面倒です。
なお、必須条件ではないですがJUnitなどでテストコードは書いておいた方が良いです。書いていない場合はAmazon Q Developerで書いてもらうことで対応できるかなと思います。Amazon Q Developerには/testで単体テストを作らせる機能があるので、それを利用するのがお手軽かなと思います。
docs.aws.amazon.com
私の場合、generate integration tests for this app.とプロンプトを書いてテストコードを生成させ、作成されたテストコードを手作業で修正する形をとりました。

単体テストはこのようなバージョンアップに対しては壊れやすい気がしたのでintegration testsとしたのがその理由ですが、あまり明確な根拠はないです。
変換
変換はAmazon Q Developerに/transformと入力してenter/returnを押せばOKです。

あとは画面の指示に従います。Javaのバージョンなどを指定します。

すべての設定が完了すると、transformation-plan.mdが作られ、変換が実行されます。

Lines of code in your applicationとして437と算出されました。この行数がどのように算出されたのかがよく分からず。clocで計算したJavaコードの行数は454行、wcコマンドで算出したJavaコードの行数はは662行となり、いずれも一致せず。
変換は約30分かかりました。ソースコードが変更されながら何度もビルドが実行されます。

画面上では確認できませんでしたが、のちほどログ(summary/buildCommandOutput.log)を見るとテストコードを実行するオプションを選択した場合、テストコードの実行も何度も行われます。おそらくですが、ビルドの成功やテストコードの成功が変換処理の正しさを判断する材料としているように見受けられます。このため、変換処理の正しさをAmazon Q Developerに判断させるためにもテストコードは用意した方が良いかと考えます。
最後にsummary/summary.mdが生成され、コード変換の結果がまとめられます。

変換結果詳細
変換結果を詳しくみていきます。
まず、Spring Bootは2.7.18から3.3.4になりました。2025年10月5日時点、Spring Bootの最新バージョンは3.5.6で、3.3.xはOSSのサポート終了となっています。
spring.io
Spring Bootのリリースサイクルが早いとはいえ、これはもうひと頑張りして3.4.xまで上げて欲しかったと思います。
Spring Securityを使っている部分は以下の通り概ねうまく変換できている形です。
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
 認証設定 - インメモリでユーザーを定義
     
    @Bean
    InMemoryUserDetailsManager inMemoryAuthManager() {
        var user = User.builder()
            .username("user")
            .password(passwordEncoder().encode("password"))
            .roles("USER")
            .build();
            
        var admin = User.builder()
            .username("admin")
            .password(passwordEncoder().encode("admin"))
            .roles("USER", "ADMIN")
            .build();
            
        return new InMemoryUserDetailsManager(user, admin);
    }
    
 認可設定 - Spring Security 5.3の古い方式
     
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            
            .authorizeHttpRequests(requests -> requests
                .requestMatchers("/", "/login", "/css/**", "/js/**").permitAll()
                .requestMatchers("/h2-console/**").permitAll() 
                .anyRequest().authenticated())
            
            .formLogin(login -> login
                .loginPage("/login")
                .defaultSuccessUrl("/todos", true)
                .permitAll())
            
            .logout(logout -> logout
                .logoutSuccessUrl("/login?logout")
                .permitAll())
            
            .csrf(csrf -> csrf.ignoringRequestMatchers("/h2-console/**"))
            .headers(headers -> headers.frameOptions(options -> options.sameOrigin()));
        return http.build();
    }
}
一部コメントに古い記述が残っていたりしていますが、テストも通りますし人がここらへんを調べながら実装するのは(Amazon Qの変換時間である)30分ではできないものなので、、良い結果なのではと思います。
その他、Spring Boot 3.0へのバージョンアップとしての変更点の一つであるパッケージ名の変更javax.*からjakarta.*への変更も行われていました。
その他細かい変更点は、GitHub上にあげているソースコードの差分を確認してください。
github.com
結果と考察
Amazon Q DeveloperのJavaアップグレード機能を使って古いSpring Bootアプリのバージョンアップをやってみました。概ね、良い変換結果となりました。私がよいと思ったのは以下の点です。
- 概ね正しい変換が行われた
- transformation-plan.mdや- summary.mdが生成され、何が行われたのか後で振り返れるようになっている- 
- 特にsummary.mdの存在は貴重で、このようなドキュメントは往々にして作成が求められるので、自動生成されるのは大変ありがたいです。
 
一方で、以下の点が気になりました。
- Mavenしか対応していない
- せめてGradleにも対応してほしいです。
- ローカルにmvnコマンドが必須のようです。Maven wrapperだけで運用していた場合は、環境構築が若干手間取るかもしれません
 
- より新しいSpring Bootのバージョンにアップグレードしてほしい
- 上でも記しましたが、すでにOSSサポート終了版にアップグレードされるのはもう少しなんとかならないかという思いがあります。
 
- Quotaが低い/Pro版の料金に含まれる行数が低い
- 今回は非常に単純なTodoアプリを対象としましたが、アプリの対象行数は437行と表示されました。
- Free版の場合、ジョブあたり1,000行、1ヶ月で2,000行が上限なので、ちょっと複雑なコードを書いていたらすぐFree版のQuotaに引っ掛かります。
- Free版はお試し版ということを理解しても、もう一声欲しいところです。
- ちなみに、Amazon Q Developer User GuideのQuotaの記述と料金ページの記述に若干数値の違いがある点は気になりました(User Guideでは2,000行/月が上限とあるが、料金ページは1,000行/月であるように読めました。)
 
- Pro版は4,000行を超えたものは1行あたり0.03ドルの課金とあります。これが思いの外高いと感じます。
 
- 変換にかかる時間が長い
- 今回のように非常に単純なTodoアプリでも約30分変換に時間がかかりました。
- 実行してしまえば、あとは放置して良いのであまり気にしなくても良いかもしれませんが、30分ぐらいはかかることは認識しておいた方がよさそうです。
 
今回は単純なTodoアプリ+JPAという構成のSpring Bootアプリケーション対して実行しましたが、User GuideをよむとConverting embedded SQLという機能があります。
docs.aws.amazon.com
JPAを使っている以上、SQLが表に出てくることはあまりないのですが、こちらも時を見て試してみたいです。