All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2002-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.transaction.annotation;

import java.io.Serializable;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.lang.Nullable;
import org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;

/**
 * Implementation of the
 * {@link org.springframework.transaction.interceptor.TransactionAttributeSource}
 * interface for working with transaction metadata from annotations.
 *
 * 

This class reads Spring's {@link Transactional @Transactional} annotation and * exposes corresponding transaction attributes to Spring's transaction infrastructure. * Also supports JTA's {@link jakarta.transaction.Transactional} and EJB's * {@link jakarta.ejb.TransactionAttribute} annotation (if present). * *

This class may also serve as base class for a custom TransactionAttributeSource, * or get customized through {@link TransactionAnnotationParser} strategies. * * @author Colin Sampaleanu * @author Juergen Hoeller * @since 1.2 * @see Transactional * @see TransactionAnnotationParser * @see SpringTransactionAnnotationParser * @see Ejb3TransactionAnnotationParser * @see org.springframework.transaction.interceptor.TransactionInterceptor#setTransactionAttributeSource * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean#setTransactionAttributeSource */ @SuppressWarnings("serial") public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource implements Serializable { private static final boolean jtaPresent; private static final boolean ejb3Present; static { ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader(); jtaPresent = ClassUtils.isPresent("jakarta.transaction.Transactional", classLoader); ejb3Present = ClassUtils.isPresent("jakarta.ejb.TransactionAttribute", classLoader); } private final Set annotationParsers; private boolean publicMethodsOnly = true; @Nullable private Set defaultRollbackRules; /** * Create a default AnnotationTransactionAttributeSource, supporting * public methods that carry the {@code Transactional} annotation * or the EJB3 {@link jakarta.ejb.TransactionAttribute} annotation. */ public AnnotationTransactionAttributeSource() { if (jtaPresent || ejb3Present) { this.annotationParsers = CollectionUtils.newLinkedHashSet(3); this.annotationParsers.add(new SpringTransactionAnnotationParser()); if (jtaPresent) { this.annotationParsers.add(new JtaTransactionAnnotationParser()); } if (ejb3Present) { this.annotationParsers.add(new Ejb3TransactionAnnotationParser()); } } else { this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser()); } } /** * Create a custom AnnotationTransactionAttributeSource, supporting * public methods that carry the {@code Transactional} annotation * or the EJB3 {@link jakarta.ejb.TransactionAttribute} annotation. * @param publicMethodsOnly whether to support public methods that carry * the {@code Transactional} annotation only (typically for use * with proxy-based AOP), or protected/private methods as well * (typically used with AspectJ class weaving) * @see #setPublicMethodsOnly */ public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) { this(); this.publicMethodsOnly = publicMethodsOnly; } /** * Create a custom AnnotationTransactionAttributeSource. * @param annotationParser the TransactionAnnotationParser to use */ public AnnotationTransactionAttributeSource(TransactionAnnotationParser annotationParser) { Assert.notNull(annotationParser, "TransactionAnnotationParser must not be null"); this.annotationParsers = Collections.singleton(annotationParser); } /** * Create a custom AnnotationTransactionAttributeSource. * @param annotationParsers the TransactionAnnotationParsers to use */ public AnnotationTransactionAttributeSource(TransactionAnnotationParser... annotationParsers) { Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified"); this.annotationParsers = Set.of(annotationParsers); } /** * Set whether transactional methods are expected to be public. *

The default is {@code true}. * @since 6.2 * @see #AnnotationTransactionAttributeSource(boolean) */ public void setPublicMethodsOnly(boolean publicMethodsOnly) { this.publicMethodsOnly = publicMethodsOnly; } /** * Add a default rollback rule, to be applied to all rule-based * transaction attributes returned by this source. *

By default, a rollback will be triggered on unchecked exceptions * but not on checked exceptions. A default rule may override this * while still respecting any custom rules in the transaction attribute. * @param rollbackRule a rollback rule overriding the default behavior, * for example, {@link RollbackRuleAttribute#ROLLBACK_ON_ALL_EXCEPTIONS} * @since 6.2 * @see RuleBasedTransactionAttribute#getRollbackRules() * @see EnableTransactionManagement#rollbackOn() * @see Transactional#rollbackFor() * @see Transactional#noRollbackFor() */ public void addDefaultRollbackRule(RollbackRuleAttribute rollbackRule) { if (this.defaultRollbackRules == null) { this.defaultRollbackRules = new LinkedHashSet<>(); } this.defaultRollbackRules.add(rollbackRule); } @Override public boolean isCandidateClass(Class targetClass) { for (TransactionAnnotationParser parser : this.annotationParsers) { if (parser.isCandidateClass(targetClass)) { return true; } } return false; } @Override @Nullable protected TransactionAttribute findTransactionAttribute(Class clazz) { return determineTransactionAttribute(clazz); } @Override @Nullable protected TransactionAttribute findTransactionAttribute(Method method) { return determineTransactionAttribute(method); } /** * Determine the transaction attribute for the given method or class. *

This implementation delegates to configured * {@link TransactionAnnotationParser TransactionAnnotationParsers} * for parsing known annotations into Spring's metadata attribute class. * Returns {@code null} if it's not transactional. *

Can be overridden to support custom annotations that carry transaction metadata. * @param element the annotated method or class * @return the configured transaction attribute, or {@code null} if none was found */ @Nullable protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { for (TransactionAnnotationParser parser : this.annotationParsers) { TransactionAttribute attr = parser.parseTransactionAnnotation(element); if (attr != null) { if (this.defaultRollbackRules != null && attr instanceof RuleBasedTransactionAttribute ruleAttr) { ruleAttr.getRollbackRules().addAll(this.defaultRollbackRules); } return attr; } } return null; } /** * By default, only public methods can be made transactional. * @see #setPublicMethodsOnly */ @Override protected boolean allowPublicMethodsOnly() { return this.publicMethodsOnly; } @Override public boolean equals(@Nullable Object other) { return (this == other || (other instanceof AnnotationTransactionAttributeSource otherTas && this.annotationParsers.equals(otherTas.annotationParsers) && this.publicMethodsOnly == otherTas.publicMethodsOnly)); } @Override public int hashCode() { return this.annotationParsers.hashCode(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy