I'm currently implementing a solution to leverage the transactional event facilities of CDI in Java SE. I've implemented:
- A TransactionServices class and made sure it's loaded via the ServiceLoader
- A UserTransaction class
- A Transactional interceptor
And I have added the weld-jta module to my project. Everything is fine until I invoke afterCompletion() of the synchronization observer. Test conditions:
private void onInit(@Observes @Initialized(ApplicationScoped.class) Object event) { |
Schedulers.single().scheduleDirect(this::fireEvent, 1, TimeUnit.SECONDS); |
} |
|
@Transactional |
public void fireEvent() { |
LOGGER.info("firing event"); |
events.fire("hello"); |
LOGGER.info("event fired"); |
} |
|
@Transactional |
private void onEvent(@Observes(during = TransactionPhase.AFTER_SUCCESS) String event) { |
LOGGER.info(() -> String.format("event received after success: %s", event)); |
}
|
Please note that the Transactional annotation in the example above is my interceptor binding annotation, not the JTA's one. When afterCompletion is invoked, the transaction related to 'fireEvent' is committed. A new transaction is started when the observer method is invoked. When the observer method returns, the later transaction (related to 'onEvent') is committed. But then, a new event is fired again and it's value is null, and in the logs I can see:
InfraUserTransaction - begin new transaction |
TransactionTest - firing event |
TransactionTest - event fired |
InfraUserTransaction - committing transaction |
InfraUserTransaction - transaction committed |
InfraUserTransaction - notifying after completion - STATUS_COMMITTED |
InfraUserTransaction - begin new transaction |
TransactionTest - event received after success: hello |
InfraUserTransaction - committing transaction |
InfraUserTransaction - transaction committed |
InfraUserTransaction - notifying after completion - STATUS_COMMITTED |
ERROR Event - WELD-000401: Failure while notifying an observer [BackedAnnotatedMethod] private steappe.production.application.TransactionTest.onEvent(@Observes String) of event null. |
java.lang.IllegalAccessError: tried to access method steappe.production.application.TransactionTest.onEvent(Ljava/lang/String;)V from class steappe.production.application.TransactionTest$Proxy$_$$_WeldSubclass |
InfraUserTransaction - after completion notified |
InfraUserTransaction - after completion notified
|
As you can see, the list of events to distribute after the completion of the first commit seems to contain some remaining of the first distributed event. Then, after the second commit, WELD tries to distribute this event again. I had a look to the source code of weld-jta, and I can see that:
- The synchronization observer is set when an event is fired
- The synchronization observer is not cleared when a new transaction is started while an AFTER_SUCCESS event is being notified
I had a look to the CDI specifications, and I could not see anything that would explain the reason why this code should not work. Did I misunderstand the specifications? Did I do something wrong? Or is there a bug? |