1818import grails .config .Settings ;
1919import grails .core .GrailsApplication ;
2020import grails .core .GrailsControllerClass ;
21+ import grails .util .Environment ;
2122import grails .util .GrailsClassUtils ;
2223import grails .web .Action ;
2324import grails .web .UrlConverter ;
@@ -52,7 +53,7 @@ public class DefaultGrailsControllerClass extends AbstractInjectableGrailsClass
5253 public static final String SCOPE = "scope" ;
5354 public static final String SCOPE_SINGLETON = "singleton" ;
5455 private String scope ;
55- private Map <String , MethodHandle > actions = new HashMap <String , MethodHandle >();
56+ private Map <String , ActionInvoker > actions = new HashMap <String , ActionInvoker >();
5657 private String defaultActionName ;
5758 private String namespace ;
5859 protected Map <String , String > actionUriToViewName = new HashMap <String , String >();
@@ -104,23 +105,27 @@ public String getDefaultAction() {
104105 return this .defaultActionName ;
105106 }
106107
107- private void methodStrategy (Map <String , MethodHandle > methodNames ) {
108+ private void methodStrategy (Map <String , ActionInvoker > methodNames ) {
108109
109110 Class superClass = getClazz ();
110111 MethodHandles .Lookup lookup = MethodHandles .lookup ();
111112 while (superClass != Object .class && superClass != GroovyObject .class ) {
112113 for (Method method : superClass .getMethods ()) {
113114 if (Modifier .isPublic (method .getModifiers ()) && method .getAnnotation (Action .class ) != null ) {
114115 String methodName = method .getName ();
115-
116- ReflectionUtils .makeAccessible (method );
117- MethodHandle mh ;
118- try {
119- mh = lookup .findVirtual (superClass , methodName , MethodType .methodType (method .getReturnType ()));
120- methodNames .put (methodName , mh );
121- } catch (NoSuchMethodException | IllegalAccessException e ) {
122- throw new GrailsConfigurationException ("Cannot find invokable controller action: " + methodName , e );
116+ if (Environment .isDevelopmentMode ()) {
117+ methodNames .put (methodName , new ReflectionInvoker (method ));
123118 }
119+ else {
120+ MethodHandle mh ;
121+ try {
122+ mh = lookup .findVirtual (superClass , methodName , MethodType .methodType (method .getReturnType ()));
123+ methodNames .put (methodName , new MethodHandleInvoker (mh ));
124+ } catch (NoSuchMethodException | IllegalAccessException e ) {
125+ methodNames .put (methodName , new ReflectionInvoker (method ));
126+ }
127+ }
128+
124129 }
125130 }
126131 superClass = superClass .getSuperclass ();
@@ -177,7 +182,7 @@ public void registerUrlConverter(UrlConverter urlConverter) {
177182 @ Override
178183 public Object invoke (Object controller , String action ) throws Throwable {
179184 if (action == null ) action = this .defaultActionName ;
180- MethodHandle handle = actions .get (action );
185+ ActionInvoker handle = actions .get (action );
181186 if (handle == null ) throw new IllegalArgumentException ("Invalid action name: " + action );
182187 return handle .invoke (controller );
183188 }
@@ -187,4 +192,34 @@ public String actionUriToViewName(String actionUri) {
187192
188193 return actionName != null ? actionName : actionUri ;
189194 }
195+
196+ private interface ActionInvoker {
197+ Object invoke (Object controller ) throws Throwable ;
198+ }
199+
200+ private class ReflectionInvoker implements ActionInvoker {
201+ private final Method method ;
202+
203+ public ReflectionInvoker (Method method ) {
204+ this .method = method ;
205+ ReflectionUtils .makeAccessible (method );
206+ }
207+
208+ @ Override
209+ public Object invoke (Object controller ) throws Throwable {
210+ return method .invoke (controller );
211+ }
212+ }
213+ private class MethodHandleInvoker implements ActionInvoker {
214+ private final MethodHandle handle ;
215+
216+ public MethodHandleInvoker (MethodHandle handle ) {
217+ this .handle = handle ;
218+ }
219+
220+ @ Override
221+ public Object invoke (Object controller ) throws Throwable {
222+ return handle .invoke (controller );
223+ }
224+ }
190225}
0 commit comments