VisitProposalを用いたルート決定ハンドラへの情報拡充

hotwired/hotwire-native-android

このPRは、ルート判定ハンドラが受け取る情報を VisitProposal に拡張し、location だけでなく訪問オプションやパス設定、バンドルまで利用できるようにした点が中心です。これにより、カスタムハンドラはより包括的な判断が可能になります。

背景

既存の RouteDecisionHandlerlocation 文字列のみを受け取り、ルーティングロジックの自由度が制限されていました。 例えば、訪問オプションやパス設定プロパティを考慮したいケースで、ハンドラは追加情報を取得できず、アプリ側で余計な処理を挟む必要がありました。この制約は、カスタムハンドラ実装や customRouteDecision のオーバーライドで顕在化していました。結果として、統一的な拡張ポイントが欠如し、コードの重複や保守コストが増大していました。

そこで、訪問に関わる全情報をひとまとめにしたデータクラスを導入し、ハンドラへ渡す方針が取られました。 この方針は、既存の location 文字列は proposal.location として引き続き参照可能にしつつ、将来的な拡張を見据えた設計です。実装側では API 変更に伴う破壊的変更が発生しますが、明示的なシグネチャ変更により移行が容易になるよう整理されています。

技術的な変更

VisitProposal データクラスが新規追加され、locationoptionspropertiesbundle を保持します。

package dev.hotwire.core.turbo.visit

import android.os.Bundle
import dev.hotwire.core.turbo.config.PathConfigurationProperties

data class VisitProposal(
    val location: String,
    val options: VisitOptions,
    val properties: PathConfigurationProperties,
    val bundle: Bundle?
)

このクラスは訪問に必要な全情報を一元化し、ハンドラの引数として提供されます。

複数のシグネチャが VisitProposal に置き換えられました。 HotwireDestination.customRouteDecisionRouter.RouteDecisionHandler.matches/handleNavigator.getRouteDecision などがすべて proposal: VisitProposal を受け取る形に変更され、旧来の location: String は削除されています。たとえば Router のインターフェースは次のように更新されています。

interface RouteDecisionHandler {
    fun matches(proposal: VisitProposal, configuration: NavigatorConfiguration): Boolean
    fun handle(proposal: VisitProposal, configuration: NavigatorConfiguration, activity: HotwireActivity): Decision
}

この変更により、ハンドラは提案全体を元に判定・処理を行えるようになります。

Navigator の内部ロジックが VisitProposal の生成と伝搬に合わせて改修されました。 ルート決定前に VisitProposal インスタンスを組み立て、currentDestination?.customRouteDecision(proposal) へ渡すことで、既存のカスタムロジックが新データに適応します。

private fun getRouteDecision(
    location: String,
    options: VisitOptions,
    bundle: Bundle?
): Router.Decision {
    val proposal = VisitProposal(
        location = location,
        options = options,
        properties = Hotwire.config.pathConfiguration.properties(location),
        bundle = bundle
    )
    val customDecision = currentDestination?.customRouteDecision(proposal)
    // ...
}

この流れは全ハンドラ実装に統一的に適用されます。

RouteDecisionHandler 実装が proposal を使用するよう修正されました。 例えば AppNavigationRouteDecisionHandlerproposal.location を基にドメイン比較を行い、BrowserTabRouteDecisionHandlerSystemNavigationRouteDecisionHandler も同様に proposal.location を参照しています。テストコードも同様に VisitProposal を生成して検証しています。

設計判断

VisitProposal を中心に据える設計は、情報の一元化と拡張性確保を目的としています。 ハンドラが個別に VisitOptionsPathConfigurationProperties を取得しに行く必要がなくなり、インターフェースがシンプルかつ表現力豊かになりました。さらに、location は依然として proposal.location で取得できるため、後方互換性はコード側で明示的に保たれています。

API 変更は破壊的ですが、意図的にシグネチャを統一したことで移行コストを明確化しています。 変更が必要な箇所は RouteDecisionHandler 実装と HotwireDestination のオーバーライドだけで、他のコンポーネントは VisitProposal の生成ロジックを介して自動的に対応します。この設計は将来的に更なるプロパティ追加が容易になる点でも評価できます。

まとめ

VisitProposal の導入により、ルート決定ハンドラは訪問全体のコンテキストを取得でき、より高度なルーティングロジックが実装可能になりました。API が変更されたことはありますが、既存の location 参照はそのまま残されているため、移行は明確です。今後、ハンドラ側での拡張やカスタマイズがシンプルになることが期待されます。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
6343ddc8

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的変更、設計判断、まとめの5セクションがすべて揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは正しい `言語:ファイルパス` 形式ですが、PRリンクが `[PR #203](URL)` となっており、指定の `[#203](URL)` 形式になっていません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門的なエンジニア向けの記述で、初心者向けの余計な説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論・各論・結論の段落構成になっており、1段落1トピック、トピックセンテンスで始まる形が保たれています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供されたDiffと一致しており、抜粋や省略がなく正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

使用されている技術用語はPRおよびDiffと一致し、誤用は見られません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な説明はDiffとPRの内容に基づき正確で、因果関係も論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

すべての主張がPR情報で裏付けられており、推測や捏造はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号 #203 やコード内の名前・定数は正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRの内容を正しく要約しており、矛盾はありません。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PRに記載のないバージョン情報やリリース計画などの外部知識は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PRの記述と一致しています。