skip to Main Content

I have a non-Spring application. I want to make an aspect or something like that which should do the code below before and after to make my method or class transactional like Spring’s @Transactional annotation;

Before;

EntityManagerFactory emf = Persistence
        .createEntityManagerFactory("AdvancedMapping");

/* Create EntityManager */
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();

transaction.begin();

After;

transaction.commit();
em.close();

How can I do this? Where can I find similar tutorials or examples for it?

EDIT:
By the way, it is needed to have em inside of the method which has @Transactional.

@Transactional
private int doSomething(String text) {
    // Here I should have the "em" which was already taken in the aspect, 
    // so I can persist something in text
    SomeEntityObject seo = new SomeEntityObject();
    seo.setText(text);
    em.persist(seo);
}

2

Answers


  1. Just use AspectJ. You find tutorials and other documentation here. If you build your project with Maven you want to use the AspectJ Maven plugin so as to simplify and automate aspect compilation and weaving.

    A little example:

    Marker annotation:

    package de.scrum_master.app;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Transactional {
        String value();
    }
    

    Driver application:

    package de.scrum_master.app;
    
    public class Application {
        public static void main(String[] args) {
            Application application = new Application();
            application.doSomething("foo");
            application.doSomethingElse(11);
            application.doSomething("bar");
            application.doSomethingElse(22);
        }
    
        @Transactional("please wrap me")
        public int doSomething(String text) {
            System.out.println("Doing something with '" + text + "'");
            return 42;
        }
    
        public void doSomethingElse(int number) {
            System.out.println("Doing something else with number " + number);
        }
    }
    

    Transaction wrapper aspect:

    package de.scrum_master.aspect;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    import de.scrum_master.app.Transactional;
    
    @Aspect
    public class TransactionalAspect {
        @Around("execution(* *(..)) && @annotation(transactional)")
        public Object wrapWithTransaction(ProceedingJoinPoint thisJoinPoint, Transactional transactional) throws Throwable {
            System.out.println(thisJoinPoint + " -> " + transactional);
    //        EntityManagerFactory emf = Persistence.createEntityManagerFactory("AdvancedMapping");
    //        EntityManager em = emf.createEntityManager();
    //        EntityTransaction transaction = em.getTransaction();
            try {
                Object result = thisJoinPoint.proceed();
    //            transaction.commit();
                return result;
            }
            catch (Exception e) {
    //            transaction.rollback();
                throw e;
            }
            finally {
    //            em.close();
            }
        }
    }
    

    Console log with JPA stuff commented out:

    execution(int de.scrum_master.app.Application.doSomething(String)) -> @de.scrum_master.app.Transactional(value=please wrap me)
    Doing something with 'foo'
    Doing something else with number 11
    execution(int de.scrum_master.app.Application.doSomething(String)) -> @de.scrum_master.app.Transactional(value=please wrap me)
    Doing something with 'bar'
    Doing something else with number 22
    
    Login or Signup to reply.
  2. I am adding another answer beside my original one because there seems to be an alternative to rebuilding @Transactional from scratch via AspectJ just so as to avoid using the Spring container:

    Actually, declarative transaction support for Spring already is an AspectJ aspect. The Spring manual describes how to use @Transactional with AspectJ without the Spring container. You do not even need Spring XML configuration but can inject the transaction manager directly into the aspect (code snippet quoted from the manual):

    // construct an appropriate transaction manager
    DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());
    
    // configure the AnnotationTransactionAspect to use it;
    // this must be done before executing any transactional methods
    AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search