Skip to content

Commit 8a3a410

Browse files
GRAILS-11576 - more flexible exception handling
Controller exception handler methods can now catch exceptions thrown during command object initialization.
1 parent 9138f1c commit 8a3a410

File tree

3 files changed

+72
-3
lines changed

3 files changed

+72
-3
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,6 @@ private MethodNode convertToMethodAction(ClassNode classNode, MethodNode methodN
354354
GrailsASTUtils.error(source, methodNode, formattedMessage);
355355
}
356356
}
357-
wrapMethodBodyWithExceptionHandling(classNode, methodNode);
358357

359358
MethodNode method = null;
360359
if (methodNode.getParameters().length > 0) {
@@ -376,9 +375,12 @@ private MethodNode convertToMethodAction(ClassNode classNode, MethodNode methodN
376375

377376
GrailsASTUtils.copyAnnotations(methodNode, method);
378377
annotateActionMethod(classNode, parameters, method);
378+
wrapMethodBodyWithExceptionHandling(classNode, method);
379379
} else {
380380
annotateActionMethod(classNode, parameters, methodNode);
381381
}
382+
383+
wrapMethodBodyWithExceptionHandling(classNode, methodNode);
382384

383385
return method;
384386
}

grails-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/plugins/web/api/ControllersApi.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
import org.codehaus.groovy.runtime.InvokerHelper;
5858
import org.grails.databinding.CollectionDataBindingSource;
5959
import org.grails.databinding.DataBindingSource;
60-
import org.grails.databinding.bindingsource.DataBindingSourceCreationException;
6160
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
6261
import org.springframework.context.ApplicationContext;
6362
import org.springframework.http.HttpMethod;
@@ -495,7 +494,11 @@ public Object initializeCommandObject(final Object controllerInstance, final Cla
495494
bindData(controllerInstance, commandObjectInstance, commandObjectBindingSource, Collections.EMPTY_MAP, null);
496495
}
497496
}
498-
} catch (DataBindingSourceCreationException e) {
497+
} catch (Exception e) {
498+
final Method exceptionHandlerMethodFor = getExceptionHandlerMethodFor(controllerInstance, e.getClass());
499+
if(exceptionHandlerMethodFor != null) {
500+
throw e;
501+
}
499502
commandObjectInstance = type.newInstance();
500503
final Object o = GrailsMetaClassUtils.invokeMethodIfExists(commandObjectInstance, "getErrors");
501504
if(o instanceof BindingResult) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.codehaus.groovy.grails.web.binding.json
2+
3+
import grails.artefact.Artefact
4+
import grails.test.mixin.TestFor
5+
6+
import org.grails.databinding.bindingsource.DataBindingSourceCreationException
7+
8+
import spock.lang.Specification
9+
10+
11+
@TestFor(BindingWithExceptionHandlerMethodController)
12+
class JsonBindingWithExceptionHandlerSpec extends Specification {
13+
14+
void 'test binding malformed JSON'() {
15+
given:
16+
request.contentType = JSON_CONTENT_TYPE
17+
request.method = 'POST'
18+
request.JSON = '{"mapData": {"name":"Jeff{{{"'
19+
20+
when:
21+
controller.bindWithCommandObject()
22+
23+
then:
24+
response.status == 400
25+
model.errorMessage == 'caught a DataBindingSourceCreationException'
26+
view == '/bindingProblems'
27+
}
28+
29+
void 'test binding valid JSON'() {
30+
given:
31+
request.contentType = JSON_CONTENT_TYPE
32+
request.method = 'POST'
33+
request.JSON = '{"name":"Jeff"}'
34+
35+
when:
36+
def model = controller.bindWithCommandObject()
37+
38+
then:
39+
response.status == 200
40+
flash.message == null
41+
model.command.name == 'Jeff'
42+
43+
}
44+
}
45+
46+
@Artefact('Controller')
47+
class BindingWithExceptionHandlerMethodController {
48+
49+
def bindWithCommandObject(SomeCommandObject co) {
50+
[command: co]
51+
}
52+
53+
def handleDataBindingException(DataBindingSourceCreationException e) {
54+
response.status = 400
55+
render view: '/bindingProblems', model: [errorMessage: 'caught a DataBindingSourceCreationException']
56+
}
57+
}
58+
59+
class SomeCommandObject {
60+
String name
61+
static constraints = {
62+
name matches: /[A-Z].*/
63+
}
64+
}

0 commit comments

Comments
 (0)