diff --git a/pom.xml b/pom.xml
index 49893e7..431d066 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,6 +75,18 @@
1.0.1
amp
+
+ javax.transaction
+ javax.transaction-api
+ 1.3
+ provided
+
+
+ jakarta.transaction
+ jakarta.transaction-api
+ 2.0.1
+ provided
+
diff --git a/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java b/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java
deleted file mode 100644
index 41f0397..0000000
--- a/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.inteligr8.alfresco.annotations;
-
-import java.lang.reflect.Method;
-
-import org.springframework.transaction.annotation.Isolation;
-import org.springframework.transaction.annotation.Propagation;
-import org.springframework.transaction.annotation.Transactional;
-
-public class TransactionalWrapper {
-
- private Transactional stxl = null;
- private javax.transaction.Transactional jtxl = null;
-
- public TransactionalWrapper(Transactional txl) {
- this.stxl = txl;
- }
-
- public TransactionalWrapper(javax.transaction.Transactional txl) {
- this.jtxl = txl;
- }
-
- public static TransactionalWrapper wrap(Method method) {
- Transactional stxl = method.getAnnotation(Transactional.class);
- javax.transaction.Transactional jtxl = method.getAnnotation(javax.transaction.Transactional.class);
- if (stxl == null && jtxl == null) {
- return null;
- } else if (stxl != null) {
- return new TransactionalWrapper(stxl);
- } else if (jtxl != null) {
- return new TransactionalWrapper(jtxl);
- } else {
- throw new IllegalStateException("This should never happen");
- }
- }
-
- public boolean isReadOnly() {
- if (this.stxl != null) {
- return this.stxl.readOnly();
- } else if (this.jtxl != null) {
- return false;
- } else {
- throw new IllegalStateException("This should never happen");
- }
- }
-
- public Propagation getPropagation() {
- if (this.stxl != null) {
- return this.stxl.propagation();
- } else if (this.jtxl != null) {
- switch (this.jtxl.value()) {
- case MANDATORY:
- return Propagation.MANDATORY;
- case REQUIRED:
- return Propagation.REQUIRED;
- case REQUIRES_NEW:
- return Propagation.REQUIRES_NEW;
- case SUPPORTS:
- return Propagation.SUPPORTS;
- case NOT_SUPPORTED:
- return Propagation.NOT_SUPPORTED;
- case NEVER:
- return Propagation.NEVER;
- default:
- throw new IllegalStateException("This should never happen");
- }
- } else {
- throw new IllegalStateException("This should never happen");
- }
- }
-
- public Isolation getIsolation() {
- if (this.stxl != null) {
- return this.stxl.isolation();
- } else if (this.jtxl != null) {
- return Isolation.DEFAULT;
- } else {
- throw new IllegalStateException("This should never happen");
- }
- }
-
- public int getTimeoutInSeconds() {
- if (this.stxl != null) {
- return this.stxl.timeout();
- } else if (this.jtxl != null) {
- return 0;
- } else {
- throw new IllegalStateException("This should never happen");
- }
- }
-
- @SuppressWarnings("unchecked")
- public Class extends Throwable>[] getRollbackFor() {
- if (this.stxl != null) {
- return this.stxl.rollbackFor();
- } else if (this.jtxl != null) {
- return this.jtxl.rollbackOn();
- } else {
- throw new IllegalStateException("This should never happen");
- }
- }
-
- @SuppressWarnings("unchecked")
- public Class extends Throwable>[] getNoRollbackFor() {
- if (this.stxl != null) {
- return this.stxl.noRollbackFor();
- } else if (this.jtxl != null) {
- return this.jtxl.dontRollbackOn();
- } else {
- throw new IllegalStateException("This should never happen");
- }
- }
-
-}
diff --git a/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java b/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java
index 820c0c9..1be4758 100644
--- a/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java
+++ b/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java
@@ -1,5 +1,6 @@
package com.inteligr8.alfresco.annotations.aspect;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
@@ -17,9 +18,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.IllegalTransactionStateException;
+import org.springframework.transaction.annotation.Transactional;
import com.inteligr8.alfresco.annotations.TransactionalRetryable;
-import com.inteligr8.alfresco.annotations.TransactionalWrapper;
+import com.inteligr8.alfresco.annotations.util.JakartaTransactionalAnnotationAdapter;
+import com.inteligr8.alfresco.annotations.util.JtaTransactionalAnnotationAdapter;
+import com.inteligr8.alfresco.annotations.util.SpringTransactionalAnnotationAdapter;
+import com.inteligr8.alfresco.annotations.util.TransactionalAnnotationAdapter;
/**
* This aspect implements the @Transactional and @TransactionalRetryable
@@ -54,16 +59,20 @@ public class RetryingTransactionAspect {
public void isJtaTransactionalAnnotated() {
}
+ @Pointcut("@annotation(jakarta.transaction.Transactional) && execution(* *(..))")
+ public void isJakartaTransactionalAnnotated() {
+ }
+
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.TransactionalRetryable) && execution(* *(..))")
public void isTransactionalRetryableAnnotated() {
}
- @Around("isTransactionalAnnotated() || isJtaTransactionalAnnotated() || isTransactionalRetryableAnnotated()")
+ @Around("isTransactionalAnnotated() || isJtaTransactionalAnnotated() || isJakartaTransactionalAnnotated() || isTransactionalRetryableAnnotated()")
public Object retryingTransactional(ProceedingJoinPoint joinPoint) throws Throwable {
this.logger.trace("retryingTransactional({})", joinPoint);
Method method = this.getMethod(joinPoint);
- TransactionalWrapper txl = TransactionalWrapper.wrap(method);
+ TransactionalAnnotationAdapter txl = this.wrapTransactionalAnnotation(method);
TransactionalRetryable txtry = method.getAnnotation(TransactionalRetryable.class);
if (this.doCreateNewTxContext(txl) || this.isReadStateChange(txl)) {
@@ -77,6 +86,33 @@ public class RetryingTransactionAspect {
}
}
+ private TransactionalAnnotationAdapter wrapTransactionalAnnotation(Method method) {
+ Annotation txl = method.getAnnotation(Transactional.class);
+ if (txl != null)
+ return new SpringTransactionalAnnotationAdapter((Transactional) txl);
+
+ txl = this.getOptionalAnnotation(method, "javax.transaction.Transactional");
+ if (txl != null)
+ return new JtaTransactionalAnnotationAdapter((javax.transaction.Transactional) txl);
+
+ txl = this.getOptionalAnnotation(method, "jakarta.transaction.Transactional");
+ if (txl != null)
+ return new JakartaTransactionalAnnotationAdapter((jakarta.transaction.Transactional) txl);
+
+ return null;
+ }
+
+ private A getOptionalAnnotation(Method method, String fullyQualifiedAnnotationName) {
+ try {
+ @SuppressWarnings("unchecked")
+ Class annotationClass = (Class) Class.forName(fullyQualifiedAnnotationName);
+ return method.getAnnotation(annotationClass);
+ } catch (ClassNotFoundException cnfe) {
+ this.logger.trace("The {} annotation is not available in the classpath; assuming not set", fullyQualifiedAnnotationName);
+ return null;
+ }
+ }
+
private Method getMethod(ProceedingJoinPoint joinPoint) {
if (!(joinPoint.getSignature() instanceof MethodSignature))
throw new IllegalStateException("The @Transactional or @TransactionalRetryable annotations must be on methods");
@@ -85,7 +121,7 @@ public class RetryingTransactionAspect {
return methodSig.getMethod();
}
- private boolean isReadStateChange(TransactionalWrapper txl) {
+ private boolean isReadStateChange(TransactionalAnnotationAdapter txl) {
if (txl == null)
return false;
@@ -114,7 +150,7 @@ public class RetryingTransactionAspect {
return txtry != null;
}
- private boolean doCreateNewTxContext(TransactionalWrapper txl) {
+ private boolean doCreateNewTxContext(TransactionalAnnotationAdapter txl) {
if (txl == null) {
return false;
} else switch (txl.getPropagation()) {
@@ -159,7 +195,7 @@ public class RetryingTransactionAspect {
}
}
- private Object execute(final ProceedingJoinPoint joinPoint, TransactionalWrapper txl, TransactionalRetryable txtry) throws Throwable {
+ private Object execute(final ProceedingJoinPoint joinPoint, TransactionalAnnotationAdapter txl, TransactionalRetryable txtry) throws Throwable {
RetryingTransactionCallback