Skip to content

Commit dba8dbf

Browse files
authored
Fix bug with traits with @action that take parameters (#10126)
* Fix bug with traits with @action that take parameters not working correctly when implemented by controllers * Make code more readable * Move method to GrailsAstUtils
2 parents c043013 + ede8670 commit dba8dbf

File tree

3 files changed

+56
-10
lines changed

3 files changed

+56
-10
lines changed

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.codehaus.groovy.syntax.Token;
3838
import org.codehaus.groovy.syntax.Types;
3939
import org.codehaus.groovy.transform.sc.StaticCompileTransformation;
40+
import org.codehaus.groovy.transform.trait.Traits;
4041
import org.grails.io.support.FileSystemResource;
4142
import org.grails.io.support.Resource;
4243
import org.springframework.util.StringUtils;
@@ -968,6 +969,16 @@ public static boolean hasAnyAnnotations(final ClassNode classNode, final Class<?
968969
return false;
969970
}
970971

972+
public static boolean removeAnnotation(final MethodNode methodNode, final Class<? extends Annotation> annotationClass) {
973+
List<AnnotationNode> annotations = methodNode.getAnnotations(new ClassNode(annotationClass));
974+
if (annotations.size() > 0) {
975+
methodNode.getAnnotations().removeAll(annotations);
976+
return true;
977+
} else {
978+
return false;
979+
}
980+
}
981+
971982
public static void addMethodIfNotPresent(ClassNode controllerClassNode, MethodNode methodNode) {
972983
MethodNode existing = controllerClassNode.getMethod(methodNode.getName(), methodNode.getParameters());
973984
if (existing == null) {
@@ -1488,4 +1499,12 @@ public static URL getSourceUrl(SourceUnit source) {
14881499
public static URL getSourceUrl(ClassNode classNode) {
14891500
return getSourceUrl(classNode.getModule().getContext());
14901501
}
1502+
1503+
public static boolean hasParameters(MethodNode methodNode) {
1504+
return methodNode.getParameters().length > 0;
1505+
}
1506+
1507+
public static boolean isInheritedFromTrait(MethodNode methodNode) {
1508+
return hasAnnotation(methodNode, Traits.TraitBridge.class);
1509+
}
14911510
}

grails-plugin-controllers/src/main/groovy/org/grails/compiler/web/ControllerActionTransformer.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
import static org.grails.compiler.injection.GrailsASTUtils.buildGetMapExpression;
2121
import static org.grails.compiler.injection.GrailsASTUtils.buildGetPropertyExpression;
2222
import static org.grails.compiler.injection.GrailsASTUtils.buildSetPropertyExpression;
23+
import static org.grails.compiler.injection.GrailsASTUtils.hasAnnotation;
24+
import static org.grails.compiler.injection.GrailsASTUtils.hasParameters;
25+
import static org.grails.compiler.injection.GrailsASTUtils.removeAnnotation;
26+
import static org.grails.compiler.injection.GrailsASTUtils.isInheritedFromTrait;
2327
import grails.artefact.Artefact;
2428
import grails.artefact.controller.support.AllowedMethodsHelper;
2529
import grails.compiler.DelegatingMethod;
@@ -37,6 +41,7 @@
3741
import groovy.lang.Closure;
3842

3943
import java.io.File;
44+
import java.lang.annotation.Annotation;
4045
import java.lang.reflect.Method;
4146
import java.lang.reflect.Modifier;
4247
import java.net.URL;
@@ -91,6 +96,7 @@
9196
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
9297
import org.codehaus.groovy.syntax.Token;
9398
import org.codehaus.groovy.syntax.Types;
99+
import org.codehaus.groovy.transform.trait.Traits;
94100
import org.grails.compiler.injection.GrailsASTUtils;
95101
import org.grails.core.DefaultGrailsControllerClass;
96102
import org.grails.core.artefact.ControllerArtefactHandler;
@@ -232,6 +238,8 @@ private boolean isExceptionHandlingMethod(MethodNode methodNode) {
232238
return isExceptionHandler;
233239
}
234240

241+
242+
235243
private void processMethods(ClassNode classNode, SourceUnit source,
236244
GeneratorContext context) {
237245

@@ -293,12 +301,18 @@ public Object call(Object object) {
293301
* @return true if the method should be configured as a controller action, false otherwise
294302
*/
295303
protected boolean methodShouldBeConfiguredAsControllerAction(final MethodNode method) {
304+
int minLineNumber = 0;
305+
if (isInheritedFromTrait(method) && hasAnnotation(method, Action.class) && hasParameters(method)) {
306+
removeAnnotation(method, Action.class);
307+
//Trait methods have a line number of -1
308+
--minLineNumber;
309+
}
296310
return !method.isStatic() &&
297311
method.isPublic() &&
298312
!method.isAbstract() &&
299313
method.getAnnotations(ACTION_ANNOTATION_NODE.getClassNode()).isEmpty() &&
300314
method.getAnnotations(new ClassNode(ControllerMethod.class)).isEmpty() &&
301-
method.getLineNumber() >= 0 &&
315+
method.getLineNumber() >= minLineNumber &&
302316
!method.getName().startsWith("$") &&
303317
!method.getReturnType().getName().equals(VOID_TYPE) &&
304318
!isExceptionHandlingMethod(method);

grails-plugin-controllers/src/test/groovy/org/codehaus/groovy/grails/compiler/web/ControllerActionTransformerSpec.groovy

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -169,23 +169,36 @@ class ControllerActionTransformerSpec extends Specification {
169169
42 == model.paramValue
170170
}
171171

172-
/* void "Test annotated controllers"() {
173-
when:
172+
173+
void "test controller with trait action with params"() {
174+
given:
174175
def cls = gcl.parseClass('''
175-
class AnnotatedControllerTransformer1Controller {
176-
def action = {
176+
@grails.artefact.Artefact('Controller')
177+
class TestTraitActionToController implements ShowMethod {
178+
179+
180+
}
181+
class MyCommandWithArg implements grails.validation.Validateable {
182+
183+
}
184+
trait ShowMethod {
185+
186+
@grails.web.Action
187+
def show(MyCommandWithArg myCommandWithArg) {
188+
!myCommandWithArg.hasErrors()
177189
}
190+
178191
}
179192
''')
180-
181193
def controller = cls.newInstance()
182194

183-
then:
184-
controller
185-
controller.getClass().getMethod("action", [] as Class[]) != null
195+
when:
196+
Boolean valid = controller.show()
186197

198+
then:
199+
valid
187200
}
188-
*/
201+
189202

190203
def cleanup() {
191204
RequestContextHolder.resetRequestAttributes()

0 commit comments

Comments
 (0)