Propagate non-recoverable JSON conversion failures instead of demoting them to a generic 500 - #1436
Closed
apoupard wants to merge 1 commit into
Closed
Conversation
…ead of demoting them to a generic 500 spring-cloudGH-1429/ef533f377 already made convertNonMessageInputIfNecessary rethrow (rather than swallow) a JSON conversion failure when the request's Content-Type is JSON (failOnJsonError), fixing a misleading ClassCastException into a real Jackson exception in the logs. But that rethrown exception is still wrapped as a plain IllegalStateException by convertInputPublisherIfNecessary, indistinguishable from any other conversion failure - so it still resolves to a generic 500, and there is no way for a downstream consumer (a web framework's exception resolver, a custom @ControllerAdvice, etc.) to recognize "this was a deliberate, non-recoverable rejection" without inspecting the message/cause chain. Add NonRecoverableConversionException, a narrow MessageConversionException subtype thrown only from the failOnJsonError path, and let it propagate unwrapped through convertInputPublisherIfNecessary. This adds no new dependency (MessageConversionException already lives in spring-messaging, a non-optional dependency of this module) and changes no existing behavior for any other exception type. Known follow-up, intentionally out of scope here: a function declared as Function<Message<T>, R> (explicit Message-wrapped type) never reaches this path at all - convertInputMessageIfNecessary deliberately returns the original, unconverted message whenever the target type is itself Message<T> (to support legitimate no-conversion-needed cases like KafkaNull), which silently masks the same class of failure. Functions declared over the plain payload type (the common case, and the only shape spring-cloud-function's own new PojoFunctionIntegrationTests covers) are unaffected and fixed by this change.
3 tasks
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.
Summary
GH-1429 (#ef533f377) already made
convertNonMessageInputIfNecessaryrethrow (rather than swallow) a JSON conversion failure when the request'sContent-Typeis JSON (failOnJsonError), fixing a misleadingClassCastExceptioninto a real Jackson exception in the logs. That's a great fix for the log message - but the rethrown exception is still wrapped as a plainIllegalStateExceptionbyconvertInputPublisherIfNecessary, indistinguishable from any other conversion failure. Two consequences:@ControllerAdvice, an app's own error handler) to recognize "this converter deliberately, definitively rejected this input" without inspecting the message/cause chain.This PR adds
NonRecoverableConversionException, a narrowMessageConversionExceptionsubtype thrown only from thefailOnJsonErrorpath, and lets it propagate unwrapped throughconvertInputPublisherIfNecessaryinstead of being folded into the genericIllegalStateExceptionbucket. Concretely, this lets an app register something like:and get a real 400 for malformed input, instead of digging through
IllegalStateExceptioncauses.MessageConversionExceptionalready lives inspring-messaging, a non-optional dependency ofspring-cloud-function-context.failOnJsonErrorbranch's exception type changes.Known follow-up (intentionally out of scope here)
A function declared as
Function<Message<T>, R>(explicitMessage-wrapped type) never reaches this path at all:convertInputMessageIfNecessarydeliberately returns the original, unconverted message whenever the target type is itselfMessage<T>(to support legitimate no-conversion-needed cases likeKafkaNull), which silently masks the same class of failure a different way. Functions declared over the plain payload type - the common case, and the only shape the newPojoFunctionIntegrationTestscovers - are unaffected and fixed by this change. Happy to open a separate issue/PR for theMessage<T>case if useful; it needs its own design discussion since the current fallback is deliberate, not an oversight.Test plan
SimpleFunctionRegistryTests#testReactivePojoFunctionPropagatesNonRecoverableConversionExceptionForMalformedJson(new) - removal-proofed: fails without the fix, passes with it.SimpleFunctionRegistryTests#testReactiveFunctionMessages(existing, valid-JSON case) - still green, confirming no behavior change on the success path.spring-cloud-function-context+spring-cloud-function-websuite: 199 tests, 0 failures, 0 errors (including the newPojoFunctionIntegrationTests).