Introduce resolvable timeout attribute on @Transactional and <tx:method>
Placeholders get resolved in timeoutString, qualifier and labels now. Closes gh-25052
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -30,6 +30,8 @@ import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
|
||||
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.StringUtils;
|
||||
|
||||
/**
|
||||
* Strategy implementation for parsing Spring's {@link Transactional} annotation.
|
||||
@@ -70,7 +72,13 @@ public class SpringTransactionAnnotationParser implements TransactionAnnotationP
|
||||
rbta.setPropagationBehavior(propagation.value());
|
||||
Isolation isolation = attributes.getEnum("isolation");
|
||||
rbta.setIsolationLevel(isolation.value());
|
||||
|
||||
rbta.setTimeout(attributes.getNumber("timeout").intValue());
|
||||
String timeoutString = attributes.getString("timeoutString");
|
||||
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
|
||||
"Specify 'timeout' or 'timeoutString', not both");
|
||||
rbta.setTimeoutString(timeoutString);
|
||||
|
||||
rbta.setReadOnly(attributes.getBoolean("readOnly"));
|
||||
rbta.setQualifier(attributes.getString("value"));
|
||||
rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
|
||||
|
||||
@@ -84,6 +84,18 @@ public @interface Transactional {
|
||||
@AliasFor("value")
|
||||
String transactionManager() default "";
|
||||
|
||||
/**
|
||||
* Defines zero (0) or more transaction labels. Labels may be used to
|
||||
* describe a transaction and they can be evaluated by individual transaction
|
||||
* manager. Labels may serve a solely descriptive purpose or map to
|
||||
* pre-defined transaction manager-specific options.
|
||||
* <p>See the description of the actual transaction manager implementation
|
||||
* how it evaluates transaction labels.
|
||||
* @since 5.3
|
||||
* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#getLabels()
|
||||
*/
|
||||
String[] label() default {};
|
||||
|
||||
/**
|
||||
* The transaction propagation type.
|
||||
* <p>Defaults to {@link Propagation#REQUIRED}.
|
||||
@@ -111,10 +123,23 @@ public @interface Transactional {
|
||||
* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
|
||||
* {@link Propagation#REQUIRES_NEW} since it only applies to newly started
|
||||
* transactions.
|
||||
* @return the timeout in seconds
|
||||
* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
|
||||
*/
|
||||
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
|
||||
|
||||
/**
|
||||
* The timeout for this transaction (in seconds).
|
||||
* <p>Defaults to the default timeout of the underlying transaction system.
|
||||
* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
|
||||
* {@link Propagation#REQUIRES_NEW} since it only applies to newly started
|
||||
* transactions.
|
||||
* @return the timeout in seconds as a String value, e.g. a placeholder
|
||||
* @since 5.3
|
||||
* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
|
||||
*/
|
||||
String timeoutString() default "";
|
||||
|
||||
/**
|
||||
* A boolean flag that can be set to {@code true} if the transaction is
|
||||
* effectively read-only, allowing for corresponding optimizations at runtime.
|
||||
@@ -190,17 +215,4 @@ public @interface Transactional {
|
||||
*/
|
||||
String[] noRollbackForClassName() default {};
|
||||
|
||||
/**
|
||||
* Defines zero (0) or more transaction labels. Labels may be used to
|
||||
* describe a transaction and they can be evaluated by individual transaction
|
||||
* manager. Labels may serve a solely descriptive purpose or map to
|
||||
* pre-defined transaction manager-specific options.
|
||||
* <p>See the description of the actual transaction manager implementation
|
||||
* how it evaluates transaction labels.
|
||||
*
|
||||
* @since 5.3
|
||||
* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#getLabels()
|
||||
*/
|
||||
String[] label() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -116,12 +116,7 @@ class TxAdviceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
attribute.setIsolationLevelName(RuleBasedTransactionAttribute.PREFIX_ISOLATION + isolation);
|
||||
}
|
||||
if (StringUtils.hasText(timeout)) {
|
||||
try {
|
||||
attribute.setTimeout(Integer.parseInt(timeout));
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
parserContext.getReaderContext().error("Timeout must be an integer value: [" + timeout + "]", methodEle);
|
||||
}
|
||||
attribute.setTimeoutString(timeout);
|
||||
}
|
||||
if (StringUtils.hasText(readOnly)) {
|
||||
attribute.setReadOnly(Boolean.parseBoolean(methodEle.getAttribute(READ_ONLY_ATTRIBUTE)));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -25,9 +25,11 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.core.MethodClassKey;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* Abstract implementation of {@link TransactionAttributeSource} that caches
|
||||
@@ -49,7 +51,8 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
*/
|
||||
public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {
|
||||
public abstract class AbstractFallbackTransactionAttributeSource
|
||||
implements TransactionAttributeSource, EmbeddedValueResolverAware {
|
||||
|
||||
/**
|
||||
* Canonical value held in cache to indicate no transaction attribute was
|
||||
@@ -71,6 +74,9 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
|
||||
*/
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@Nullable
|
||||
private transient StringValueResolver embeddedValueResolver;
|
||||
|
||||
/**
|
||||
* Cache of TransactionAttributes, keyed by method on a specific target class.
|
||||
* <p>As this base class is not marked Serializable, the cache will be recreated
|
||||
@@ -79,6 +85,12 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
|
||||
private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);
|
||||
|
||||
|
||||
@Override
|
||||
public void setEmbeddedValueResolver(StringValueResolver resolver) {
|
||||
this.embeddedValueResolver = resolver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the transaction attribute for this method invocation.
|
||||
* <p>Defaults to the class's transaction attribute if no method attribute is found.
|
||||
@@ -117,7 +129,9 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
|
||||
else {
|
||||
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
|
||||
if (txAttr instanceof DefaultTransactionAttribute) {
|
||||
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
|
||||
DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr;
|
||||
dta.setDescriptor(methodIdentification);
|
||||
dta.resolveAttributeStrings(this.embeddedValueResolver);
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -18,10 +18,13 @@ package org.springframework.transaction.interceptor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* Spring's common transaction attribute implementation.
|
||||
@@ -36,10 +39,13 @@ import org.springframework.util.StringUtils;
|
||||
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
|
||||
|
||||
@Nullable
|
||||
private String qualifier;
|
||||
private String descriptor;
|
||||
|
||||
@Nullable
|
||||
private String descriptor;
|
||||
private String timeoutString;
|
||||
|
||||
@Nullable
|
||||
private String qualifier;
|
||||
|
||||
private Collection<String> labels = Collections.emptyList();
|
||||
|
||||
@@ -83,11 +89,54 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a descriptor for this transaction attribute,
|
||||
* e.g. indicating where the attribute is applying.
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public void setDescriptor(@Nullable String descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a descriptor for this transaction attribute,
|
||||
* or {@code null} if none.
|
||||
* @since 4.3.4
|
||||
*/
|
||||
@Nullable
|
||||
public String getDescriptor() {
|
||||
return this.descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timeout to apply, if any,
|
||||
* as a String value that resolves to a number of seconds.
|
||||
* @since 5.3
|
||||
* @see #setTimeout
|
||||
* @see #resolveAttributeStrings
|
||||
*/
|
||||
public void setTimeoutString(@Nullable String timeoutString) {
|
||||
this.timeoutString = timeoutString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the timeout to apply, if any,
|
||||
* as a String value that resolves to a number of seconds.
|
||||
* @since 5.3
|
||||
* @see #getTimeout
|
||||
* @see #resolveAttributeStrings
|
||||
*/
|
||||
@Nullable
|
||||
public String getTimeoutString() {
|
||||
return this.timeoutString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a qualifier value with this transaction attribute.
|
||||
* <p>This may be used for choosing a corresponding transaction manager
|
||||
* to process this specific transaction.
|
||||
* @since 3.0
|
||||
* @see #resolveAttributeStrings
|
||||
*/
|
||||
public void setQualifier(@Nullable String qualifier) {
|
||||
this.qualifier = qualifier;
|
||||
@@ -108,6 +157,7 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
|
||||
* <p>This may be used for applying specific transactional behavior
|
||||
* or follow a purely descriptive nature.
|
||||
* @since 5.3
|
||||
* @see #resolveAttributeStrings
|
||||
*/
|
||||
public void setLabels(Collection<String> labels) {
|
||||
this.labels = labels;
|
||||
@@ -118,25 +168,6 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
|
||||
return this.labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a descriptor for this transaction attribute,
|
||||
* e.g. indicating where the attribute is applying.
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public void setDescriptor(@Nullable String descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a descriptor for this transaction attribute,
|
||||
* or {@code null} if none.
|
||||
* @since 4.3.4
|
||||
*/
|
||||
@Nullable
|
||||
public String getDescriptor() {
|
||||
return this.descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default behavior is as with EJB: rollback on unchecked exception
|
||||
* ({@link RuntimeException}), assuming an unexpected outcome outside of any
|
||||
@@ -157,6 +188,42 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve attribute values that are defined as resolvable Strings:
|
||||
* {@link #setTimeoutString}, {@link #setQualifier}, {@link #setLabels}.
|
||||
* This is typically used for resolving "${...}" placeholders.
|
||||
* @param resolver the embedded value resolver to apply, if any
|
||||
* @since 5.3
|
||||
*/
|
||||
public void resolveAttributeStrings(@Nullable StringValueResolver resolver) {
|
||||
String timeoutString = this.timeoutString;
|
||||
if (StringUtils.hasText(timeoutString)) {
|
||||
if (resolver != null) {
|
||||
timeoutString = resolver.resolveStringValue(timeoutString);
|
||||
}
|
||||
if (StringUtils.hasLength(timeoutString)) {
|
||||
try {
|
||||
setTimeout(Integer.parseInt(timeoutString));
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid timeoutString value \"" + timeoutString + "\" - cannot parse into int");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resolver != null) {
|
||||
if (this.qualifier != null) {
|
||||
this.qualifier = resolver.resolveStringValue(this.qualifier);
|
||||
}
|
||||
Set<String> resolvedLabels = new LinkedHashSet<>(this.labels.size());
|
||||
for (String label : this.labels) {
|
||||
resolvedLabels.add(resolver.resolveStringValue(label));
|
||||
}
|
||||
this.labels = resolvedLabels;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an identifying description for this transaction attribute.
|
||||
* <p>Available to subclasses, for inclusion in their {@code toString()} result.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* methods being handled by a transaction interceptor.
|
||||
*
|
||||
* @author Colin Sampaleanu
|
||||
* @author Juergen Hoeller
|
||||
* @since 15.10.2003
|
||||
* @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean
|
||||
* @see org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
|
||||
@@ -48,6 +49,9 @@ public class MatchAlwaysTransactionAttributeSource implements TransactionAttribu
|
||||
* @see org.springframework.transaction.interceptor.TransactionAttributeEditor
|
||||
*/
|
||||
public void setTransactionAttribute(TransactionAttribute transactionAttribute) {
|
||||
if (transactionAttribute instanceof DefaultTransactionAttribute) {
|
||||
((DefaultTransactionAttribute) transactionAttribute).resolveAttributeStrings(null);
|
||||
}
|
||||
this.transactionAttribute = transactionAttribute;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -27,11 +27,13 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* Simple {@link TransactionAttributeSource} implementation that
|
||||
@@ -44,7 +46,7 @@ import org.springframework.util.PatternMatchUtils;
|
||||
* @see NameMatchTransactionAttributeSource
|
||||
*/
|
||||
public class MethodMapTransactionAttributeSource
|
||||
implements TransactionAttributeSource, BeanClassLoaderAware, InitializingBean {
|
||||
implements TransactionAttributeSource, EmbeddedValueResolverAware, BeanClassLoaderAware, InitializingBean {
|
||||
|
||||
/** Logger available to subclasses. */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
@@ -53,6 +55,9 @@ public class MethodMapTransactionAttributeSource
|
||||
@Nullable
|
||||
private Map<String, TransactionAttribute> methodMap;
|
||||
|
||||
@Nullable
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
@Nullable
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
@@ -83,6 +88,11 @@ public class MethodMapTransactionAttributeSource
|
||||
this.methodMap = methodMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmbeddedValueResolver(StringValueResolver resolver) {
|
||||
this.embeddedValueResolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
@@ -189,6 +199,9 @@ public class MethodMapTransactionAttributeSource
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding transactional method [" + method + "] with attribute [" + attr + "]");
|
||||
}
|
||||
if (this.embeddedValueResolver != null && attr instanceof DefaultTransactionAttribute) {
|
||||
((DefaultTransactionAttribute) attr).resolveAttributeStrings(this.embeddedValueResolver);
|
||||
}
|
||||
this.transactionAttributeMap.put(method, attr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -26,10 +26,13 @@ import java.util.Properties;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* Simple {@link TransactionAttributeSource} implementation that
|
||||
@@ -41,7 +44,8 @@ import org.springframework.util.PatternMatchUtils;
|
||||
* @see MethodMapTransactionAttributeSource
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NameMatchTransactionAttributeSource implements TransactionAttributeSource, Serializable {
|
||||
public class NameMatchTransactionAttributeSource
|
||||
implements TransactionAttributeSource, EmbeddedValueResolverAware, InitializingBean, Serializable {
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
@@ -50,7 +54,10 @@ public class NameMatchTransactionAttributeSource implements TransactionAttribute
|
||||
protected static final Log logger = LogFactory.getLog(NameMatchTransactionAttributeSource.class);
|
||||
|
||||
/** Keys are method names; values are TransactionAttributes. */
|
||||
private Map<String, TransactionAttribute> nameMap = new HashMap<>();
|
||||
private final Map<String, TransactionAttribute> nameMap = new HashMap<>();
|
||||
|
||||
@Nullable
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
|
||||
/**
|
||||
@@ -94,9 +101,26 @@ public class NameMatchTransactionAttributeSource implements TransactionAttribute
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding transactional method [" + methodName + "] with attribute [" + attr + "]");
|
||||
}
|
||||
if (this.embeddedValueResolver != null && attr instanceof DefaultTransactionAttribute) {
|
||||
((DefaultTransactionAttribute) attr).resolveAttributeStrings(this.embeddedValueResolver);
|
||||
}
|
||||
this.nameMap.put(methodName, attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmbeddedValueResolver(StringValueResolver resolver) {
|
||||
this.embeddedValueResolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
for (TransactionAttribute attr : this.nameMap.values()) {
|
||||
if (attr instanceof DefaultTransactionAttribute) {
|
||||
((DefaultTransactionAttribute) attr).resolveAttributeStrings(this.embeddedValueResolver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -69,7 +69,7 @@ public class TransactionAttributeEditor extends PropertyEditorSupport {
|
||||
}
|
||||
else if (trimmedToken.startsWith(RuleBasedTransactionAttribute.PREFIX_TIMEOUT)) {
|
||||
String value = trimmedToken.substring(DefaultTransactionAttribute.PREFIX_TIMEOUT.length());
|
||||
attr.setTimeout(Integer.parseInt(value));
|
||||
attr.setTimeoutString(value);
|
||||
}
|
||||
else if (trimmedToken.equals(RuleBasedTransactionAttribute.READ_ONLY_MARKER)) {
|
||||
attr.setReadOnly(true);
|
||||
@@ -84,6 +84,7 @@ public class TransactionAttributeEditor extends PropertyEditorSupport {
|
||||
throw new IllegalArgumentException("Invalid transaction attribute token: [" + trimmedToken + "]");
|
||||
}
|
||||
}
|
||||
attr.resolveAttributeStrings(null); // placeholders expected to be pre-resolved
|
||||
setValue(attr);
|
||||
}
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user