private <T extends Annotation> T findAnnotationOnMethodOrEnclosingType( final JMethod method, final Class<T> annotationType) { T annotation = method.getAnnotation(annotationType); if (annotation == null) { annotation = method.getEnclosingType().getAnnotation(annotationType); } return annotation; }
private String getRestMethod(JMethod method) throws UnableToCompleteException { String restMethod = null; if (method.getAnnotation(DELETE.class) != null) { restMethod = METHOD_DELETE; } else if (method.getAnnotation(GET.class) != null) { restMethod = METHOD_GET; } else if (method.getAnnotation(HEAD.class) != null) { restMethod = METHOD_HEAD; } else if (method.getAnnotation(OPTIONS.class) != null) { restMethod = METHOD_OPTIONS; } else if (method.getAnnotation(POST.class) != null) { restMethod = METHOD_POST; } else if (method.getAnnotation(PUT.class) != null) { restMethod = METHOD_PUT; } else if (method.getAnnotation(JSONP.class) != null) { restMethod = METHOD_JSONP; } else { restMethod = method.getName(); if (!REST_METHODS.contains(restMethod)) { getLogger() .log( ERROR, "Invalid rest method. It must either have a lower case rest method name or have a javax rs method annotation: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } } return restMethod; }
private void writeSubresourceLocatorImpl(JMethod method) throws UnableToCompleteException { JClassType iface = method.getReturnType().isInterface(); if (iface == null || !REST_SERVICE_TYPE.isAssignableFrom(iface)) { getLogger() .log( ERROR, "Invalid subresource locator method. Method must have return type of an interface that extends RestService: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } Path pathAnnotation = method.getAnnotation(Path.class); if (pathAnnotation == null) { getLogger() .log( ERROR, "Invalid subresource locator method. Method must have @Path annotation: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } String pathExpression = wrap(pathAnnotation.value()); for (JParameter arg : method.getParameters()) { PathParam paramPath = arg.getAnnotation(PathParam.class); if (paramPath != null) { pathExpression = pathExpression(pathExpression, arg, paramPath); } } p(method.getReadableDeclaration(false, false, false, false, true) + " {").i(1); { JType type = method.getReturnType(); String name; if (type instanceof JClassType) { JClassType restService = (JClassType) type; RestServiceClassCreator generator = new RestServiceClassCreator(getLogger(), context, restService); name = generator.create(); } else { throw new UnsupportedOperationException("Subresource method may not return: " + type); } p(method.getReturnType().getQualifiedSourceName() + " __subresource = new " + name + "();"); p( "((" + RestServiceProxy.class.getName() + ")__subresource).setResource(getResource().resolve(" + pathExpression + "));"); p("return __subresource;"); } i(-1).p("}"); }
private void writeMethodImpl(JMethod method) throws UnableToCompleteException { boolean returnRequest = false; if (method.getReturnType() != JPrimitiveType.VOID) { if (!method.getReturnType().getQualifiedSourceName().equals(Request.class.getName()) && !method .getReturnType() .getQualifiedSourceName() .equals(JsonpRequest.class.getName())) { getLogger() .log( ERROR, "Invalid rest method. Method must have void, Request or JsonpRequest return types: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } else { returnRequest = true; } } Json jsonAnnotation = source.getAnnotation(Json.class); final Style classStyle = jsonAnnotation != null ? jsonAnnotation.style() : Style.DEFAULT; Options classOptions = source.getAnnotation(Options.class); Options options = method.getAnnotation(Options.class); p(method.getReadableDeclaration(false, false, false, false, true) + " {").i(1); { String restMethod = getRestMethod(method); LinkedList<JParameter> args = new LinkedList<JParameter>(Arrays.asList(method.getParameters())); // the last arg should be the callback. if (args.isEmpty()) { getLogger() .log( ERROR, "Invalid rest method. Method must declare at least a callback argument: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } JParameter callbackArg = args.removeLast(); JClassType callbackType = callbackArg.getType().isClassOrInterface(); JClassType methodCallbackType = METHOD_CALLBACK_TYPE; if (callbackType == null || !callbackType.isAssignableTo(methodCallbackType)) { getLogger() .log( ERROR, "Invalid rest method. Last argument must be a " + methodCallbackType.getName() + " type: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } JClassType resultType = getCallbackTypeGenericClass(callbackType); String pathExpression = null; Path pathAnnotation = method.getAnnotation(Path.class); if (pathAnnotation != null) { pathExpression = wrap(pathAnnotation.value()); } JParameter contentArg = null; HashMap<String, JParameter> queryParams = new HashMap<String, JParameter>(); HashMap<String, JParameter> formParams = new HashMap<String, JParameter>(); HashMap<String, JParameter> headerParams = new HashMap<String, JParameter>(); for (JParameter arg : args) { PathParam paramPath = arg.getAnnotation(PathParam.class); if (paramPath != null) { if (pathExpression == null) { getLogger() .log( ERROR, "Invalid rest method. Invalid @PathParam annotation. Method is missing the @Path annotation: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } pathExpression = pathExpression(pathExpression, arg, paramPath); // .replaceAll(Pattern.quote("{" + paramPath.value() + "}"), // "\"+com.google.gwt.http.client.URL.encodePathSegment(" + toStringExpression(arg) + // ")+\""); if (arg.getAnnotation(Attribute.class) != null) { // allow part of the arg-object participate in as PathParam and the object goes over the // wire contentArg = arg; } continue; } QueryParam queryParam = arg.getAnnotation(QueryParam.class); if (queryParam != null) { queryParams.put(queryParam.value(), arg); continue; } FormParam formParam = arg.getAnnotation(FormParam.class); if (formParam != null) { formParams.put(formParam.value(), arg); continue; } HeaderParam headerParam = arg.getAnnotation(HeaderParam.class); if (headerParam != null) { headerParams.put(headerParam.value(), arg); continue; } if (!formParams.isEmpty()) { getLogger() .log( ERROR, "You can not have both @FormParam parameters and a content parameter: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } if (contentArg != null) { getLogger() .log( ERROR, "Invalid rest method. Only one content parameter is supported: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } contentArg = arg; } String acceptTypeBuiltIn = null; if (callbackType.equals(TEXT_CALLBACK_TYPE)) { acceptTypeBuiltIn = "CONTENT_TYPE_TEXT"; } else if (callbackType.equals(JSON_CALLBACK_TYPE)) { acceptTypeBuiltIn = "CONTENT_TYPE_JSON"; } else if (callbackType.isAssignableTo(OVERLAY_CALLBACK_TYPE)) { acceptTypeBuiltIn = "CONTENT_TYPE_JSON"; } else if (callbackType.equals(XML_CALLBACK_TYPE)) { acceptTypeBuiltIn = "CONTENT_TYPE_XML"; } p("final " + METHOD_CLASS + " __method ="); p("getResource()"); if (pathExpression != null) { p(".resolve(" + pathExpression + ")"); } for (Map.Entry<String, JParameter> entry : queryParams.entrySet()) { String expr = entry.getValue().getName(); JClassType type = entry.getValue().getType().isClassOrInterface(); if (type != null && isQueryParamListType(type)) { p( ".addQueryParams(" + wrap(entry.getKey()) + ", " + toIteratedStringExpression(entry.getValue()) + ")"); } else { p( ".addQueryParam(" + wrap(entry.getKey()) + ", " + toStringExpression(entry.getValue().getType(), expr) + ")"); } } // example: .get() p("." + restMethod + "();"); // Handle JSONP specific configuration... JSONP jsonpAnnotation = method.getAnnotation(JSONP.class); final boolean isJsonp = restMethod.equals(METHOD_JSONP) && jsonpAnnotation != null; if (isJsonp) { if (returnRequest && !method .getReturnType() .getQualifiedSourceName() .equals(JsonpRequest.class.getName())) { getLogger() .log( ERROR, "Invalid rest method. JSONP method must have void or JsonpRequest return types: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } if (jsonpAnnotation.callbackParam().length() > 0) { p( "((" + JSONP_METHOD_CLASS + ")__method).callbackParam(" + wrap(jsonpAnnotation.callbackParam()) + ");"); } if (jsonpAnnotation.failureCallbackParam().length() > 0) { p( "((" + JSONP_METHOD_CLASS + ")__method).failureCallbackParam(" + wrap(jsonpAnnotation.failureCallbackParam()) + ");"); } } else { if (returnRequest && !method.getReturnType().getQualifiedSourceName().equals(Request.class.getName())) { getLogger() .log( ERROR, "Invalid rest method. Non JSONP method must have void or Request return types: " + method.getReadableDeclaration()); throw new UnableToCompleteException(); } } // configure the dispatcher if (options != null && options.dispatcher() != Dispatcher.class) { // use the dispatcher configured for the method. p("__method.setDispatcher(" + options.dispatcher().getName() + ".INSTANCE);"); } else { // use the default dispatcher configured for the service.. p("__method.setDispatcher(this.dispatcher);"); } // configure the expected statuses.. if (options != null && options.expect().length != 0) { // Using method level defined expected status p("__method.expect(" + join(options.expect(), ", ") + ");"); } else if (classOptions != null && classOptions.expect().length != 0) { // Using class level defined expected status p("__method.expect(" + join(classOptions.expect(), ", ") + ");"); } // configure the timeout if (options != null && options.timeout() >= 0) { // Using method level defined value p("__method.timeout(" + options.timeout() + ");"); } else if (classOptions != null && classOptions.timeout() >= 0) { // Using class level defined value p("__method.timeout(" + classOptions.timeout() + ");"); } if (jsonpAnnotation == null) { Produces producesAnnotation = findAnnotationOnMethodOrEnclosingType(method, Produces.class); if (producesAnnotation != null) { p( "__method.header(" + RESOURCE_CLASS + ".HEADER_ACCEPT, " + wrap(producesAnnotation.value()[0]) + ");"); } else { // set the default accept header.... if (acceptTypeBuiltIn != null) { p( "__method.header(" + RESOURCE_CLASS + ".HEADER_ACCEPT, " + RESOURCE_CLASS + "." + acceptTypeBuiltIn + ");"); } else { p( "__method.header(" + RESOURCE_CLASS + ".HEADER_ACCEPT, " + RESOURCE_CLASS + ".CONTENT_TYPE_JSON);"); } } Consumes consumesAnnotation = findAnnotationOnMethodOrEnclosingType(method, Consumes.class); if (consumesAnnotation != null) { p( "__method.header(" + RESOURCE_CLASS + ".HEADER_CONTENT_TYPE, " + wrap(consumesAnnotation.value()[0]) + ");"); } // and set the explicit headers now (could override the accept header) for (Map.Entry<String, JParameter> entry : headerParams.entrySet()) { String expr = entry.getValue().getName(); p( "__method.header(" + wrap(entry.getKey()) + ", " + toStringExpression(entry.getValue().getType(), expr) + ");"); } } if (!formParams.isEmpty()) { p(FORM_POST_CONTENT_CLASS + " __formPostContent = new " + FORM_POST_CONTENT_CLASS + "();"); for (Map.Entry<String, JParameter> entry : formParams.entrySet()) { p( "__formPostContent.addParameter(" + wrap(entry.getKey()) + ", " + toFormStringExpression(entry.getValue(), classStyle) + ");"); } p("__method.form(__formPostContent.getTextContent());"); } if (contentArg != null) { if (contentArg.getType() == STRING_TYPE) { p("__method.text(" + contentArg.getName() + ");"); } else if (contentArg.getType() == JSON_VALUE_TYPE) { p("__method.json(" + contentArg.getName() + ");"); } else if (contentArg.getType().isClass() != null && isOverlayArrayType(contentArg.getType().isClass())) { p("__method.json(new " + JSON_ARRAY_CLASS + "(" + contentArg.getName() + "));"); } else if (contentArg.getType().isClass() != null && contentArg.getType().isClass().isAssignableTo(OVERLAY_VALUE_TYPE)) { p("__method.json(new " + JSON_OBJECT_CLASS + "(" + contentArg.getName() + "));"); } else if (contentArg.getType() == DOCUMENT_TYPE) { p("__method.xml(" + contentArg.getName() + ");"); } else { JClassType contentClass = contentArg.getType().isClass(); if (contentClass == null) { contentClass = contentArg.getType().isClassOrInterface(); if (!locator.isCollectionType(contentClass)) { getLogger().log(ERROR, "Content argument must be a class."); throw new UnableToCompleteException(); } } jsonAnnotation = contentArg.getAnnotation(Json.class); Style style = jsonAnnotation != null ? jsonAnnotation.style() : classStyle; // example: // .json(Listings$_Generated_JsonEncoder_$.INSTANCE.encode(arg0) // ) p( "__method.json(" + locator.encodeExpression(contentClass, contentArg.getName(), style) + ");"); } } List<AnnotationResolver> annotationResolvers = getAnnotationResolvers(context, getLogger()); getLogger() .log( TreeLogger.DEBUG, "found " + annotationResolvers.size() + " additional AnnotationResolvers"); for (AnnotationResolver a : annotationResolvers) { getLogger() .log( TreeLogger.DEBUG, "(" + a.getClass().getName() + ") resolve `" + source.getName() + "#" + method.getName() + "ยด ..."); final Map<String, String[]> addDataParams = a.resolveAnnotation(getLogger(), source, method, restMethod); if (addDataParams != null) { for (String s : addDataParams.keySet()) { final StringBuilder sb = new StringBuilder(); final List<String> classList = Arrays.asList(addDataParams.get(s)); sb.append("["); for (int i = 0; i < classList.size(); ++i) { sb.append("\\\"").append(classList.get(i)).append("\\\""); if ((i + 1) < classList.size()) { sb.append(","); } } sb.append("]"); getLogger() .log(TreeLogger.DEBUG, "add call with (\"" + s + "\", \"" + sb.toString() + "\")"); p("__method.addData(\"" + s + "\", \"" + sb.toString() + "\");"); } } } if (acceptTypeBuiltIn != null) { // TODO: shouldn't we also have a cach in here? p(returnRequest(returnRequest, isJsonp) + "__method.send(" + callbackArg.getName() + ");"); } else if (isJsonp) { p(returnRequest(returnRequest, isJsonp) + "((" + JSONP_METHOD_CLASS + ")__method).send(new " + ABSTRACT_ASYNC_CALLBACK_CLASS + "<" + resultType.getParameterizedQualifiedSourceName() + ">((" + JSONP_METHOD_CLASS + ")__method, " + callbackArg.getName() + ") {") .i(1); { p("protected " + resultType.getParameterizedQualifiedSourceName() + " parseResult(" + JSON_VALUE_CLASS + " result) throws Exception {") .i(1); { if (resultType.getParameterizedQualifiedSourceName().equals("java.lang.Void")) { p("return (java.lang.Void) null;"); } else { p("try {").i(1); { if (resultType.isAssignableTo(locator.LIST_TYPE)) { p("result = new " + JSON_ARRAY_CLASS + "(result.getJavaScriptObject());"); } jsonAnnotation = method.getAnnotation(Json.class); Style style = jsonAnnotation != null ? jsonAnnotation.style() : classStyle; p("return " + locator.decodeExpression(resultType, "result", style) + ";"); } i(-1).p("} catch (Throwable __e) {").i(1); { p( "throw new " + RESPONSE_FORMAT_EXCEPTION_CLASS + "(\"Response was NOT a valid JSON document\", __e);"); } i(-1).p("}"); } } i(-1).p("}"); } i(-1).p("});"); } else { p("try {").i(1); { p(returnRequest(returnRequest, isJsonp) + "__method.send(new " + ABSTRACT_REQUEST_CALLBACK_CLASS + "<" + resultType.getParameterizedQualifiedSourceName() + ">(__method, " + callbackArg.getName() + ") {") .i(1); { p("protected " + resultType.getParameterizedQualifiedSourceName() + " parseResult() throws Exception {") .i(1); { if (resultType.getParameterizedQualifiedSourceName().equals("java.lang.Void")) { p("return (java.lang.Void) null;"); } else { p("try {").i(1); { jsonAnnotation = method.getAnnotation(Json.class); Style style = jsonAnnotation != null ? jsonAnnotation.style() : classStyle; p( "return " + locator.decodeExpression( resultType, JSON_PARSER_CLASS + ".parse(__method.getResponse().getText())", style) + ";"); } i(-1).p("} catch (Throwable __e) {").i(1); { p( "throw new " + RESPONSE_FORMAT_EXCEPTION_CLASS + "(\"Response was NOT a valid JSON document\", __e);"); } i(-1).p("}"); } } i(-1).p("}"); } i(-1).p("});"); } i(-1).p("} catch (" + REQUEST_EXCEPTION_CLASS + " __e) {").i(1); { p(callbackArg.getName() + ".onFailure(__method,__e);"); if (returnRequest) { p("return null;"); } } i(-1).p("}"); } } i(-1).p("}"); }
@Override protected void generate() throws UnableToCompleteException { if (source.isInterface() == null) { getLogger().log(ERROR, "Type is not an interface."); throw new UnableToCompleteException(); } locator = new JsonEncoderDecoderInstanceLocator(context, getLogger()); this.XML_CALLBACK_TYPE = find(XmlCallback.class, getLogger(), context); this.METHOD_CALLBACK_TYPE = find(MethodCallback.class, getLogger(), context); this.TEXT_CALLBACK_TYPE = find(TextCallback.class, getLogger(), context); this.JSON_CALLBACK_TYPE = find(JsonCallback.class, getLogger(), context); this.OVERLAY_CALLBACK_TYPE = find(OverlayCallback.class, getLogger(), context); this.DOCUMENT_TYPE = find(Document.class, getLogger(), context); this.METHOD_TYPE = find(Method.class, getLogger(), context); this.STRING_TYPE = find(String.class, getLogger(), context); this.JSON_VALUE_TYPE = find(JSONValue.class, getLogger(), context); this.OVERLAY_VALUE_TYPE = find(JavaScriptObject.class, getLogger(), context); this.OVERLAY_ARRAY_TYPES = new HashSet<JClassType>(); this.OVERLAY_ARRAY_TYPES.add(find(JsArray.class, getLogger(), context)); this.OVERLAY_ARRAY_TYPES.add(find(JsArrayBoolean.class, getLogger(), context)); this.OVERLAY_ARRAY_TYPES.add(find(JsArrayInteger.class, getLogger(), context)); this.OVERLAY_ARRAY_TYPES.add(find(JsArrayNumber.class, getLogger(), context)); this.OVERLAY_ARRAY_TYPES.add(find(JsArrayString.class, getLogger(), context)); this.QUERY_PARAM_LIST_TYPES = new HashSet<JClassType>(); this.QUERY_PARAM_LIST_TYPES.add(find(List.class, getLogger(), context)); this.QUERY_PARAM_LIST_TYPES.add(find(Set.class, getLogger(), context)); this.REST_SERVICE_TYPE = find(RestService.class, getLogger(), context); String path = null; Path pathAnnotation = source.getAnnotation(Path.class); if (pathAnnotation != null) { path = pathAnnotation.value(); } RemoteServiceRelativePath relativePath = source.getAnnotation(RemoteServiceRelativePath.class); if (relativePath != null) { path = relativePath.value(); } p("private " + RESOURCE_CLASS + " resource = null;"); p(); p("public void setResource(" + RESOURCE_CLASS + " resource) {").i(1); { p("this.resource = resource;"); } i(-1).p("}"); p("public " + RESOURCE_CLASS + " getResource() {").i(1); { p("if (this.resource == null) {").i(1); if (path == null) { p("this.resource = new " + RESOURCE_CLASS + "(" + DEFAULTS_CLASS + ".getServiceRoot());"); } else { p( "this.resource = new " + RESOURCE_CLASS + "(" + DEFAULTS_CLASS + ".getServiceRoot()).resolve(" + quote(path) + ");"); } i(-1).p("}"); p("return this.resource;"); } i(-1).p("}"); Options options = source.getAnnotation(Options.class); if (options != null && options.dispatcher() != Dispatcher.class) { p( "private " + DISPATCHER_CLASS + " dispatcher = " + options.dispatcher().getName() + ".INSTANCE;"); } else { p("private " + DISPATCHER_CLASS + " dispatcher = null;"); } p(); p("public void setDispatcher(" + DISPATCHER_CLASS + " dispatcher) {").i(1); { p("this.dispatcher = dispatcher;"); } i(-1).p("}"); p(); p("public " + DISPATCHER_CLASS + " getDispatcher() {").i(1); { p("return this.dispatcher;"); } i(-1).p("}"); for (JMethod method : source.getInheritableMethods()) { JClassType iface = method.getReturnType().isInterface(); if (iface != null && REST_SERVICE_TYPE.isAssignableFrom(iface)) writeSubresourceLocatorImpl(method); else writeMethodImpl(method); } }
private InjectionNode innerGenerateProxyCode(InjectionNode injectionNode) { AOPProxyAspect aopProxyAspect = injectionNode.getAspect(AOPProxyAspect.class); JDefinedClass definedClass; String proxyClassName = injectionNode.getClassName() + "_AOPProxy"; ASTInjectionAspect injectionAspect = injectionNode.getAspect(ASTInjectionAspect.class); ConstructorInjectionPoint constructorInjectionPoint = injectionAspect.getConstructorInjectionPoint(); ConstructorInjectionPoint proxyConstructorInjectionPoint = new ConstructorInjectionPoint(ASTAccessModifier.PUBLIC); try { definedClass = codeModel._class(JMod.PUBLIC, proxyClassName, ClassType.CLASS); annotateGeneratedClass(definedClass); // extending injectionNode definedClass._extends(codeModel.ref(injectionNode.getClassName())); // copy constructor elements and add aop interceptors JMethod constructor = definedClass.constructor(JMod.PUBLIC); // converting exceptions into runtime exceptions proxyConstructorInjectionPoint.addThrows(constructorInjectionPoint.getThrowsTypes()); for (ASTType throwType : constructorInjectionPoint.getThrowsTypes()) { constructor._throws(codeModel.ref(throwType.getName())); } JBlock constructorBody = constructor.body(); List<JVar> superArguments = new ArrayList<JVar>(); for (InjectionNode node : constructorInjectionPoint.getInjectionNodes()) { String paramName = namer.generateName(node); JVar param = constructor.param(codeModel.ref(node.getClassName()), paramName); superArguments.add(param); proxyConstructorInjectionPoint.addInjectionNode(node); } // super construction JInvocation constructorInvocation = constructorBody.invoke(SUPER_REF); for (JVar paramArgument : superArguments) { constructorInvocation.arg(paramArgument); } // method interceptors Map<ASTMethod, Map<InjectionNode, JFieldVar>> interceptorFields = new HashMap<ASTMethod, Map<InjectionNode, JFieldVar>>(); for (Map.Entry<ASTMethod, Set<InjectionNode>> methodInterceptorEntry : aopProxyAspect.getMethodInterceptors().entrySet()) { buildMethodInterceptor( definedClass, proxyConstructorInjectionPoint, constructor, constructorBody, interceptorFields, methodInterceptorEntry); } } catch (JClassAlreadyExistsException e) { logger.error("JClassAlreadyExistsException while building AOP Proxy", e); } catch (ClassNotFoundException e) { logger.error("ClassNotFoundException while building AOP Proxy", e); } return buildProxyInjectionNode( injectionNode, proxyClassName, injectionAspect, proxyConstructorInjectionPoint); }
private JExpression buildInterceptorChain( JDefinedClass definedClass, ASTMethod method, Map<ASTParameter, JVar> parameterMap, Set<InjectionNode> interceptors, Map<InjectionNode, JFieldVar> interceptorNameMap) { try { JDefinedClass methodExecutionClass = definedClass._class( JMod.PRIVATE | JMod.FINAL, namer.generateClassName(MethodInterceptorChain.MethodExecution.class)); methodExecutionClass._implements(MethodInterceptorChain.MethodExecution.class); // setup constructor with needed parameters JMethod constructor = methodExecutionClass.constructor(JMod.PUBLIC); JBlock constructorbody = constructor.body(); List<JExpression> methodParameters = new ArrayList<JExpression>(); for (ASTParameter parameter : method.getParameters()) { JType parameterType = parameterMap.get(parameter).type(); JVar param = constructor.param(parameterType, namer.generateName(parameterType)); JFieldVar field = methodExecutionClass.field( JMod.PRIVATE, parameterType, namer.generateName(parameterType)); constructorbody.assign(field, param); methodParameters.add(field); } // getMethod() JMethod getMethod = methodExecutionClass.method( JMod.PUBLIC, Method.class, MethodInterceptorChain.MethodExecution.GET_METHOD); JInvocation getMethodInvocation = definedClass.dotclass().invoke(CLASS_GET_METHOD).arg(method.getName()); getMethod.body()._return(getMethodInvocation); getMethod._throws(NoSuchMethodException.class); for (ASTParameter astParameter : method.getParameters()) { getMethodInvocation.arg(codeModel.ref(astParameter.getASTType().getName()).dotclass()); } // invoke() JMethod invokeMethod = methodExecutionClass.method( JMod.PUBLIC, Object.class, MethodInterceptorChain.MethodExecution.INVOKE); // add all throws of contained method for (ASTType throwable : method.getThrowsTypes()) { invokeMethod._throws(codeModel.ref(throwable.getName())); } JInvocation superCall = definedClass.staticRef(SUPER_REF).invoke(method.getName()); for (JExpression methodParam : methodParameters) { superCall.arg(methodParam); } if (method.getReturnType().equals(ASTVoidType.VOID)) { invokeMethod.body().add(superCall); invokeMethod.body()._return(JExpr._null()); } else { invokeMethod.body()._return(superCall); } JInvocation methodExecutionInvocation = JExpr._new(methodExecutionClass); for (ASTParameter astParameter : method.getParameters()) { methodExecutionInvocation.arg(parameterMap.get(astParameter)); } JInvocation newInterceptorInvocation = JExpr._new(codeModel.ref(MethodInterceptorChain.class)) .arg(methodExecutionInvocation) .arg(JExpr._this()); for (InjectionNode interceptor : interceptors) { newInterceptorInvocation.arg(interceptorNameMap.get(interceptor)); } return newInterceptorInvocation; } catch (JClassAlreadyExistsException e) { throw new TransfuseAnalysisException("Class already defined while generating inner class", e); } }
private void buildMethodInterceptor( JDefinedClass definedClass, ConstructorInjectionPoint proxyConstructorInjectionPoint, JMethod constructor, JBlock constructorBody, Map<ASTMethod, Map<InjectionNode, JFieldVar>> interceptorFields, Map.Entry<ASTMethod, Set<InjectionNode>> methodInterceptorEntry) throws ClassNotFoundException { ASTMethod method = methodInterceptorEntry.getKey(); if (method.getAccessModifier().equals(ASTAccessModifier.PRIVATE)) { throw new TransfuseAnalysisException("Unable to provide AOP on private methods"); } if (!interceptorFields.containsKey(methodInterceptorEntry.getKey())) { interceptorFields.put( methodInterceptorEntry.getKey(), new HashMap<InjectionNode, JFieldVar>()); } Map<InjectionNode, JFieldVar> injectionNodeInstanceNameMap = interceptorFields.get(methodInterceptorEntry.getKey()); // setup interceptor fields for (InjectionNode interceptorInjectionNode : methodInterceptorEntry.getValue()) { String interceptorInstanceName = namer.generateName(interceptorInjectionNode); JFieldVar interceptorField = definedClass.field( JMod.PRIVATE, codeModel.ref(interceptorInjectionNode.getClassName()), interceptorInstanceName); injectionNodeInstanceNameMap.put(interceptorInjectionNode, interceptorField); JVar interceptorParam = constructor.param( codeModel.ref(interceptorInjectionNode.getClassName()), namer.generateName(interceptorInjectionNode)); constructorBody.assign(interceptorField, interceptorParam); proxyConstructorInjectionPoint.addInjectionNode(interceptorInjectionNode); } JType returnType = codeModel.parseType(method.getReturnType().getName()); JMethod methodDeclaration = definedClass.method( method.getAccessModifier().getCodeModelJMod(), returnType, method.getName()); JBlock body = methodDeclaration.body(); // define method parameter Map<ASTParameter, JVar> parameterMap = new HashMap<ASTParameter, JVar>(); for (ASTParameter parameter : method.getParameters()) { parameterMap.put( parameter, methodDeclaration.param( JMod.FINAL, codeModel.ref(parameter.getASTType().getName()), namer.generateName(parameter.getASTType()))); } // aop interceptor Map<InjectionNode, JFieldVar> interceptorNameMap = interceptorFields.get(methodInterceptorEntry.getKey()); JArray paramArray = JExpr.newArray(codeModel.ref(Object.class)); for (ASTParameter astParameter : method.getParameters()) { paramArray.add(parameterMap.get(astParameter)); } JInvocation interceptorInvocation = buildInterceptorChain( definedClass, method, parameterMap, methodInterceptorEntry.getValue(), interceptorNameMap) .invoke("invoke"); interceptorInvocation.arg(paramArray); if (method.getReturnType().equals(ASTVoidType.VOID)) { body.add(interceptorInvocation); } else { body._return(JExpr.cast(returnType.boxify(), interceptorInvocation)); } }