Skip to content

Commit 8364fb2

Browse files
committed
Fix isGetterOrSetter from incorrectly returning true for methods that start with set that aren't setters, Ex: setupData. Apply transactional behavior to getter methods when a setter is not found. Fixes apache/grails-data-mapping#1013 for GORM 6.0.x
1 parent d9444e3 commit 8364fb2

File tree

3 files changed

+116
-15
lines changed

3 files changed

+116
-15
lines changed

grails-core/src/main/groovy/org/grails/compiler/injection/GrailsASTUtils.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,19 +1457,25 @@ public static void processVariableScopes(SourceUnit source, ClassNode classNode,
14571457
scopeVisitor.visitMethod(methodNode);
14581458
}
14591459
}
1460-
1461-
public static boolean isSetterOrGetterMethod(MethodNode md) {
1460+
1461+
public static boolean isGetterMethod(MethodNode md) {
14621462
String methodName = md.getName();
1463-
1464-
if((methodName.startsWith("set") && methodName.length() > 3) && md.getParameters() != null && md.getParameters().length == 1) {
1465-
return true;
1466-
}
1467-
1468-
if(((methodName.startsWith("get") && methodName.length() > 3) || (methodName.startsWith("is") && methodName.length() > 2)) && (md.getParameters()==null || md.getParameters().length == 0)) {
1469-
return true;
1470-
}
1471-
1472-
return false;
1463+
1464+
return (((methodName.startsWith("get") && methodName.length() > 3) || (methodName.startsWith("is") && methodName.length() > 2)) && (md.getParameters()==null || md.getParameters().length == 0));
1465+
}
1466+
1467+
public static boolean isSetterMethod(MethodNode md) {
1468+
String methodName = md.getName();
1469+
1470+
return ((methodName.startsWith("set") &&
1471+
methodName.length() > 3) &&
1472+
Character.isUpperCase(methodName.substring(3).charAt(0)) &&
1473+
md.getParameters() != null &&
1474+
md.getParameters().length == 1);
1475+
}
1476+
1477+
public static boolean isSetterOrGetterMethod(MethodNode md) {
1478+
return isGetterMethod(md) || isSetterMethod(md);
14731479
}
14741480

14751481
/**

grails-core/src/main/groovy/org/grails/transaction/transform/TransactionalTransform.groovy

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package org.grails.transaction.transform
1818

1919
import grails.compiler.DelegatingMethod
2020
import grails.transaction.Rollback
21+
import grails.util.GrailsClassUtils
22+
import grails.util.GrailsNameUtils
2123
import groovy.transform.TypeChecked
2224
import org.codehaus.groovy.ast.stmt.Statement
2325
import org.codehaus.groovy.ast.tools.GenericsUtils
@@ -114,7 +116,17 @@ class TransactionalTransform implements ASTTransformation{
114116
public void weaveTransactionalBehavior(SourceUnit source, ClassNode classNode, AnnotationNode annotationNode) {
115117
weaveTransactionManagerAware(source, classNode)
116118
List<MethodNode> methods = new ArrayList<MethodNode>(classNode.getMethods());
117-
119+
120+
List<String> setterMethodNames = []
121+
Iterator<MethodNode> methodNodeIterator = methods.iterator()
122+
while (methodNodeIterator.hasNext()) {
123+
MethodNode md = methodNodeIterator.next()
124+
if (isSetterMethod(md)) {
125+
setterMethodNames.add(md.name)
126+
methodNodeIterator.remove()
127+
}
128+
}
129+
118130
for (MethodNode md in methods) {
119131
String methodName = md.getName()
120132
int modifiers = md.modifiers
@@ -132,8 +144,15 @@ class TransactionalTransform implements ASTTransformation{
132144
}
133145

134146
if(METHOD_NAME_EXCLUDES.contains(methodName)) continue
135-
136-
if(isSetterOrGetterMethod(md)) continue
147+
148+
if (isGetterMethod(md)) {
149+
final String propertyName = GrailsClassUtils.getPropertyForGetter(md.name, md.returnType.typeClass)
150+
final String setterName = GrailsNameUtils.getSetterName(propertyName)
151+
152+
//If a setter exists for the getter, don't apply the transformation
153+
if (setterMethodNames.contains(setterName)) continue
154+
}
155+
137156

138157
// don't apply to methods added by traits
139158
if(hasAnnotation(md, org.codehaus.groovy.transform.trait.Traits.TraitBridge.class)) continue

grails-core/src/test/groovy/grails/transaction/TransactionalTransformSpec.groovy

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,83 @@ class SomeClass {
906906
ex.message.contains 'Cannot find matching method java.lang.String#lastName()'
907907

908908
}
909+
910+
911+
void "test transactional behavior is applied to getter methods without a setter"() {
912+
given:
913+
def someClass = new GroovyShell().evaluate('''
914+
package demo
915+
916+
@grails.transaction.Transactional
917+
class SomeClass {
918+
919+
public void setAge(String name) {
920+
921+
}
922+
923+
public String getAge() {
924+
'valid'
925+
}
926+
927+
public String getPhone() {
928+
'valid'
929+
}
909930
}
931+
932+
new SomeClass()
933+
''')
934+
935+
final transactionManager = getPlatformTransactionManager()
936+
someClass.transactionManager = transactionManager
937+
938+
when:
939+
someClass.setAge('x')
940+
941+
then:
942+
transactionManager.transactionStarted == false
943+
944+
when:
945+
someClass.getAge()
946+
947+
then:
948+
transactionManager.transactionStarted == false
949+
950+
when:
951+
someClass.getPhone()
952+
953+
then:
954+
transactionManager.transactionStarted == true
955+
}
956+
957+
void "test transactional behavior is applied to methods that aren't setters but start with set"() {
958+
given:
959+
def someClass = new GroovyShell().evaluate('''
960+
package demo
961+
962+
963+
@grails.transaction.Transactional
964+
class SomeClass {
965+
966+
public void setupSessionAfterLogin(String username) {
967+
}
968+
969+
}
970+
971+
new SomeClass()
972+
''')
973+
974+
final transactionManager = getPlatformTransactionManager()
975+
someClass.transactionManager = transactionManager
976+
977+
when:
978+
someClass.setupSessionAfterLogin()
979+
980+
then:
981+
transactionManager.transactionStarted == true
982+
}
983+
}
984+
985+
910986
@Transactional
911987
class TransactionalTransformSpecService implements InitializingBean {
912988
String name

0 commit comments

Comments
 (0)