Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2011 SpringSource
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package org.codehaus.groovy.grails.compiler.web;
 
 import static org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils.applyDefaultMethodTarget;
 import static org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils.applyMethodTarget;
 import static org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils.buildGetMapExpression;
 import static org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils.buildGetPropertyExpression;
 import static org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils.buildSetPropertyExpression;
 
 import java.io.File;
 import java.net.URL;
 import java.util.List;
 import java.util.Map;
 
 import  javax.servlet.http.HttpServletResponse;
 
Enhances controller classes by converting closures actions to method actions and binding request parameters to action arguments.
/*
class TestController{
    //default  scope configurable in Config.groovy
    static scope = 'singleton'
    def peterTheFrenchService
    //--------------------------
    //allow use of methods as actions
    def someAction() {
            render 'ata'
    }
    / becomes behind the scene :
    @Action
    def someAction() {
        render 'ata'
    }
    /
    //--------------------------
    //Compile time transformed to method
    def lol2 = {
        render 'testxx'
    }
    / becomes behind the scene :
        @Action def lol2() {  render 'testxx'  }
    /
    //--------------------------
    def lol4 = { PeterCommand cmd ->
        render cmd.a
    }
    / becomes behind the scene :
        @Action(commandObjects={PeterCommand}) def lol4() {
            PeterCommand cmd = new PeterCommand(); bindData(cmd, params)
            render 'testxx'
        }
    /
*/
    private static final String ALLOWED_METHODS_HANDLED_ATTRIBUTE_NAME = "ALLOWED_METHODS_HANDLED";
    private static final ClassNode OBJECT_CLASS = new ClassNode(Object.class);
    public static final AnnotationNode ACTION_ANNOTATION_NODE = new AnnotationNode(
            new ClassNode(Action.class));
    private static final String ACTION_MEMBER_TARGET = "commandObjects";
    public static final String EXCEPTION_HANDLER_META_DATA_FIELD_NAME = "$exceptionHandlerMetaData";
    private static final TupleExpression EMPTY_TUPLE = new TupleExpression();
    @SuppressWarnings({"unchecked"})
    private static final Map<ClassNodeStringTYPE_WRAPPER_CLASS_TO_CONVERSION_METHOD_NAME = CollectionUtils.<ClassNodeString>newMap(
            ."int",
            ."float",
            ."long",
            ."double",
            ."short",
            ."boolean",
            ."byte",
            ."char");
    private static List<ClassNodePRIMITIVE_CLASS_NODES = CollectionUtils.<ClassNode>newList(
            .,
            .,
            .,
            .,
            .,
            .,
            .,
            .);
    public static final String VOID_TYPE = "void";
    private Boolean converterEnabled;
    public ControllerActionTransformer() {
    }
    public String[] getArtefactTypes() {
        return new String[]{.};
    }
    public void performInjection(SourceUnit sourceGeneratorContext contextClassNode classNode) {
        // don't inject if already an @Artefact annotation is applied
        if(!classNode.getAnnotations(new ClassNode(Artefact.class)).isEmpty()) return;
        performInjectionOnAnnotatedClass(sourcecontextclassNode);
    }
    @Override
    public void performInjectionOnAnnotatedClass(SourceUnit sourceGeneratorContext contextClassNode classNode) {
        final String className = classNode.getName();
        if (className.endsWith(.)) {
            processMethods(classNodesourcecontext);
            processClosures(classNodesourcecontext);
        }
    }
    @Override
    public void performInjectionOnAnnotatedClass(SourceUnit sourceClassNode classNode) {
        performInjectionOnAnnotatedClass(source,nullclassNode);
    }
    private boolean isExceptionHandlingMethod(MethodNode methodNode) {
        boolean isExceptionHandler = false;
        if(!methodNode.isPrivate() && methodNode.getName().indexOf("$") == -1) {
            Parameter[] parameters = methodNode.getParameters();
            if(parameters.length == 1) {
                ClassNode parameterTypeClassNode = parameters[0].getType();
                isExceptionHandler = parameterTypeClassNode.isDerivedFrom(new ClassNode(Exception.class));
            }
        }
        return isExceptionHandler;
    }
    private void processMethods(ClassNode classNodeSourceUnit source,
            GeneratorContext context) {
        List<MethodNodedeferredNewMethods = new ArrayList<MethodNode>();
        for (MethodNode method : classNode.getMethods()) {
            if (methodShouldBeConfiguredAsControllerAction(method)) {
                final List<MethodNodedeclaredMethodsWithThisName = classNode.getDeclaredMethods(method.getName());
                if(declaredMethodsWithThisName != null) {
                    final int numberOfNonExceptionHandlerMethodsWithThisName = DefaultGroovyMethods.count((Iterable)declaredMethodsWithThisNamenew Closure(this) {
                        @Override
                        public Object call(Object object) {
                            return !isExceptionHandlingMethod((MethodNodeobject);
                        }
                    }).intValue();
                    if (numberOfNonExceptionHandlerMethodsWithThisName > 1) {
                        String message = "Controller actions may not be overloaded.  The [" +
                                method.getName() +
                                "] action has been overloaded in [" +
                                classNode.getName() +
                                "].";
                        GrailsASTUtils.error(sourcemethodmessage);
                    }
                }
                MethodNode wrapperMethod = convertToMethodAction(classNodemethodsourcecontext);
                if (wrapperMethod != null) {
                    deferredNewMethods.add(wrapperMethod);
                }
            }
        }
        Collection<MethodNodeexceptionHandlerMethods = getExceptionHandlerMethods(classNodesource);
        final FieldNode exceptionHandlerMetaDataField = classNode.getField();
        if(exceptionHandlerMetaDataField == null || !exceptionHandlerMetaDataField.getDeclaringClass().equals(classNode)) {
            final ListExpression listOfExceptionHandlerMetaData = new ListExpression();
            for(final MethodNode exceptionHandlerMethod : exceptionHandlerMethods) {
                final Parameter[] parameters = exceptionHandlerMethod.getParameters();
                final Parameter firstParameter = parameters[0];
                final ClassNode firstParameterTypeClassNode = firstParameter.getType();
                final String exceptionHandlerMethodName = exceptionHandlerMethod.getName();
                final ArgumentListExpression defaultControllerExceptionHandlerMetaDataCtorArgs = new ArgumentListExpression();
                defaultControllerExceptionHandlerMetaDataCtorArgs.addExpression(new ConstantExpression(exceptionHandlerMethodName));
                defaultControllerExceptionHandlerMetaDataCtorArgs.addExpression(new ClassExpression(firstParameterTypeClassNode.getPlainNodeReference()));
                listOfExceptionHandlerMetaData.addExpression(new ConstructorCallExpression(new ClassNode(DefaultControllerExceptionHandlerMetaData.class), defaultControllerExceptionHandlerMetaDataCtorArgs));
            }
            classNode.addField(,
                    . | . | .new ClassNode(List.class),
                    listOfExceptionHandlerMetaData);
        }
        for (MethodNode newMethod : deferredNewMethods) {
            classNode.addMethod(newMethod);
        }
    }

    

Parameters:
method a potential controller action method
Returns:
true if the method should be configured as a controller action, false otherwise
    protected boolean methodShouldBeConfiguredAsControllerAction(final MethodNode method) {
        return !method.isStatic() && 
                method.isPublic() && 
                !method.isAbstract() &&
                method.getAnnotations(.getClassNode()).isEmpty() &&
                method.getAnnotations(new ClassNode(ControllerMethod.class)).isEmpty() &&
                method.getLineNumber() >= 0 &&
                !method.getName().startsWith("$") &&
                !method.getReturnType().getName().equals() &&
                !isExceptionHandlingMethod(method);
    }
    protected Collection<MethodNodegetExceptionHandlerMethods(final ClassNode classNodeSourceUnit sourceUnit) {
        final Map<ClassNodeMethodNodeexceptionTypeToHandlerMethodMap = new HashMap<ClassNodeMethodNode>();
        final List<MethodNodemethods = classNode.getMethods();
        for(MethodNode methodNode : methods) {
            if(isExceptionHandlingMethod(methodNode)) {
                final Parameter exceptionParameter = methodNode.getParameters()[0];
                final ClassNode exceptionType = exceptionParameter.getType();
                if(!exceptionTypeToHandlerMethodMap.containsKey(exceptionType)) {
                    exceptionTypeToHandlerMethodMap.put(exceptionTypemethodNode);
                } else {
                    final MethodNode otherHandlerMethod = exceptionTypeToHandlerMethodMap.get(exceptionType);
                    final String message = "A controller may not define more than 1 exception handler for a particular exception type.  [%s] defines the [%s] and [%s] exception handlers which each accept a [%s] which is not allowed.";
                    final String formattedMessage = String.format(messageclassNode.getName(), otherHandlerMethod.getName(), methodNode.getName(), exceptionType.getName());
                    GrailsASTUtils.error(sourceUnitmethodNodeformattedMessage);
                }
            }
        }
        final ClassNode superClass = classNode.getSuperClass();
        if(!superClass.equals()) {
            final Collection<MethodNodesuperClassMethods = getExceptionHandlerMethods(superClasssourceUnit);
            for(MethodNode superClassMethod : superClassMethods) {
                final Parameter exceptionParameter = superClassMethod.getParameters()[0];
                final ClassNode exceptionType = exceptionParameter.getType();
                // only add this super class handler if we don't already have
                // a handler for this exception type in this class
                if(!exceptionTypeToHandlerMethodMap.containsKey(exceptionType)) {
                    exceptionTypeToHandlerMethodMap.put(exceptionTypesuperClassMethod);
                }
            }
        }
        return exceptionTypeToHandlerMethodMap.values();
    }

    
Converts a method into a controller action. If the method accepts parameters, a no-arg counterpart is created which delegates to the original.

Parameters:
classNode The controller class
methodNode The method to be converted
Returns:
The no-arg wrapper method, or null if none was created.
    private MethodNode convertToMethodAction(ClassNode classNodeMethodNode methodNode,
            SourceUnit sourceGeneratorContext context) {
        final ClassNode returnType = methodNode.getReturnType();
        Parameter[] parameters = methodNode.getParameters();
        for (Parameter param : parameters) {
            if (param.hasInitialExpression()) {
                String paramName = param.getName();
                String methodName = methodNode.getName();
                String initialValue = param.getInitialExpression().getText();
                String methodDeclaration = methodNode.getText();
                String message = "Parameter [%s] to method [%s] has default value [%s].  " +
                        "Default parameter values are not allowed in controller action methods. ([%s])";
                String formattedMessage = String.format(messageparamNamemethodName,
                        initialValuemethodDeclaration);
                GrailsASTUtils.error(sourcemethodNodeformattedMessage);
            }
        }
        MethodNode method = null;
        if (methodNode.getParameters().length > 0) {
            final BlockStatement methodCode = new BlockStatement();
            
            final BlockStatement codeToHandleAllowedMethods = getCodeToHandleAllowedMethods(classNodemethodNode.getName());
            final Statement codeToCallOriginalMethod = addOriginalMethodCall(methodNodeinitializeActionParameters(
                    classNodemethodNodemethodNode.getName(), parameterssourcecontext));
            
            methodCode.addStatement(codeToHandleAllowedMethods);
            methodCode.addStatement(codeToCallOriginalMethod);
            
            method = new MethodNode(
                    methodNode.getName(),
                    .returnType,
                    ,
                    ,
                    methodCode);
            
            GrailsASTUtils.copyAnnotations(methodNodemethod);
            annotateActionMethod(classNodeparametersmethod);
            wrapMethodBodyWithExceptionHandling(classNodemethod);
        } else {
            annotateActionMethod(classNodeparametersmethodNode);
        }
        
        wrapMethodBodyWithExceptionHandling(classNodemethodNode);
        return method;
    }
    private Statement addOriginalMethodCall(MethodNode methodNodeBlockStatement blockStatement) {
        if (blockStatement == null) {
            return null;
        }
        final ArgumentListExpression arguments = new ArgumentListExpression();
        for (Parameter p : methodNode.getParameters()) {
            arguments.addExpression(new VariableExpression(p.getName(), p.getType()));
        }
        MethodCallExpression callExpression = new MethodCallExpression(
                new VariableExpression("this"), methodNode.getName(), arguments);
        callExpression.setMethodTarget(methodNode);
        blockStatement.addStatement(new ReturnStatement(callExpression));
        return blockStatement;
    }
    //See WebMetaUtils#isCommandObjectAction
    private boolean isCommandObjectAction(Parameter[] params) {
        return params != null && params.length > 0
                && params[0].getType() != new ClassNode(Object[].class)
                && params[0].getType() != new ClassNode(Object.class);
    }
    private void processClosures(ClassNode classNodeSourceUnit sourceGeneratorContext context) {
        List<PropertyNodepropertyNodes = new ArrayList<PropertyNode>(classNode.getProperties());
        Expression initialExpression;
        ClosureExpression closureAction;
        for (PropertyNode property : propertyNodes) {
            initialExpression = property.getInitialExpression();
            if (!property.isStatic() && initialExpression != null &&
                    initialExpression.getClass().equals(ClosureExpression.class)) {
                closureAction = (ClosureExpressioninitialExpression;
                if () {
                    transformClosureToMethod(classNodeclosureActionpropertysourcecontext);
                } else {
                    addMethodToInvokeClosure(classNodepropertysourcecontext);
                }
            }
        }
    }
    protected void addMethodToInvokeClosure(ClassNode controllerClassNode,
            PropertyNode closurePropertySourceUnit sourceGeneratorContext context) {
        MethodNode method = controllerClassNode.getMethod(closureProperty.getName(), );
        if (method == null || !method.getDeclaringClass().equals(controllerClassNode)) {
            ClosureExpression closureExpression = (ClosureExpressionclosureProperty.getInitialExpression();
            final Parameter[] parameters = closureExpression.getParameters();
            final BlockStatement newMethodCode = initializeActionParameters(
                    controllerClassNodeclosurePropertyclosureProperty.getName(),
                    parameterssourcecontext);
            final ArgumentListExpression closureInvocationArguments = new ArgumentListExpression();
            if (parameters != null) {
                for (Parameter p : parameters) {
                    closureInvocationArguments.addExpression(new VariableExpression(p.getName()));
                }
            }
            final MethodCallExpression methodCallExpression = new MethodCallExpression(
                    closureExpression"call"closureInvocationArguments);
            newMethodCode.addStatement(new ExpressionStatement(applyMethodTarget(methodCallExpressionClosure.classObject.class)));
            final MethodNode methodNode = new MethodNode(closureProperty.getName(), .,
                    new ClassNode(Object.class), newMethodCode);
            wrapMethodBodyWithExceptionHandling(controllerClassNodemethodNode);
            annotateActionMethod(controllerClassNodeparametersmethodNode);
            controllerClassNode.addMethod(methodNode);
        }
    }
    protected void annotateActionMethod(ClassNode controllerClassNodefinal Parameter[] parametersfinal MethodNode methodNode) {
        if (isCommandObjectAction(parameters)) {
            ListExpression initArray = new ListExpression();
            for (Parameter parameter : parameters) {
                initArray.addExpression(new ClassExpression(parameter.getType()));
            }
            AnnotationNode paramActionAnn = new AnnotationNode(new ClassNode(Action.class));
            paramActionAnn.setMember(initArray);
            methodNode.addAnnotation(paramActionAnn);
        } else {
            methodNode.addAnnotation();
        }
    }
    protected BlockStatement getCodeToHandleAllowedMethods(ClassNode controllerClassString methodName) {
        final BlockStatement checkAllowedMethodsBlock = new BlockStatement();
        
        final PropertyExpression requestPropertyExpression = new PropertyExpression(new VariableExpression("this"), "request");
        
        final FieldNode allowedMethodsField = controllerClass.getField(.);
        
        if(allowedMethodsField != null) {
            final Expression initialAllowedMethodsExpression = allowedMethodsField.getInitialExpression();
            if(initialAllowedMethodsExpression instanceof MapExpression) {
                final List<StringallowedMethodNames = new ArrayList<String>();
                final MapExpression allowedMethodsMapExpression = (MapExpressioninitialAllowedMethodsExpression;
                final List<MapEntryExpressionallowedMethodsMapEntryExpressions = allowedMethodsMapExpression.getMapEntryExpressions();
                for(MapEntryExpression allowedMethodsMapEntryExpression : allowedMethodsMapEntryExpressions) {
                    final Expression allowedMethodsMapEntryKeyExpression = allowedMethodsMapEntryExpression.getKeyExpression();
                    if(allowedMethodsMapEntryKeyExpression instanceof ConstantExpression) {
                        final ConstantExpression allowedMethodsMapKeyConstantExpression = (ConstantExpressionallowedMethodsMapEntryKeyExpression;
                        final Object allowedMethodsMapKeyValue = allowedMethodsMapKeyConstantExpression.getValue();
                        if(methodName.equals(allowedMethodsMapKeyValue)) {
                            final Expression allowedMethodsMapEntryValueExpression = allowedMethodsMapEntryExpression.getValueExpression();
                            if(allowedMethodsMapEntryValueExpression instanceof ListExpression) {
                                final ListExpression allowedMethodsEntryListExpression = (ListExpressionallowedMethodsMapEntryValueExpression;
                                final List<ExpressionlistExpressions = allowedMethodsEntryListExpression.getExpressions();
                                for(Expression expression : listExpressions) {
                                    if(expression instanceof ConstantExpression) {
                                        final ConstantExpression constantListValue = (ConstantExpressionexpression;
                                        allowedMethodNames.add(constantListValue.getValue().toString());
                                    }
                                }
                            } else if(allowedMethodsMapEntryValueExpression instanceof ConstantExpression) {
                                final ConstantExpression contantValue = (ConstantExpressionallowedMethodsMapEntryValueExpression;
                                allowedMethodNames.add(contantValue.getValue().toString());
                            }
                            break;
                        }
                    }
                }
                final int numberOfAllowedMethods = allowedMethodNames.size();
                if(numberOfAllowedMethods > 0) {
                    final PropertyExpression responsePropertyExpression = new PropertyExpression(new VariableExpression("this"), "response");
                    final PropertyExpression requestMethodExpression = new PropertyExpression(requestPropertyExpression"method");
                    BooleanExpression isValidRequestMethod = new BooleanExpression(new MethodCallExpression(requestMethodExpression
                                                                                                            "equalsIgnoreCase"
                                                                                                            new ConstantExpression(allowedMethodNames.get(0))));
                    for(int x = 1; x < numberOfAllowedMethodsx++) {
                        isValidRequestMethod = new BooleanExpression(new BinaryExpression(isValidRequestMethod
                                                                                          Token.newSymbol(., 0, 0), 
                                                                                          new MethodCallExpression(requestMethodExpression
                                                                                                                   "equalsIgnoreCase"
                                                                                                                   new ConstantExpression(allowedMethodNames.get(x)))));
                    }
                    final MethodCallExpression sendErrorMethodCall = new MethodCallExpression(responsePropertyExpression"sendError"new ConstantExpression(HttpServletResponse.SC_METHOD_NOT_ALLOWED));
                    final ReturnStatement returnStatement = new ReturnStatement(new ConstantExpression(null));
                    final BlockStatement blockToSendError = new BlockStatement();
                    blockToSendError.addStatement(new ExpressionStatement(sendErrorMethodCall));
                    blockToSendError.addStatement(returnStatement);
                    final IfStatement ifIsValidRequestMethodStatement = new IfStatement(isValidRequestMethodnew ExpressionStatement(new EmptyExpression()), blockToSendError);
                  
                    checkAllowedMethodsBlock.addStatement(ifIsValidRequestMethodStatement);
                }
            }
        }
        
        final ArgumentListExpression argumentListExpression = new ArgumentListExpression();
        argumentListExpression.addExpression(new ConstantExpression());
        argumentListExpression.addExpression(new ConstantExpression(methodName));
        
        final Expression setAttributeMethodCall = new MethodCallExpression(requestPropertyExpression"setAttribute"argumentListExpression);
        
        final BlockStatement codeToExecuteIfAttributeIsNotSet = new BlockStatement();
        codeToExecuteIfAttributeIsNotSet.addStatement(new ExpressionStatement(setAttributeMethodCall));
        codeToExecuteIfAttributeIsNotSet.addStatement(checkAllowedMethodsBlock);
        final BooleanExpression attributeIsSetBooleanExpression = new BooleanExpression(new MethodCallExpression(requestPropertyExpression"getAttribute"new ArgumentListExpression(new ConstantExpression())));
        final Statement ifAttributeIsAlreadySetStatement = new IfStatement(attributeIsSetBooleanExpressionnew EmptyStatement(), codeToExecuteIfAttributeIsNotSet);
        
        final BlockStatement code = new BlockStatement();
        code.addStatement(ifAttributeIsAlreadySetStatement);
        return code;
    }
    
This will wrap the method body in a try catch block which does something like this:
 try {
     // original method body here
 } catch (Exception $caughtException) {
     Method $method = getExceptionHandlerMethod($caughtException.getClass())
     if($method) {
         return $method.invoke(this, $caughtException)
     } else {
         throw $caughtException
     }
 }
 

Parameters:
methodNode the method to add the try catch block to
    protected void wrapMethodBodyWithExceptionHandling(final ClassNode controllerClassNodefinal MethodNode methodNode) {
        final BlockStatement catchBlockCode = new BlockStatement();
        final String caughtExceptionArgumentName = "$caughtException";
        final Expression caughtExceptionVariableExpression = new VariableExpression(caughtExceptionArgumentName);
        final Expression caughtExceptionTypeExpression = new PropertyExpression(caughtExceptionVariableExpression"class");
        final Expression thisExpression = new VariableExpression("this");
        final MethodCallExpression getExceptionHandlerMethodCall = new MethodCallExpression(thisExpression"getExceptionHandlerMethodFor"caughtExceptionTypeExpression);
        applyDefaultMethodTarget(getExceptionHandlerMethodCallcontrollerClassNode);
        final ClassNode reflectMethodClassNode = new ClassNode(Method.class);
        final String exceptionHandlerMethodVariableName = "$method";
        final Expression exceptionHandlerMethodExpression = new VariableExpression(exceptionHandlerMethodVariableNamenew ClassNode(Method.class));
        final Expression declareExceptionHandlerMethod = new DeclarationExpression(
                new VariableExpression(exceptionHandlerMethodVariableNamereflectMethodClassNode), Token.newSymbol(., 0, 0), getExceptionHandlerMethodCall);
        final ArgumentListExpression invokeArguments = new ArgumentListExpression();
        invokeArguments.addExpression(thisExpression);
        invokeArguments.addExpression(caughtExceptionVariableExpression);
        final MethodCallExpression invokeExceptionHandlerMethodExpression = new MethodCallExpression(new VariableExpression(exceptionHandlerMethodVariableName), "invoke"invokeArguments);
        applyDefaultMethodTarget(invokeExceptionHandlerMethodExpressionreflectMethodClassNode);
        
        final Statement returnStatement = new ReturnStatement(invokeExceptionHandlerMethodExpression);
        final Statement throwCaughtExceptionStatement = new ThrowStatement(caughtExceptionVariableExpression);
        final Statement ifExceptionHandlerMethodExistsStatement = new IfStatement(new BooleanExpression(exceptionHandlerMethodExpression), returnStatementthrowCaughtExceptionStatement);
        catchBlockCode.addStatement(new ExpressionStatement(declareExceptionHandlerMethod));
        catchBlockCode.addStatement(ifExceptionHandlerMethodExistsStatement);
        final CatchStatement catchStatement = new CatchStatement(new Parameter(new ClassNode(Exception.class), caughtExceptionArgumentName), catchBlockCode);
        final Statement methodBody = methodNode.getCode();
        BlockStatement tryBlock = new BlockStatement();
        BlockStatement codeToHandleAllowedMethods = getCodeToHandleAllowedMethods(controllerClassNodemethodNode.getName());
        tryBlock.addStatement(codeToHandleAllowedMethods);
        tryBlock.addStatement(methodBody);
        final TryCatchStatement tryCatchStatement = new TryCatchStatement(tryBlocknew EmptyStatement());
        tryCatchStatement.addCatch(catchStatement);
        final ArgumentListExpression argumentListExpression = new ArgumentListExpression();
        argumentListExpression.addExpression(new ConstantExpression());
        
        final PropertyExpression requestPropertyExpression = new PropertyExpression(new VariableExpression("this"), "request");
        final Expression removeAttributeMethodCall = new MethodCallExpression(requestPropertyExpression"removeAttribute"argumentListExpression);
        
        final Expression getAttributeMethodCall = new MethodCallExpression(requestPropertyExpression"getAttribute"new ArgumentListExpression(new ConstantExpression()));
        final VariableExpression attributeValueExpression = new VariableExpression("$allowed_methods_attribute_value", ClassHelper.make(Object.class));
        final Expression initializeAttributeValue = new DeclarationExpression(
                attributeValueExpression, Token.newSymbol(., 0, 0), getAttributeMethodCall);
        final Expression attributeValueMatchesMethodNameExpression = new BinaryExpression(new ConstantExpression(methodNode.getName()), 
                                                  Token.newSymbol(., 0, 0), 
                                                  attributeValueExpression);
        final Statement ifAttributeValueMatchesMethodName = 
                new IfStatement(new BooleanExpression(attributeValueMatchesMethodNameExpression), 
                                new ExpressionStatement(removeAttributeMethodCall), new EmptyStatement());
        final BlockStatement blockToRemoveAttribute = new BlockStatement();
        blockToRemoveAttribute.addStatement(new ExpressionStatement(initializeAttributeValue));
        blockToRemoveAttribute.addStatement(ifAttributeValueMatchesMethodName);
        
        final TryCatchStatement tryCatchToRemoveAttribute = new TryCatchStatement(blockToRemoveAttributenew EmptyStatement());
        tryCatchToRemoveAttribute.addCatch(new CatchStatement(new Parameter(ClassHelper.make(Exception.class), "$exceptionRemovingAttribute"), new EmptyStatement()));
        tryCatchStatement.setFinallyStatement(tryCatchToRemoveAttribute);
        methodNode.setCode(tryCatchStatement);
    }
    protected void transformClosureToMethod(ClassNode classNodeClosureExpression closureAction,
            PropertyNode propertySourceUnit sourceGeneratorContext context) {
        final MethodNode actionMethod = new MethodNode(property.getName(),
                .property.getType(), closureAction.getParameters(),
                closureAction.getCode());
        MethodNode convertedMethod = convertToMethodAction(classNodeactionMethodsourcecontext);
        if (convertedMethod != null) {
            classNode.addMethod(convertedMethod);
        }
        classNode.getProperties().remove(property);
        classNode.getFields().remove(property.getField());
        classNode.addMethod(actionMethod);
    }
    protected BlockStatement initializeActionParameters(ClassNode classNodeASTNode actionNode,
            String actionNameParameter[] actionParametersSourceUnit source,
            GeneratorContext context) {
        BlockStatement wrapper = new BlockStatement();
        ArgumentListExpression mapBindingResultConstructorArgs = new ArgumentListExpression();
        mapBindingResultConstructorArgs.addExpression(new ConstructorCallExpression(
                new ClassNode(HashMap.class), ));
        mapBindingResultConstructorArgs.addExpression(new ConstantExpression("controller"));
        final Expression mapBindingResultConstructorCallExpression = new ConstructorCallExpression(
                new ClassNode(MapBindingResult.class), mapBindingResultConstructorArgs);
        final Expression errorsAssignmentExpression = buildSetPropertyExpression(new VariableExpression("this"classNode), "errors"classNodemapBindingResultConstructorCallExpression);
        wrapper.addStatement(new ExpressionStatement(errorsAssignmentExpression));
        if (actionParameters != null) {
            for (Parameter param : actionParameters) {
                initializeMethodParameter(classNodewrapperactionNodeactionName,
                        paramsourcecontext);
            }
        }
        return wrapper;
    }
    protected void initializeMethodParameter(final ClassNode classNodefinal BlockStatement wrapper,
            final ASTNode actionNodefinal String actionNamefinal Parameter param,
            final SourceUnit sourcefinal GeneratorContext context) {
        final ClassNode paramTypeClassNode = param.getType();
        final String paramName = param.getName();
        String requestParameterName = paramName;
        List<AnnotationNoderequestParameters = param.getAnnotations(
                new ClassNode(RequestParameter.class));
        if (requestParameters.size() == 1) {
            requestParameterName = requestParameters.get(0).getMember("value").getText();
        }
        if ((.contains(paramTypeClassNode) ||
                .containsKey(paramTypeClassNode))) {
            initializePrimitiveOrTypeWrapperParameter(classNodewrapperparamrequestParameterName);
        } else if (paramTypeClassNode.equals(new ClassNode(String.class))) {
            initializeStringParameter(classNodewrapperparamrequestParameterName);
        } else if (!paramTypeClassNode.equals()) {
            initializeAndValidateCommandObjectParameter(wrapperclassNodeparamTypeClassNode,
                    actionNodeactionNameparamNamesourcecontext);
        }
    }
    protected void initializeAndValidateCommandObjectParameter(final BlockStatement wrapper,
            final ClassNode controllerNodefinal ClassNode commandObjectNode,
            final ASTNode actionNodefinal String actionNamefinal String paramName,
            final SourceUnit sourcefinal GeneratorContext context) {
        final DeclarationExpression declareCoExpression = new DeclarationExpression(
                new VariableExpression(paramNamecommandObjectNode), Token.newSymbol(., 0, 0), new EmptyExpression());
        wrapper.addStatement(new ExpressionStatement(declareCoExpression));
        if(commandObjectNode.isInterface() || Modifier.isAbstract(commandObjectNode.getModifiers())) {
            final String warningMessage = "The [" + actionName + "] action in [" +
                    controllerNode.getName() + "] accepts a parameter of type [" +
                    commandObjectNode.getName() +
                    "].  Interface types and abstract class types are not supported as command objects.  This parameter will be ignored.";
            GrailsASTUtils.warning(sourceactionNodewarningMessage);
        } else {
            initializeCommandObjectParameter(wrappercommandObjectNodeparamNamesource);
            @SuppressWarnings("unchecked")
            boolean argumentIsValidateable = GrailsASTUtils.hasAnyAnnotations(
                    commandObjectNode,
                    grails.validation.Validateable.class,
                    org.codehaus.groovy.grails.validation.Validateable.class,
                    grails.persistence.Entity.class,
                    javax.persistence.Entity.class);
            if (!argumentIsValidateable) {
                final ModuleNode commandObjectModule = commandObjectNode.getModule();
                if (commandObjectModule != null) {
                    if (commandObjectModule == controllerNode.getModule() ||
                            doesModulePathIncludeSubstring(commandObjectModule,
                                    "grails-app" + . + "controllers" + .)) {
                        final ASTValidateableHelper h = new DefaultASTValidateableHelper();
                        h.injectValidateableCode(commandObjectNodefalse);
                        argumentIsValidateable = true;
                    } else if (doesModulePathIncludeSubstring(commandObjectModule,
                            "grails-app" + . + "domain" + .)) {
                        argumentIsValidateable = true;
                    }
                }
            }
            
            if (argumentIsValidateable) {
                final MethodCallExpression validateMethodCallExpression =
                        new MethodCallExpression(new VariableExpression(paramName), "validate");
                final MethodNode validateMethod =
                        commandObjectNode.getMethod("validate"new Parameter[0]);
                if (validateMethod != null) {
                    validateMethodCallExpression.setMethodTarget(validateMethod);
                }
                final Statement ifCommandObjectIsNotNullThenValidate = new IfStatement(new BooleanExpression(new VariableExpression(paramName)), new ExpressionStatement(validateMethodCallExpression), new ExpressionStatement(new EmptyExpression()));
                wrapper.addStatement(ifCommandObjectIsNotNullThenValidate);
            } else {
                // try to dynamically invoke the .validate() method if it is available at runtime...
                final Expression respondsToValidateMethodCallExpression = new MethodCallExpression(
                        new VariableExpression(paramName), "respondsTo"new ArgumentListExpression(
                                new ConstantExpression("validate")));
                final Expression validateMethodCallExpression = new MethodCallExpression(
                        new VariableExpression(paramName), "validate"new ArgumentListExpression());
                final Statement ifRespondsToValidateThenValidateStatement = new IfStatement(
                        new BooleanExpression(respondsToValidateMethodCallExpression),
                        new ExpressionStatement(validateMethodCallExpression),
                        new ExpressionStatement(new EmptyExpression()));
                final Statement ifCommandObjectIsNotNullThenValidate = new IfStatement(new BooleanExpression(new VariableExpression(paramName)), ifRespondsToValidateThenValidateStatementnew ExpressionStatement(new EmptyExpression()));
                wrapper.addStatement(ifCommandObjectIsNotNullThenValidate);
                
                final String warningMessage = "The [" + actionName + "] action accepts a parameter of type [" +
                        commandObjectNode.getName() +
                        "] which has not been marked with @Validateable.  Data binding will still be applied " +
                        "to this command object but the instance will not be validateable.";
                GrailsASTUtils.warning(sourceactionNodewarningMessage);
            }
            if(GrailsASTUtils.isInnerClassNode(commandObjectNode)) {
                final String warningMessage = "The [" + actionName + "] action accepts a parameter of type [" +
                        commandObjectNode.getName() +
                        "] which is an inner class. Command object classes should not be inner classes.";
                GrailsASTUtils.warning(sourceactionNodewarningMessage);
                
            }
            else {
                new DefaultASTDatabindingHelper().injectDatabindingCode(sourcecontextcommandObjectNode);
            }
        }
    }
    protected void initializeCommandObjectParameter(final BlockStatement wrapper,
            final ClassNode commandObjectNodefinal String paramNameSourceUnit source) {
        final ArgumentListExpression initializeCommandObjectArguments = new ArgumentListExpression();
        initializeCommandObjectArguments.addExpression(new ClassExpression(commandObjectNode));
        initializeCommandObjectArguments.addExpression(new ConstantExpression(paramName));
        final MethodCallExpression initializeCommandObjectMethodCall = new MethodCallExpression(new VariableExpression("this"), "initializeCommandObject"initializeCommandObjectArguments);
        applyDefaultMethodTarget(initializeCommandObjectMethodCallcommandObjectNode);
        
        final Expression assignCommandObjectToParameter = new BinaryExpression(new VariableExpression(paramName), Token.newSymbol(., 0, 0), initializeCommandObjectMethodCall);
        
        wrapper.addStatement(new ExpressionStatement(assignCommandObjectToParameter));
    }

    
Checks to see if a Module is defined at a path which includes the specified substring

Parameters:
moduleNode a ModuleNode
substring The substring to search for
Returns:
true if moduleNode is defined at a path which includes the specified substring
    private boolean doesModulePathIncludeSubstring(ModuleNode moduleNodefinal String substring) {
        if (moduleNode == null) {
            return false;
        }
        boolean substringFoundInDescription = false;
        String commandObjectModuleDescription = moduleNode.getDescription();
        if (commandObjectModuleDescription != null) {
            substringFoundInDescription = commandObjectModuleDescription.contains(substring);
        }
        return substringFoundInDescription;
    }
    protected void initializeStringParameter(final ClassNode classNodefinal BlockStatement wrapperfinal Parameter param,
            final String requestParameterName) {
        final ClassNode paramTypeClassNode = param.getType();
        final String methodParamName = param.getName();
        Expression getParamsExpression = buildGetPropertyExpression(new VariableExpression("this"), "params"classNode);
        final Expression paramsContainsKeyMethodArguments = new ArgumentListExpression(
                new ConstantExpression(requestParameterName));
        final BooleanExpression containsKeyExpression = new BooleanExpression(
                applyDefaultMethodTarget(new MethodCallExpression(getParamsExpression"containsKey"paramsContainsKeyMethodArguments), Map.class));
        final Statement initializeParameterStatement = new ExpressionStatement(
                new DeclarationExpression(new VariableExpression(
                        methodParamNameparamTypeClassNode),
                        Token.newSymbol(., 0, 0),
                        new TernaryExpression(containsKeyExpressionbuildGetMapExpression(getParamsExpressionrequestParameterName) , new ConstantExpression(null))));
        wrapper.addStatement(initializeParameterStatement);
    }
    protected void initializePrimitiveOrTypeWrapperParameter(final ClassNode classNodefinal BlockStatement wrapper,
            final Parameter paramfinal String requestParameterName) {
        final ClassNode paramTypeClassNode = param.getType();
        final String methodParamName = param.getName();
        final Expression defaultValueExpression;
        if (paramTypeClassNode.equals(.)) {
            defaultValueExpression = new ConstantExpression(false);
        } else if (.contains(paramTypeClassNode)) {
            defaultValueExpression = new ConstantExpression(0);
        } else {
            defaultValueExpression = new ConstantExpression(null);
        }
        final ConstantExpression paramConstantExpression = new ConstantExpression(requestParameterName);
        final Expression paramsTypeConversionMethodArguments = new ArgumentListExpression(
                paramConstantExpression/*, defaultValueExpression*/new ConstantExpression(null));
        final String conversionMethodName;
        if (.containsKey(paramTypeClassNode)) {
            conversionMethodName = .get(paramTypeClassNode);
        } else {
            conversionMethodName = paramTypeClassNode.getName();
        }
        Expression getParamsExpression = buildGetPropertyExpression(new VariableExpression("this"), "params"classNode);
        final MethodCallExpression retrieveConvertedValueExpression = new MethodCallExpression(
                getParamsExpressionconversionMethodNameparamsTypeConversionMethodArguments);
        Class<?> defaultValueClass = null// choose any
        if("char".equals(conversionMethodName)) {
            // TypeConvertingMap.'char' method has 2 different signatures, choose the one with "Character 'char'(String name, Integer defaultValue)" signature
            defaultValueClass = Integer.class;
        }
        applyMethodTarget(retrieveConvertedValueExpressionTypeConvertingMap.classnulldefaultValueClass);
        final Expression paramsContainsKeyMethodArguments = new ArgumentListExpression(paramConstantExpression);
        final BooleanExpression containsKeyExpression = new BooleanExpression(
                applyDefaultMethodTarget(new MethodCallExpression(getParamsExpression"containsKey"paramsContainsKeyMethodArguments), Map.class));
        final Token equalsToken = Token.newSymbol(., 0, 0);
        final VariableExpression convertedValueExpression = new VariableExpression(
                "___converted_" + methodParamNamenew ClassNode(Object.class));
        final DeclarationExpression declareConvertedValueExpression = new DeclarationExpression(
                convertedValueExpressionequalsTokennew EmptyExpression());
        Statement declareVariableStatement = new ExpressionStatement(declareConvertedValueExpression);
        wrapper.addStatement(declareVariableStatement);
        final VariableExpression methodParamExpression = new VariableExpression(
                methodParamNameparamTypeClassNode);
        final DeclarationExpression declareParameterVariableStatement = new DeclarationExpression(
                methodParamExpressionequalsTokennew EmptyExpression());
        declareVariableStatement = new ExpressionStatement(declareParameterVariableStatement);
        wrapper.addStatement(declareVariableStatement);
        final Expression assignmentExpression = new BinaryExpression(
                convertedValueExpressionequalsToken,
                new TernaryExpression(containsKeyExpressionretrieveConvertedValueExpressiondefaultValueExpression));
        wrapper.addStatement(new ExpressionStatement(assignmentExpression));
        Expression rejectValueMethodCallExpression = getRejectValueExpression(classNodemethodParamName);
        BlockStatement ifConvertedValueIsNullBlockStatement = new BlockStatement();
        ifConvertedValueIsNullBlockStatement.addStatement(
                new ExpressionStatement(rejectValueMethodCallExpression));
        ifConvertedValueIsNullBlockStatement.addStatement(
                new ExpressionStatement(new BinaryExpression(
                        methodParamExpressionequalsTokendefaultValueExpression)));
        final BooleanExpression isConvertedValueNullExpression = new BooleanExpression(new BinaryExpression(
                convertedValueExpression, Token.newSymbol(., 0, 0),
                new ConstantExpression(null)));
        final ExpressionStatement assignConvertedValueToParamStatement = new ExpressionStatement(
                new BinaryExpression(methodParamExpressionequalsTokenconvertedValueExpression));
        final Statement ifStatement = new IfStatement(isConvertedValueNullExpression,
                ifConvertedValueIsNullBlockStatement,
                assignConvertedValueToParamStatement);
        wrapper.addStatement(new IfStatement(new BooleanExpression(containsKeyExpression),
                ifStatementnew ExpressionStatement(new EmptyExpression())));
    }
    protected Expression getRejectValueExpression(final ClassNode classNodefinal String methodParamName) {
        ArgumentListExpression rejectValueArgs = new ArgumentListExpression();
        rejectValueArgs.addExpression(new ConstantExpression(methodParamName));
        rejectValueArgs.addExpression(new ConstantExpression(
                "params." + methodParamName + ".conversion.error"));
        Expression getErrorsExpression = buildGetPropertyExpression(new VariableExpression("this"classNode), "errors"classNode);
        Expression rejectValueMethodCallExpression = applyDefaultMethodTarget(new MethodCallExpression(
                getErrorsExpression"rejectValue"rejectValueArgs), Errors.class);
        return rejectValueMethodCallExpression;
    }
    public void performInjection(SourceUnit sourceClassNode classNode) {
        performInjection(sourcenullclassNode);
    }