-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Allows Jackson2 encoders to log Throwable reason for not being able to serialize or deserialize #25892
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
----------------------------------------------------------------------- I have a `@RestController` `@RequestBody` that Jackson *should* be able to deserialize, but it can't because I made an error in my serialization setup. All I get in my application's logs is > org.springframework.web.server.UnsupportedMediaTypeStatusException: 415 UNSUPPORTED_MEDIA_TYPE "Content type 'application/json' not supported for bodyType=CLASS_NAME" Meanwhile there's a very helpful `IllegalArgumentException` from within Jackson that gets swallowed. Jackson actually propagates the exception all the way up to `ObjectMapper#canDeserialize(JavaType)`, where it sees that you haven't asked for that exception and swallows it. If we instead called `ObjectMapper#canSerialize(Class<T>, AtomicReference<Throwable>)`, the consumer could do something with the exception. And the same is true of `ObjectMapper#canDeserialize`. This changes Jackson2Encoder and Jackson2Decoder to call the canSerialize/canDeserialize methods that propagate the Throwable. It adds a hook where users can receive that Throwable and act on it if they want.
If you're interested in this, I'd love to get it marked |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the added protected method is slightly more convenient I don't see a big difference vs overriding canDecode
and the overhead of create that AtomicReference
instances goes to waste if not needed or when not debugging.
What do you plan to do with the information in the protected method? If it is just logging, we could consider making this all conditional on DEBUG level logging and automatically logging any exception at DEBUG level. That way it's useful out of the box and has no impact in production which may be good for what looks like a debugging feature. However I'm not sure how much noise it might add or if all exceptions should be logged?
It seems we have a similar mechanism for |
I was concerned about the overhead of creating a new My understanding, which is admittedly limited, is that Jackson will only throw an exception if it thinks it should be able to deserialize and it can't. I'd want to log this at a higher level than One question though: why do we check for |
That special debug level check for a warn statement is a pattern that we're using in a few places. The goal is to only log a single line in case of just warn level, while a full stacktrace is being added to the warn level log statement if debug level is active as well. It's a compromise to not log an extra debug log statement with the full stacktrace, and to keep the plain warn log as concise as possible. |
I've added similar logic to the Jackson Encoder/Decoder but mainly enabled as long as the DEBUG level is on. This saves us from creating and using an |
I have a
@RestController
@RequestBody
that Jackson should be ableto deserialize, but it can't because I made an error in my
serialization setup. All I get in my application's logs is
Meanwhile there's a very helpful
IllegalArgumentException
from withinJackson that gets swallowed. Jackson actually propagates the exception
all the way up to
ObjectMapper#canDeserialize(JavaType)
, where itsees that you haven't asked for that exception and swallows it. If we
instead called
ObjectMapper#canSerialize(Class<T>, AtomicReference<Throwable>)
,the consumer could do something with the exception. And the same is
true of
ObjectMapper#canDeserialize
.This changes Jackson2Encoder and Jackson2Decoder to call the
canSerialize/canDeserialize methods that propagate the Throwable. It
adds a hook where users can receive that Throwable and act on it if
they want.