How to inject Hibernate's Session into async listener in micronaut?

Viewed 544

I am trying to inject Hibernate session to listener that programmed to run on worker thread.

So i have this kind of event.

public class SomeEvent {
    public long id;
    public Double value;
}

And i pushing it from a service.

import javax.inject.Singleton;
import io.micronaut.context.event.ApplicationEventPublisher;

@Singleton
public class SomeService {

    public void createAndPublish(Create payload) {
        Record record = this.create(payload);
        Long id = record.getId();
        record.setValue(10);
        assert id != null;

        SomeEvent event = new SomeEvent();
        event.id = id;
        event.value = 10;

        publisher.publishEvent(event);
    }
}

And this is my listener

import javax.persistence.EntityManager;
import javax.inject.Singleton;
import io.micronaut.runtime.event.annotation.EventListener;
import io.micronaut.scheduling.annotation.Async;
import io.micronaut.spring.tx.annotation.Transactional;
import io.micronaut.configuration.hibernate.jpa.scope.CurrentSession;

@Singleton
public class SomeEventListener {

    protected EntityManager em;

    public SomeEventListener(@CurrentSession EntityManager em) {
        this.em = em;
    }


    @Transactional
    @EventListener
    @Async
    onSomeEvent(SomeEvent event) {
        // Do something with event..
    }
}

But micronaut could not create Hibernate session.

01:10:05.017 [pool-1-thread-3] ERROR i.micronaut.scheduling.TaskExecutors - Error occurred executing @Async method [void onSomeEvent(SomeEvent event)]: Error instantiating bean of type [org.hibernate.Session]: Could not obtain transaction-synchronized Session for current thread
1 Answers

You can solve the problem by injecting into the listener a service which already has the entitymanager injected and do the real job:

    @Singleton
    public class DoTheJobService {

         protected EntityManager em;

         public DoTheJobService(@CurrentSession EntityManager em) {
            this.em = em;
         }

         public void doTheJob(Integer id) {
            // Do something with database
         }
    }

And call from the listener:

   @Singleton
   public class SomeEventListener {

       protected DoTheJobService svc;

       public SomeEventListener(DoTheJobService s) {
          this.svc = s;
       }

       @Transactional
       @EventListener
       @Async
       void onSomeEvent(SomeEvent event) {
          svc.doTheJob(event.id);
       }
   }
Related