package org.carlspring.strongbox.data.tx; import java.util.Collection; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.carlspring.strongbox.data.domain.GenericEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionInterceptor; import com.orientechnologies.orient.object.db.OObjectDatabaseTx; @Aspect @Component @Order(OEntityUnproxyAspect.ORDER) public class OEntityUnproxyAspect { public static final int ORDER = 110; private static final Logger logger = LoggerFactory.getLogger(OEntityUnproxyAspect.class); @PersistenceContext private EntityManager entityManager; /** * This method will wrap "Top level" transactional invocations according to rules defined with pointcut expressions. * "Top level" means the methods, declared with {@link Transactional}, where the new Transaction has started and * will be ended after method invocation complete. * The goal is to get unproxied value, which has been returned with intercepted (target) method. * The order of calling the interceptor is important, for this reason the class is declared with {@link Order} annotation. * The order must be before the {@link TransactionInterceptor}. * * @param jp * @return * @throws Throwable */ @Around("execution(@org.springframework.transaction.annotation.Transactional * *(..)) " + "|| (execution(public * ((@org.springframework.transaction.annotation.Transactional *)+).*(..)) " + "&& within(@org.springframework.transaction.annotation.Transactional *))) " + "&& !cflowbelow(execution(* OEntityUnproxyAspect.*(..)) ") public Object transactional(ProceedingJoinPoint jp) throws Throwable { logger.debug("Transactional metod execution start."); Object result = jp.proceed(); logger.debug("Transactional metod execution end."); return unproxy(result); } private Object unproxy(Object result) { if (result == null) { return null; } if (result instanceof GenericEntity) { result = ((OObjectDatabaseTx) entityManager.getDelegate()).detachAll(result, true); } else if (result instanceof Collection) { result = ((Collection) result).stream() .map(e -> unproxy(e)) .collect(result instanceof Set ? Collectors.toSet() : Collectors.toList()); } else if (result instanceof Optional) { result = Optional.ofNullable(unproxy(((Optional) result).orElse(null))); } return result; } }