fix: pin the clobbered JSON keys with @JsonKey and surface 5 fields the native SDKs already support - #57
Merged
Merged
Conversation
3d753f8 regenerated every .g.dart from a clean build. For four fields the committed JSON keys changed, because their Dart field names do not round-trip through json_serializable's `field_rename: snake` (which inserts `_` before every single uppercase letter): PrivateMoney.onlineMessage oneline_message -> online_message PrivateMoney.canUseC2CTransfer can_use_c2c_transfer -> can_use_c2_c_transfer BankPayRedirectUrl.redirectUrl redirectUrl -> redirect_url BankPayRedirectUrl.paytreeCustomerNumber paytreeCustomerNumber -> paytree_customer_number Both are non-nullable in PrivateMoney, so fromJson now throws on every response the API actually returns. Pin the keys with @jsonkey so they survive any future regeneration, and regenerate the two affected files. `onlineMessage` is a typo of `oneline` introduced in 51b7a62; the field name is left alone to avoid a breaking API change. Note this also repairs its toJson side, which had been emitting `online_message` since that commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
flutter-sdk はサーバを直接叩かず、ネイティブSDK (pokepaylib / Pokepay pod)
の型付きレスポンスクラスを経由して再シリアライズされた JSON を読む。
Android は FAIL_ON_UNKNOWN_PROPERTIES=false で未知キーを捨てたうえ
Response.toString() が宣言済みフィールドだけを書き戻し、iOS も Codable +
明示 CodingKeys で同じ挙動になる。したがってネイティブ側に無いキーは
Dart まで届かず、Dart にフィールドを足しても常に null になる。
監査で挙がった 27 件のうち、ネイティブ 2.0.28 が既に対応していて
Dart 側だけが欠けている 5 件を通す。
レスポンス (未対応1 のうち 4 件):
CvsAuthorization に haraikomi_url / receipt_no / done_at / canceled_at を追加。
Android BankAPI/autogen/responses/CvsAuthorization.java と
iOS Responses/CvsAuthorization.swift の双方が既に保持している。
done_at / canceled_at はネイティブが String のまま素通しするため、
同クラスの pay_limit や UserTransaction.done_at と揃えて String? で受ける。
4 件とも nullable なので既存レスポンスでも fromJson は落ちない。
リクエスト (未対応2 のうち 1 件):
patchAccountCouponDetail に code を追加。
PokepaySdkPlugin.java は既に call.argument("code") を読んで
PatchAccountCouponDetail に渡しており、Dart が送っていなかった。
Swift 側は PatchCouponDetail の code 引数を渡し忘れていたので併せて修正。
残り 22 件は CreateBill / UpdateCashtray / CreateAccountCpmToken 等の
コンストラクタ自体にパラメータが無く、PrivateMoney / UserTransaction /
Account / AccountCpmToken のレスポンスクラスにもフィールドが無いため、
android-sdk と ios-sdk の改修とリリースが先に必要になる。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Two things in one PR.
3d753f8(bug fix)1. Fixing the JSON keys broken by the clean regeneration
When
3d753f8(fix: make build_runner output reproducible in CI) regenerated every.g.dartfrom scratch, the JSON keys of 4 fields changed and were committed to master as-is.The cause is that these Dart field names do not round-trip through json_serializable's
field_rename: snake. That transform inserts a_before every uppercase character except the first, so names containing acronyms or typos get mangled.PrivateMoney.onlineMessageoneline_messageonline_messagePrivateMoney.canUseC2CTransfercan_use_c2c_transfercan_use_c2_c_transferBankPayRedirectUrl.redirectUrlredirectUrlredirect_urlBankPayRedirectUrl.paytreeCustomerNumberpaytreeCustomerNumberpaytree_customer_numberBoth
PrivateMoneyfields are non-nullable (as String/as bool), soPrivateMoney.fromJsonthrows on every response the API actually returns.TokenInfowas another casualty of3d753f8and was fixed incd96258, but these 4 were missed.This PR makes the JSON key explicit with
@JsonKey(name: ...)so regeneration on any future version cannot break them again. The field names themselves are left alone since renaming them would be a breaking change to the public API.lib/responses/private_money.dart/.g.dartlib/responses/bankpay_redirect_url.dart/.g.dartAs a side effect, the toJson side of
onlineMessageis fixed too.onlineMessagewas mistakenly renamed fromonelineMessagein51b7a62; at the time only thefromJsonhalf of the.g.dartwas hand-patched back tooneline_message, leaving toJson emittingonline_messagesince 2022.2. Surfacing fields the native SDKs already support
Comparing
pokepay-server'sapi/views/json/*.lispagainst the hand-written SDK turned up 13 response keys the server returns but the SDK never reads, and 14 request parameters the API accepts but the SDK never sends. This PR lands the 5 of those that flutter-sdk can fix on its own.Why only 5
flutter-sdk does not talk to the API directly. Every call goes through a native SDK.
On Android,
JsonConverter.createObjectMapper()setsFAIL_ON_UNKNOWN_PROPERTIES=falseso unknown keys are discarded, andResponse.toString()then writes back only the declared fields viawriteValueAsString(this). iOS behaves identically withCodable+ explicitCodingKeys->JSONEncoder.In other words, a key that does not exist on the native class never reaches Dart, and adding the field to the Dart class only ever yields null. The same applies to requests: a parameter absent from the native request class's constructor cannot be sent.
Changes
4 new fields on
CvsAuthorizationThe payment-slip URL, receipt number, and completion/cancellation timestamps for convenience-store payments. These look necessary in practice.
haraikomi_urlString?receipt_noString?done_atString?canceled_atString?Both native SDKs already carry these — Android in
BankAPI/autogen/responses/CvsAuthorization.java, iOS inResponses/CvsAuthorization.swift— so adding them to the Dart class is enough to make the values arrive.done_at/canceled_atareString?rather thanDateTime?because both native SDKs type them asString(String?on Swift) and pass the server's RFC3339 string straight through.Account.nearestExpiresAtisDateTime?only because the native layer receives it as aDateand reformats it; the pass-through fieldsCvsAuthorization.payLimitandUserTransaction.doneAtare alreadyString. This follows that convention.All 4 are nullable, so
fromJsonwill not break on existing responses.codeonpatchAccountCouponDetailThe coupon redemption code. The native side already supports it — Android
PatchAccountCouponDetail, iOSPatchCouponDetail— andPokepaySdkPlugin.javaalready readscall.argument("code")and forwards it. Dart simply never sent it.The Swift side was missing the
codeargument onPatchCouponDetail(SwiftPokepaySdkPlugin.swift:509), which this PR fixes as well.About the remaining 22
CreateBill/UpdateCashtray/UpdateBill/CreateAccountCpmToken/UpdateTerminal/GetBill/GetAccountBalances/CreateCheckhave no such parameters on their constructors, and thePrivateMoney/UserTransaction/Account/AccountCpmTokenresponse classes have no such fields.PrivateMoney.display_money_and_point/is_topup_quota_available/is_itrust_authentication_enabled/money_topup_transfer_limit/sounds,UserTransaction.raw_point_amount/campaign_point_amount,Account.status,AccountCpmToken.strategycreateAccountCpmToken'skeep_alive/is_short_token/strategy,createBill'sadditional_account_ids/min_amount/max_amount/metadata,createCheck'smetadata,productsonupdateBill/updateCashtray,updateTerminal'spush_service,getAccountBalances'sexpired,getBill'sprivate_money_idEach of these needs android-sdk and ios-sdk changes -> a 2.0.29 release -> a dependency bump in flutter-sdk, in that order, so they are out of scope here.
For what it's worth, no required parameter is missing anywhere (all 47 operators were checked).
Verification
Static
build_runner clean+--delete-conflicting-outputs) and confirmed the.g.dartdiff is limited to the 3 intended files (the other 179 match master exactly)flutter analyze --no-fatal-warnings-> No issues found!can_use_c2c_transfer/redirectUrl/paytreeCustomerNumbermatch the keys as of3d753f8^exactlydart run tool/check_native_links.dart-> 0 errors. The newly addedcodedoes not appear in the warnings, which mechanically confirms both Java and Swift read the key Dart sendsAgainst the live dev environment
Built a test app depending on
pokepay_sdkby path and ran it underintegration_teston a Pixel_5_API_31 emulator, exercising the real path Dart -> MethodChannel -> pokepaylib 2.0.28 -> api-dev.pokepay.jp. 32 passed / 2 failed / 3 skipped.The 4 new
CvsAuthorizationfields carry real values:This also backs up the
String?decision — the server's RFC3339 string arrives verbatim through the native layer.patchAccountCouponDetail(code)returned 200, and the SDK debug log showscode: smoke-test-codein the MethodChannel argument map. Note that the dev coupon does not require a code, so the response cannot distinguish whethercodewas sent (verified with curl: identical 200 with and without it). The native-to-server leg is confirmed at the source level only.The fix in part 1 is confirmed live as well:
getPrivateMoneyreturnscanUseC2CTransfer=true. On master this is exactly where the non-nullablefromJsonwould have thrown looking forcan_use_c2_c_transfer.The 2 failures are server-side data/permission conditions, not SDK bugs:
getAccountTopupStats-> 422private_money_total_topup_limit_not_found, andcreateCashtray-> 403 Forbidden (this terminal token has no merchant role), which also caused the 3 skips.Not verified
iOS was not run. The one-line Swift change compiles only in principle — it matches the existing
PatchCouponDetailinitializer signature, but no Xcode build was performed. Worth a run on a real iOS device before merging.Note
Two unrelated pre-existing bugs turned up during the dev-environment run and were filed separately: #58 (CPM token detection in
getTokenInfo/scanTokendoes not match the actual token format) and #59 (PokepayClient.topup()passes the string literal'check.id').🤖 Generated with Claude Code