Skip to content

Support for @KafkaListener beanRef #873

Open
@ruskaof

Description

Describe the feature request
According to the spring-kafka docs (https://docs.spring.io/spring-kafka/reference/kafka/receiving-messages/listener-annotation.html) it is possible to reference the current bean of a method annotated @KafkaListener using __listener, but this pseudo bean is not resolved by springwolf.

Example:

@Component
public class Listener {

    private final String topic = "topicname";
    private final String group = "groupname";

    @KafkaListener(topics = "#{__listener.topic}", groupId = "#{__listener.group}")
    public void listen(Object message) {

    }

    public String getTopic() {
        return this.topic;
    }

    public String getGroup() {
        return this.group;
    }
}

The kafka listener itself is created successfully in this case, but there is a SpelEvaluationException thrown in springwolf code:

2024-07-27T21:37:00.479+03:00 ERROR 9656 --- [test] [           main] i.g.s.c.a.o.DefaultOperationsService     : An error was encountered during operation scanning with io.github.springwolf.core.asyncapi.scanners.operations.SpringAnnotationOperationsScanner@6bee793f: Expression parsing failed

org.springframework.beans.factory.BeanExpressionException: Expression parsing failed
	at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:186) ~[spring-context-6.1.11.jar:6.1.11]
	at org.springframework.beans.factory.config.EmbeddedValueResolver.resolveStringValue(EmbeddedValueResolver.java:56) ~[spring-beans-6.1.11.jar:6.1.11]
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
	at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:1024) ~[na:na]
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
	at io.github.springwolf.plugins.kafka.asyncapi.scanners.common.KafkaListenerUtil.getChannelName(KafkaListenerUtil.java:34) ~[springwolf-kafka-1.4.0.jar:na]
	at io.github.springwolf.plugins.kafka.asyncapi.scanners.bindings.KafkaBindingFactory.getChannelName(KafkaBindingFactory.java:23) ~[springwolf-kafka-1.4.0.jar:na]
	at io.github.springwolf.plugins.kafka.asyncapi.scanners.bindings.KafkaBindingFactory.getChannelName(KafkaBindingFactory.java:17) ~[springwolf-kafka-1.4.0.jar:na]
	at io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationMethodLevelOperationsScanner.mapMethodToOperation(SpringAnnotationMethodLevelOperationsScanner.java:73) ~[springwolf-core-1.4.0.jar:na]
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) ~[na:na]
	at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:1024) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) ~[na:na]
	at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1715) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627) ~[na:na]
	at io.github.springwolf.core.asyncapi.scanners.operations.SpringAnnotationOperationsScanner.mapToOperations(SpringAnnotationOperationsScanner.java:31) ~[springwolf-core-1.4.0.jar:na]
	at io.github.springwolf.core.asyncapi.scanners.operations.SpringAnnotationOperationsScanner.scan(SpringAnnotationOperationsScanner.java:25) ~[springwolf-core-1.4.0.jar:na]
	at io.github.springwolf.core.asyncapi.operations.DefaultOperationsService.findOperations(DefaultOperationsService.java:34) ~[springwolf-core-1.4.0.jar:na]
	at io.github.springwolf.core.asyncapi.DefaultAsyncApiService.initAsyncAPI(DefaultAsyncApiService.java:71) ~[springwolf-core-1.4.0.jar:na]
	at io.github.springwolf.core.asyncapi.DefaultAsyncApiService.getAsyncAPI(DefaultAsyncApiService.java:42) ~[springwolf-core-1.4.0.jar:na]
	at io.github.springwolf.core.SpringwolfInitApplicationListener.onApplicationEvent(SpringwolfInitApplicationListener.java:31) ~[springwolf-core-1.4.0.jar:na]
	at io.github.springwolf.core.SpringwolfInitApplicationListener.onApplicationEvent(SpringwolfInitApplicationListener.java:17) ~[springwolf-core-1.4.0.jar:na]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185) ~[spring-context-6.1.11.jar:6.1.11]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178) ~[spring-context-6.1.11.jar:6.1.11]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156) ~[spring-context-6.1.11.jar:6.1.11]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:452) ~[spring-context-6.1.11.jar:6.1.11]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:385) ~[spring-context-6.1.11.jar:6.1.11]
	at org.springframework.boot.context.event.EventPublishingRunListener.ready(EventPublishingRunListener.java:109) ~[spring-boot-3.3.2.jar:3.3.2]
	at org.springframework.boot.SpringApplicationRunListeners.lambda$ready$6(SpringApplicationRunListeners.java:80) ~[spring-boot-3.3.2.jar:3.3.2]
	at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118) ~[spring-boot-3.3.2.jar:3.3.2]
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112) ~[spring-boot-3.3.2.jar:3.3.2]
	at org.springframework.boot.SpringApplicationRunListeners.ready(SpringApplicationRunListeners.java:80) ~[spring-boot-3.3.2.jar:3.3.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:349) ~[spring-boot-3.3.2.jar:3.3.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.2.jar:3.3.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.2.jar:3.3.2]
	at com.example.test.TestApplication.main(TestApplication.java:10) ~[main/:na]
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field '__listener' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:229) ~[spring-expression-6.1.11.jar:6.1.11]
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:112) ~[spring-expression-6.1.11.jar:6.1.11]
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:100) ~[spring-expression-6.1.11.jar:6.1.11]
	at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:60) ~[spring-expression-6.1.11.jar:6.1.11]
	at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:96) ~[spring-expression-6.1.11.jar:6.1.11]
	at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:114) ~[spring-expression-6.1.11.jar:6.1.11]
	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:273) ~[spring-expression-6.1.11.jar:6.1.11]
	at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:183) ~[spring-context-6.1.11.jar:6.1.11]
	... 54 common frames omitted

Motivation
This feature should be implemented to make springwolf more compatible with org.springframework.kafka.annotation.KafkaListener annotation.

Technical details
I haven't studied the source code of springwolf enough to know how to implement this.

Describe alternatives you've considered
I can always replace usages of the __listener bean to something else.

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions