Skip to content
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

Event publishing from an EventListener doesn't work in Kotlin [SPR-16433] #20979

Closed
spring-issuemaster opened this issue Jan 30, 2018 · 6 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Jan 30, 2018

Abhijit Sarkar opened SPR-16433 and commented

Spring 4.2 introduced annotation-driven event handling such that a non-void method annotated with @EventListener automatically publishes a new event with the return type as the source. This behavior is not working with Kotlin. I haven't checked with Java. Following is complete reproducible code.

data class A(val s: String)
data class B(val s: String)
@SpringBootApplication
@EnableAsync
class DemoApplication {
    @EventListener
    fun onApplicationReady(e: ApplicationReadyEvent): A {
        println("Received ApplicationReadyEvent")

        return A("Hello")
    }
}

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}
@Component
class DemoEventListener {
    @EventListener
    @Async
    fun onEventA(a: A): B {
        println("Received: $a")
        return B("${a.s} World!")
    }
}
@RunWith(SpringRunner::class)
@SpringBootTest
class DemoApplicationTest {
    @Autowired
    lateinit var ctx: ConfigurableApplicationContext

    val latch = CountDownLatch(1)

    @PostConstruct
    fun init() {
        ctx.addApplicationListener {
            println("Received: $it")
            if (it.source is B) {
                latch.countDown()
                assertThat((it.source as B).s).isEqualTo("Hello World!")
            }
        }
    }

    @Test
    fun testEvent() {
        assertThat(latch.await(5L, TimeUnit.SECONDS)).isTrue()
    }
}

Affects: 5.0.2

Attachments:

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 30, 2018

Stéphane Nicoll commented

This behavior is not working with Kotlin. I haven't checked with Java.

Before doing such wide statement, you should write something that accurately represents what you are describing. I have written a simple example with Kotlin and it works. The feature is tested with Java as well and works.

That doesn't mean that there isn't an issue of course but narrowing it down a bit would help. When you do, please create an actual project rather than pasting text in an issue: if we want to give that a spin, copy/pasting all that in a project is no fun.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 30, 2018

Abhijit Sarkar commented

Before doing such wide statement, you should write something that accurately represents what you are describing.

The statement I made is consistent with the behavior I observed, as well as demonstrated by the code I pasted. I didn't create the ticket to win a Nobel prize in literature; I created it to describe a technical problem.

I've now attached the projects that you can open in an IDE if you wish. I suppose copy-paste is too much work indeed.

As for your example, it does not publish the event B; only prints it. That's not the use case described in the ticket.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 30, 2018

Stéphane Nicoll commented

I've ran your test, it fails. Here is the output


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::             (v2.0.0.M7)

2018-01-30 09:56:28.970  INFO 66659 --- [    Test worker] com.example.demo.DemoApplicationTest     : Starting DemoApplicationTest on leo.local with PID 66659 (started by snicoll in /Users/snicoll/Downloads/demo 8)
2018-01-30 09:56:28.972  INFO 66659 --- [    Test worker] com.example.demo.DemoApplicationTest     : No active profile set, falling back to default profiles: default
2018-01-30 09:56:28.993  INFO 66659 --- [    Test worker] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@58e461d8: startup date [Tue Jan 30 09:56:28 CET 2018]; root of context hierarchy
Received ApplicationReadyEvent
2018-01-30 09:56:29.716  INFO 66659 --- [    Test worker] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
2018-01-30 09:56:29.722  INFO 66659 --- [    Test worker] com.example.demo.DemoApplicationTest     : Started DemoApplicationTest in 0.974 seconds (JVM running for 1.823)
Received: A(s=Hello)

The test fails but the second event is received as you can see in that last log statement. As the purpose of this tracker is not to help you track down what's wrong in your test, I am closing this issue. If you have more questions, ask them on StackOverflow.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 30, 2018

Abhijit Sarkar commented

You misunderstand. The problem I'm trying to highlight is that event B is supposed to be re-emitted; that never happens. The test is designed to fail to demo that exact problem.
I don't have a question here. I'm calling out what I believe to be a problem. If there's a gap in the implementation, please point it out.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 30, 2018

Abhijit Sarkar commented

I'm surprised that the issue was hurriedly closed without waiting for my feedback. Well, thanks for your time; when I find out the root cause by looking in the source code, I'll let you know.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 30, 2018

Stéphane Nicoll commented

I got that. This is your description of the issue

a non-void method annotated with @EventListener automatically publishes a new event with the return type as the source. This behavior is not working with Kotlin.

onApplicationReady is an EventListener that returns A so it matches your description of the issue. When running the test DemoEventListener#onEvent is invoked properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.