Problem statement
Request and response validation keys are not fully symmetric in naming and structure, which makes configuration harder to understand and maintain. We should provide the same pattern on both sides for ID rules, duplicate-member handling, and field-contamination rules, and define explicit option policies (default, validation rule, failure behavior).
Proposed solution
- Shared version and id-member policies
-
jsonrpc.validation.request.require-json-rpc-version-20
- Default:
true
- Rule: request
jsonrpc must be exactly "2.0"
- Failure:
-32600 INVALID_REQUEST
-
jsonrpc.validation.response.require-json-rpc-version-20
- Default:
true
- Rule: response
jsonrpc must be exactly "2.0"
- Failure:
-32600 INVALID_REQUEST (response-side validation exception)
-
jsonrpc.validation.request.require-id-member
- Default:
false
- Rule: optionally require
id member in request
- RFC note: default remains
false because JSON-RPC 2.0 allows Request objects without id (Notification)
- Failure (when enabled):
-32600 INVALID_REQUEST
-
jsonrpc.validation.response.require-id-member
- Default:
true
- Rule: require
id member in response
- Failure:
-32600 INVALID_REQUEST
- Shared id-type policies
-
jsonrpc.validation.request.allow-string-id
-
jsonrpc.validation.response.allow-string-id
- Default:
true
- Rule: allow string
id
- Failure on disallowed value:
-32600
-
jsonrpc.validation.request.allow-numeric-id
-
jsonrpc.validation.response.allow-numeric-id
- Default:
true
- Rule: allow numeric
id
- Failure on disallowed value:
-32600
-
jsonrpc.validation.request.allow-null-id
-
jsonrpc.validation.response.allow-null-id
- Default:
true
- Rule: allow
id: null
- Failure on disallowed value:
-32600
-
jsonrpc.validation.request.allow-fractional-id
-
jsonrpc.validation.response.allow-fractional-id
- Default:
true
- Rule: allow fractional numeric
id
- Failure on disallowed value:
-32600
- Shared duplicate-member policies
- Symmetric field-contamination policies
- Response
error.code policy group
-
jsonrpc.validation.response.error-code.policy
- Default:
ANY_INTEGER
- Policies:
ANY_INTEGER: pass when integer
STANDARD_ONLY: allow JSON-RPC standard error codes only
STANDARD_OR_SERVER_ERROR_RANGE: allow standard + server error range
CUSTOM_RANGE: allow only user-defined range
-
jsonrpc.validation.response.error-code.range.min
-
jsonrpc.validation.response.error-code.range.max
- Default: none
- Rule: required when
policy=CUSTOM_RANGE
- Constraint:
min <= max
- Failure on invalid config: fail fast at startup
- Keep existing request params policy
jsonrpc.validation.request.params-type-violation-code-policy
- Default:
INVALID_PARAMS
- Rule: map params shape/type violations to
INVALID_PARAMS or INVALID_REQUEST
Implementation scope:
- Core parser/validator/options updates
- Spring properties and auto-configuration wiring
- configuration metadata and IDE hints updates
- unit/integration/e2e tests (success/failure/branch/exception)
- README/docs examples synchronization
Alternatives considered
- Expanding request-side only
- Adding partial keys without structural symmetry
Rejected because these approaches keep configuration inconsistent and increase long-term maintenance cost.
JSON-RPC behavior impact
No default protocol breaking behavior is intended.
Behavior changes occur only when stricter options are enabled.
Additional context
Acceptance criteria:
- Symmetric request/response key patterns where applicable
- Option policy docs include defaults, validation rules, and failure behavior
./gradlew check passes
- docs, metadata, and implementation are fully aligned
Migration notes
This change requires migration for existing response validation keys.
Required key renames:
jsonrpc.validation.response.require-response-id-member -> jsonrpc.validation.response.require-id-member
jsonrpc.validation.response.allow-string-response-id -> jsonrpc.validation.response.allow-string-id
jsonrpc.validation.response.allow-numeric-response-id -> jsonrpc.validation.response.allow-numeric-id
jsonrpc.validation.response.allow-null-response-id -> jsonrpc.validation.response.allow-null-id
jsonrpc.validation.response.allow-fractional-response-id -> jsonrpc.validation.response.allow-fractional-id
Semantic inversion:
- Old:
jsonrpc.validation.response.allow-request-fields-in-response
- New:
jsonrpc.validation.response.reject-request-fields
- Mapping rule:
reject-request-fields = !allow-request-fields-in-response
No default-value flip is required for jsonrpc.validation.request.require-id-member.
- It remains
false by design because JSON-RPC Notifications are valid requests without id.
New additive keys (no migration required if previously unused):
jsonrpc.validation.request.allow-string-id
jsonrpc.validation.request.allow-numeric-id
jsonrpc.validation.request.allow-null-id
jsonrpc.validation.request.allow-fractional-id
jsonrpc.validation.request.reject-response-fields
jsonrpc.validation.request.reject-duplicate-members
jsonrpc.validation.response.reject-duplicate-members
jsonrpc.validation.response.error-code.policy
jsonrpc.validation.response.error-code.range.min
jsonrpc.validation.response.error-code.range.max
Documentation requirements:
- Add old->new key mapping table in
docs/configuration-reference.md
- Add before/after YAML examples in README and Spring Boot guide
- Reflect canonical keys in configuration metadata/IDE hints
- Include migration section in release notes
Problem statement
Request and response validation keys are not fully symmetric in naming and structure, which makes configuration harder to understand and maintain. We should provide the same pattern on both sides for ID rules, duplicate-member handling, and field-contamination rules, and define explicit option policies (default, validation rule, failure behavior).
Proposed solution
jsonrpc.validation.request.require-json-rpc-version-20truejsonrpcmust be exactly"2.0"-32600 INVALID_REQUESTjsonrpc.validation.response.require-json-rpc-version-20truejsonrpcmust be exactly"2.0"-32600 INVALID_REQUEST(response-side validation exception)jsonrpc.validation.request.require-id-memberfalseidmember in requestfalsebecause JSON-RPC 2.0 allows Request objects withoutid(Notification)-32600 INVALID_REQUESTjsonrpc.validation.response.require-id-membertrueidmember in response-32600 INVALID_REQUESTjsonrpc.validation.request.allow-string-idjsonrpc.validation.response.allow-string-idtrueid-32600jsonrpc.validation.request.allow-numeric-idjsonrpc.validation.response.allow-numeric-idtrueid-32600jsonrpc.validation.request.allow-null-idjsonrpc.validation.response.allow-null-idtrueid: null-32600jsonrpc.validation.request.allow-fractional-idjsonrpc.validation.response.allow-fractional-idtrueid-32600jsonrpc.validation.request.reject-duplicate-membersfalse-32700 PARSE_ERRORor-32600 INVALID_REQUEST)jsonrpc.validation.response.reject-duplicate-membersfalsejsonrpc.validation.request.reject-response-fieldsfalseresultorerror-32600 INVALID_REQUESTjsonrpc.validation.response.reject-request-fieldsfalsemethodorparams-32600 INVALID_REQUESTerror.codepolicy groupjsonrpc.validation.response.error-code.policyANY_INTEGERANY_INTEGER: pass when integerSTANDARD_ONLY: allow JSON-RPC standard error codes onlySTANDARD_OR_SERVER_ERROR_RANGE: allow standard + server error rangeCUSTOM_RANGE: allow only user-defined rangejsonrpc.validation.response.error-code.range.minjsonrpc.validation.response.error-code.range.maxpolicy=CUSTOM_RANGEmin <= maxjsonrpc.validation.request.params-type-violation-code-policyINVALID_PARAMSINVALID_PARAMSorINVALID_REQUESTImplementation scope:
Alternatives considered
Rejected because these approaches keep configuration inconsistent and increase long-term maintenance cost.
JSON-RPC behavior impact
No default protocol breaking behavior is intended.
Behavior changes occur only when stricter options are enabled.
Additional context
Acceptance criteria:
./gradlew checkpassesMigration notes
This change requires migration for existing response validation keys.
Required key renames:
jsonrpc.validation.response.require-response-id-member->jsonrpc.validation.response.require-id-memberjsonrpc.validation.response.allow-string-response-id->jsonrpc.validation.response.allow-string-idjsonrpc.validation.response.allow-numeric-response-id->jsonrpc.validation.response.allow-numeric-idjsonrpc.validation.response.allow-null-response-id->jsonrpc.validation.response.allow-null-idjsonrpc.validation.response.allow-fractional-response-id->jsonrpc.validation.response.allow-fractional-idSemantic inversion:
jsonrpc.validation.response.allow-request-fields-in-responsejsonrpc.validation.response.reject-request-fieldsreject-request-fields = !allow-request-fields-in-responseNo default-value flip is required for
jsonrpc.validation.request.require-id-member.falseby design because JSON-RPC Notifications are valid requests withoutid.New additive keys (no migration required if previously unused):
jsonrpc.validation.request.allow-string-idjsonrpc.validation.request.allow-numeric-idjsonrpc.validation.request.allow-null-idjsonrpc.validation.request.allow-fractional-idjsonrpc.validation.request.reject-response-fieldsjsonrpc.validation.request.reject-duplicate-membersjsonrpc.validation.response.reject-duplicate-membersjsonrpc.validation.response.error-code.policyjsonrpc.validation.response.error-code.range.minjsonrpc.validation.response.error-code.range.maxDocumentation requirements:
docs/configuration-reference.md