Skip to content

GH-3869: Should fail bean registration when no method … #3870

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

Merged
merged 5 commits into from
Apr 29, 2025

Conversation

chickenchickenlove
Copy link
Contributor

@chickenchickenlove chickenchickenlove commented Apr 26, 2025

I created an issue and a PR regarding an improvement I thought of from a fast-fail perspective.
Please feel free to let me know if you think the changes are unnecessary.
Thanks for your time 🙇‍♂️

…listeners are registered.

Signed-off-by: chickenchickenlove <[email protected]>
Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, supply the test for coverage .
Thanks

Signed-off-by: chickenchickenlove <[email protected]>
@chickenchickenlove
Copy link
Contributor Author

@artembilan thanks for comments even if holiday!

I added new test code to cover worst case.
other happy cases can be discovered other test codes which already exist.

When you have time, Please take a look 🙇‍♂️
Thanks again to look into my PR even if holiday!

* @since 4.0.0
*/

class KafkaListenerAnnotationBeanPostProcessorTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer to use *Tests suffix.

static class TestConfig {

@Bean
public KafkaListenerAnnotationBeanPostProcessor<Object, Object> kafkaListenerAnnotationBeanPostProcessor() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to do this explicitly?
Cannot we rely on the @EnableKafka instead?

// WHEN + THEN
assertThatThrownBy(ctx::refresh)
.isInstanceOf(expectedErrorType)
.hasMessage(expectedErrorMsg);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer different style:

assertThatExceptionOfType()
   .isThrownBy()

I also don't see a reason in those GIVEN/WHEN/THEN


@Component
@KafkaListener
static class BuggyListener {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think buggy is the correct word to express the problem.
For me this word mean "the comfortable cart for infants".

Perhaps something like NoHandlerMethodListener to be as explicit for the problem as possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know that. Thanks a lot 🙇‍♂️

static class BuggyListener {

public void listen(String message) {
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need return for the void method?
Why just we cannot leave it as an empty body?

@@ -0,0 +1,76 @@
/*
* Copyright 2017-2025 the original author or authors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a copy/paste from other classes, but what is the point of that 2017?
The goal of the copyright dates is to show when the entity was created and when modified.
Was this class created in 2017? No. So, why use that pattern?
Something like just 2025 is enough. However the pattern 2025-2025 would still work if you are afraid some parser would expect two years.

private void throwErrorIfNoListenerMethods(Object bean, boolean hasMethodLevelListeners,
boolean hasClassLevelListeners, boolean hasMethodLevelKafkaHandlerAnnotation) {
if (hasMethodLevelListeners) {
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit awkward style.
Why do we need to go to this method at all, if we meet this condition?
I fully don't see a reason in this method.
The if (!hasMethodLevelListeners && hasClassLevelListeners && !hasMethodLevelKafkaHandlerAnnotation) and throw new IllegalStateException is enough to have in place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you and addressed it!
I anticipated that the conditions could become more complex because of #3865 .
So, I extracted them into a separate method to clearly separate and handle the problematic conditions.

}

if (hasClassLevelListeners && !hasMethodLevelKafkaHandlerAnnotation) {
throw new IllegalStateException("No kafka listener methods found on bean type: " + bean.getClass());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think just on bean is enough, without any getClass() extraction.
The bean instance might lead to the place where it declared.

Signed-off-by: chickenchickenlove <[email protected]>
@chickenchickenlove
Copy link
Contributor Author

chickenchickenlove commented Apr 28, 2025

I added two withMessage(...) to test cases.
Because a BeanCreationException may occur, but I want to explicitly show that it is caused within our test target NoHandlerMethodListener.
When you have time, PTAL. 🙇‍♂️

@@ -407,13 +407,19 @@ public Object postProcessAfterInitialization(final Object bean, final String bea
this.logger.debug(() -> annotatedMethods.size() + " @KafkaListener methods processed on bean '"
+ beanName + "': " + annotatedMethods);
}
Set<Method> methodsWithHandler = MethodIntrospector.selectMethods(targetClass,
(ReflectionUtils.MethodFilter) method ->
AnnotationUtils.findAnnotation(method, KafkaHandler.class) != null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think no need to do this extraction outside of the if (hasClassLevelListeners) { branch.


assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(ctx::refresh)
.withMessageContaining("No kafka listener methods found on bean type.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also can check for our IllegalStateException as a cause.

chickenchickenlove and others added 2 commits April 30, 2025 00:17
…n/KafkaListenerAnnotationBeanPostProcessor.java

Co-authored-by: Artem Bilan <[email protected]>
Signed-off-by: ChickenchickenLove <[email protected]>
Signed-off-by: chickenchickenlove <[email protected]>
@artembilan artembilan merged commit 6682837 into spring-projects:main Apr 29, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Should fail bean registration when no method listeners are registered.
2 participants