-
Notifications
You must be signed in to change notification settings - Fork 1.7k
GH-3880: The DefaultHandler resolves an incorrect value for the parameter annotated with @Header. #3881
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
args[0] = message.getPayload(); | ||
System.arraycopy(providedArgs, 0, args, 1, providedArgs.length); | ||
return this.delegatingHandler.invoke(message, args); | ||
return this.delegatingHandler.invoke(message, providedArgs); |
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.
inline comment;
I think previous code cause the bug. (#577)
However, I don't fully understand why the payload needs to be resolved and included in the args when a defaultHandler
is set.
I did dig into the lower call stack of this.delegatingHandler.invoke(...)
, but the defaultHandler
was not used in relation to providedArgs
.
So, I think this code change is better in terms of bug fix.
However, there may be reasons I haven't realized, so I would appreciate any advice from the maintainers on this point.
For now, only one of the existing test cases has been modified.
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.
See that comment:
// Needed to avoid returning raw Message which matches Object
If @KafkaHandler(isDefault = true)
method has argument like Object payload
, it would match the whole message instead of just its payload.
Usually, a @KafkaHandler(isDefault = true)
method is used as a last resort when any other @KafkaHandler
cannot match the provided payload.
The whole point of the @KafkaHandler
is to handle different payload types with different methods.
So, I'm not sure if your fix is legit: https://docs.spring.io/spring-kafka/reference/kafka/receiving-messages/class-level-kafkalistener.html#page-title
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.
@artembilan
I have a question!
@KafkaListener
class MyListener {
@KafkaHandler(isDefault = true)
public void (@Header("receivedTopic") String topic, Object payload) {
boolean isSame = topic == payload;
}
}
There are two parameters.
One is annotated with @Header
, and the other one is the expected payload
.
I means that the topic
and payload
parameters are same in the current implementation.
So, the variable isSame
is True
. 😓
May I ask if this behavior is intentional by design?
Thanks for your time 🙇♂️
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.
I have to look into those details deeper, but that looks suspicious that payload
argument is resolved to header 🤷
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.
I have to look into those details deeper, but that looks suspicious that payload argument is resolved to header 🤷
The code I mentioned PR description causes the problem.
It is not part of spring-kafka
. 😢
InvocableHandlerMethod
I think the easiest way to address this issue is that InvocationHandler
respect ArgumentResolver
. (
However, since it would affect a larger number of users, I believe it might not be accepted.
That said, I personally think that explicitly used annotations should take precedence over resolving parameters by type.
If this change affects the design intention of the DefaultKafkaHandler, it might be a good idea to document that annotations cannot be explicitly used with the default handler.
What do you think?
args[0] = message.getPayload(); | ||
System.arraycopy(providedArgs, 0, args, 1, providedArgs.length); | ||
return this.delegatingHandler.invoke(message, args); | ||
return this.delegatingHandler.invoke(message, providedArgs); |
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.
See that comment:
// Needed to avoid returning raw Message which matches Object
If @KafkaHandler(isDefault = true)
method has argument like Object payload
, it would match the whole message instead of just its payload.
Usually, a @KafkaHandler(isDefault = true)
method is used as a last resort when any other @KafkaHandler
cannot match the provided payload.
The whole point of the @KafkaHandler
is to handle different payload types with different methods.
So, I'm not sure if your fix is legit: https://docs.spring.io/spring-kafka/reference/kafka/receiving-messages/class-level-kafkalistener.html#page-title
Just wrote this test:
It fails on the So, apparently the header is resolved to the payload somehow... |
According to the doc, the existing behavior is correct:
So, that Do I miss anything else? |
Exactly! This is exactly what I'm saying. |
sure! That could be a good plan. |
---- | ||
|
||
Also, this won't work as well. | ||
The `payload` value will be injected as the `topic`. |
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.
" will be injected into the topic
parameter"?
Otherwise I ma getting confused as before.
Such a sentence makes me think that header value is injected into the payload
parameter.
} | ||
---- | ||
|
||
If you need discrete custom headers in a default method, use this: |
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.
I thought we discussed before that no "you", "me", "we" or even "they" in the technical documentation.
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.
My bad, I will keep in mind 😢
you contribute a lot and we are grateful for that. Tried to merge this your PR and noticed this: Signed-off-by: chickenchickenlove [email protected] from legal respective that doesn’t follow DCO requirements: https://docs.brigade.sh/topics/contributor-guide/signing/#:~:text=Verify%20the%20contribution%20in%20your,the%20terms%20of%20the%20DCO.&text=You%20MUST%20use%20your%20legal,Configure%20your%20git%20client%20appropriately. Please , revise your Git client for your real name and real email. |
@artembilan Thanks for your comment! |
You can just squash all the commits to one, add real Sign off by, and force push to PR. |
251a18e
to
249d777
Compare
I squashed commits to update legal name, and force pushed.!! |
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.
Please, re-push with the proper commit message.
Here are some tips how that supposed to be: https://cbea.ms/git-commit/
@artembilan I read the article you shared, and I assumed it might be one of the following requests.
What is your point? Please let me know 🙇♂️ |
I mean mostly “what?” and “why?”. Very often there is a situation when we look into the past change and we cannot determine why. I don’t insist on that, but if you’d like to avoid this kind of discussion in the future contributions I’d recommend to make commits meaningful. For example: b0db30c |
…e for the parameter annotated with @Header. Fixes: spring-projects#3880 Issue link: spring-projects#3880 Add an documentation on how to correctly inject headers in default methods of class-level @KafkaListener. Because currently, The DefaultHandler resolve an incorrect value for the parameter annotated with @Header. also, the spring-kafka's intended usage is incompatiable with the design intent of the InvocationHandler, so spring-kafka cannot resolve this issue. Therefore, we will add documentation to prevent users from becoming confused. Signed-off-by: Sanghyeok An <[email protected]>
249d777
to
049ef27
Compare
Thanks for sharing proper examples 🙇♂️ |
@chickenchickenlove , |
If
defaultHandler
is set, the above code is executed.During this call stack, the
args
array contains a payload ofKafkaMessage
, which is then passed to the invoked method.InvocableHandlerMethod.java (L212-L224)
each paramater's value is resolved here.
However, the method
findProvidedArgument(...)
resolves parameter by only checkingparameterType
.So, if either the payload type or the parameter type annotated with
@Header
isString
,the payload and the annotated parameter will have the same value.