protected String toStringExpression(JParameter arg) { Attribute attribute = arg.getAnnotation(Attribute.class); if (attribute != null) { return arg.getName() + "." + attribute.value(); } return toStringExpression(arg.getType(), arg.getName()); }
protected String toFormStringExpression(JParameter argument, Style classStyle) throws UnableToCompleteException { JType type = argument.getType(); String expr = argument.getName(); if (type.isPrimitive() != null) { return "\"\"+" + expr; } if (STRING_TYPE == type) { return expr; } if (type.isClass() != null && isOverlayArrayType(type.isClass())) { return "(new " + JSON_ARRAY_CLASS + "(" + expr + ")).toString()"; } if (type.isClass() != null && OVERLAY_VALUE_TYPE.isAssignableFrom(type.isClass())) { return "(new " + JSON_OBJECT_CLASS + "(" + expr + ")).toString()"; } if (type.getQualifiedBinaryName().startsWith("java.lang.")) { return String.format("(%s != null ? %s.toString() : null)", expr, expr); } Json jsonAnnotation = argument.getAnnotation(Json.class); final Style style = jsonAnnotation != null ? jsonAnnotation.style() : classStyle; return locator.encodeExpression(type, expr, style) + ".toString()"; }
protected String toIteratedStringExpression(JParameter arg) { StringBuilder result = new StringBuilder(); result .append("new org.fusesource.restygwt.client.StringIterable (") .append(arg.getName()) .append(")"); return result.toString(); }
/** * @param srcWriter * @param type * @param parentVariable * @param added * @param iocContainerVariable * @param configurations */ private static void injectMethods( SourcePrinter srcWriter, JClassType type, String parentVariable, Set<String> added, String iocContainerVariable, Map<String, IocConfig<?>> configurations) { for (JMethod method : type.getMethods()) { Inject inject = method.getAnnotation(Inject.class); if (inject != null && !method.isStatic()) { String methodName = method.getName(); if (!added.contains(methodName + "()")) { added.add(methodName + "()"); JParameter[] parameters = method.getParameters(); List<String> params = new ArrayList<String>(); for (JParameter parameter : parameters) { JType parameterType = parameter.getType(); if ((parameterType.isPrimitive() != null)) { throw new IoCException( "IoC Error Method [" + methodName + "] from class [" + type.getQualifiedSourceName() + "] declares an invalid parameter. Primitive types are not allowed here"); } String variableName = "parameter_" + methodName + "_" + parameter.getName(); params.add(variableName); String injectionExpression = getParameterInjectionExpression(parameter, iocContainerVariable, configurations); srcWriter.println( parameterType.getQualifiedSourceName() + " " + variableName + " = " + injectionExpression + ";"); } srcWriter.print(parentVariable + "." + methodName + "("); boolean first = true; for (String param : params) { if (!first) { srcWriter.print(", "); } first = false; srcWriter.print(param); } srcWriter.println(");"); } } } }
@SuppressWarnings("deprecation") private static String getParameterInjectionExpression( JParameter parameter, String iocContainerVariable, Map<String, IocConfig<?>> configurations) { JType parameterType = parameter.getType(); if (parameterType.isClassOrInterface() != null) { String fieldTypeName = parameterType.getQualifiedSourceName(); IocConfigImpl<?> iocConfig = (IocConfigImpl<?>) configurations.get(fieldTypeName); if (iocConfig != null) { Inject inject = getInjectAnnotation(parameter); if (inject.scope().equals(org.cruxframework.crux.core.client.ioc.Inject.Scope.DEFAULT)) { return iocContainerVariable + ".get" + fieldTypeName.replace('.', '_') + "(" + Scope.class.getCanonicalName() + "." + iocConfig.getScope().name() + ", null)"; } return iocContainerVariable + ".get" + fieldTypeName.replace('.', '_') + "(" + Scope.class.getCanonicalName() + "." + getScopeName(inject.scope()) + ", " + EscapeUtils.quote(inject.subscope()) + ")"; } else { return "GWT.create(" + fieldTypeName + ".class)"; } } else { throw new IoCException( "Error injecting parameter [" + parameter.getName() + "] from method [" + parameter.getEnclosingMethod().getReadableDeclaration() + "]. Primitive fields can not be handled by ioc container."); } }
@Override protected void generateWrapperMethod(JMethod method, SourcePrinter srcWriter) { if (mustDelegateToController(method)) { JType returnType = method.getReturnType().getErasedType(); srcWriter.println(method.getReadableDeclaration(false, false, false, false, true) + "{"); if (returnType != JPrimitiveType.VOID) { srcWriter.print("return "); } srcWriter.print("this._controller." + method.getName() + "("); boolean needsComma = false; for (JParameter parameter : method.getParameters()) { if (needsComma) { srcWriter.print(", "); } needsComma = true; srcWriter.print(parameter.getName()); } srcWriter.println(");"); srcWriter.println("}"); } }
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("}"); }
public void generateMethodParamToBodyCode( SourcePrinter srcWriter, RestMethodInfo methodInfo, String builder, String httpMethod) { JParameter[] parameters = methodInfo.method.getParameters(); boolean formEncoded = false; boolean hasBodyObject = false; String formString = getFormString(methodInfo); if (!StringUtils.isEmpty(formString)) { srcWriter.println("String requestData = " + EscapeUtils.quote(formString) + ";"); } for (int i = 0; i < methodInfo.parameterAnnotations.length; i++) { Annotation[] annotations = methodInfo.parameterAnnotations[i]; if (annotations == null || annotations.length == 0) { // JSON on body if (hasBodyObject) { throw new CruxGeneratorException( "Invalid Method: " + methodInfo.method.getEnclosingType().getName() + "." + methodInfo.method.getName() + "(). " + "Request body can not contain more than one body parameter (JSON serialized object)."); } hasBodyObject = true; String serializerName = new JSonSerializerProxyCreator(context, logger, parameters[i].getType()).create(); srcWriter.println( builder + ".setHeader(\"" + HttpHeaderNames.CONTENT_TYPE + "\", \"application/json\");"); srcWriter.println( "JSONValue serialized = new " + serializerName + "().encode(" + parameters[i].getName() + ");"); srcWriter.println( "String requestData = (serialized==null||serialized.isNull()!=null)?null:serialized.toString();"); } else { for (Annotation annotation : annotations) { JParameter parameter = parameters[i]; JType parameterType = parameter.getType(); String parameterName = parameter.getName(); formEncoded = generateMethodParamToBodyCodeForAnnotatedParameter( srcWriter, builder, parameters, formEncoded, i, annotation, parameterType, parameterName); } } } if (hasBodyObject && formEncoded) { throw new CruxGeneratorException( "Invalid Method: " + methodInfo.method.getEnclosingType().getName() + "." + methodInfo.method.getName() + "(). " + "Request body can not contain form parameters and a JSON serialized object."); } if (hasBodyObject || formEncoded) { if (httpMethod.equals("GET")) { throw new CruxGeneratorException( "Invalid Method: " + methodInfo.method.getEnclosingType().getName() + "." + methodInfo.method.getName() + "(). " + "Can not use request body parameters on a GET operation."); } srcWriter.println(builder + ".setRequestData(requestData);"); } }
/** * Generates the client's asynchronous proxy method. * * @param serializableTypeOracle the type oracle */ protected void generateProxyMethod( SourceWriter w, SerializableTypeOracle serializableTypeOracle, TypeOracle typeOracle, JMethod syncMethod, JMethod asyncMethod) { w.println(); // Write the method signature JType asyncReturnType = asyncMethod.getReturnType().getErasedType(); w.print("public "); w.print(asyncReturnType.getQualifiedSourceName()); w.print(" "); w.print(asyncMethod.getName() + "("); boolean needsComma = false; NameFactory nameFactory = new NameFactory(); JParameter[] asyncParams = asyncMethod.getParameters(); for (int i = 0; i < asyncParams.length; ++i) { JParameter param = asyncParams[i]; if (needsComma) { w.print(", "); } else { needsComma = true; } /* * Ignoring the AsyncCallback parameter, if any method requires a call to * SerializationStreamWriter.writeObject we need a try catch block */ JType paramType = param.getType(); paramType = paramType.getErasedType(); w.print(paramType.getQualifiedSourceName()); w.print(" "); String paramName = param.getName(); nameFactory.addName(paramName); w.print(paramName); } w.println(") {"); w.indent(); String helperName = nameFactory.createName("helper"); String helperClassName = RemoteServiceProxy.ServiceHelper.class.getCanonicalName(); w.println( "%s %s = new %s(\"%s\", \"%s\");", helperClassName, helperName, helperClassName, getProxySimpleName(), syncMethod.getName()); w.println("try {"); w.indent(); // Write the parameter count followed by the parameter values JParameter[] syncParams = syncMethod.getParameters(); String streamWriterName = nameFactory.createName("streamWriter"); w.println( "%s %s = %s.start(REMOTE_SERVICE_INTERFACE_NAME, %s);", SerializationStreamWriter.class.getSimpleName(), streamWriterName, helperName, syncParams.length); for (JParameter param : syncParams) { JType paramType = param.getType().getErasedType(); String typeNameExpression = computeTypeNameExpression(paramType); assert typeNameExpression != null : "Could not compute a type name for " + paramType.getQualifiedSourceName(); w.println(streamWriterName + ".writeString(" + typeNameExpression + ");"); } // Encode all of the arguments to the asynchronous method, but exclude the // last argument which is the callback instance. // for (int i = 0; i < asyncParams.length - 1; ++i) { JParameter asyncParam = asyncParams[i]; w.print(streamWriterName + "."); w.print(Shared.getStreamWriteMethodNameFor(asyncParam.getType())); w.println("(" + asyncParam.getName() + ");"); } /* * Depending on the return type for the async method, return a * RequestBuilder, a Request, or nothing at all. */ JParameter callbackParam = asyncParams[asyncParams.length - 1]; JType returnType = syncMethod.getReturnType(); String callbackName = callbackParam.getName(); if (asyncReturnType == JPrimitiveType.VOID) { w.println( "%s.finish(%s, ResponseReader.%s);", helperName, callbackName, getResponseReaderFor(returnType).name()); } else if (asyncReturnType.getQualifiedSourceName().equals(RequestBuilder.class.getName())) { w.println( "return %s.finishForRequestBuilder(%s, ResponseReader.%s);", helperName, callbackName, getResponseReaderFor(returnType).name()); } else if (asyncReturnType.getQualifiedSourceName().equals(Request.class.getName())) { w.println( "return %s.finish(%s, ResponseReader.%s);", helperName, callbackName, getResponseReaderFor(returnType).name()); } else { // This method should have been caught by RemoteServiceAsyncValidator throw new RuntimeException( "Unhandled return type " + asyncReturnType.getQualifiedSourceName()); } w.outdent(); w.print("} catch (SerializationException "); String exceptionName = nameFactory.createName("ex"); w.println(exceptionName + ") {"); w.indent(); if (!asyncReturnType.getQualifiedSourceName().equals(RequestBuilder.class.getName())) { /* * If the method returns void or Request, signal the serialization error * immediately. If the method returns RequestBuilder, the error will be * signaled whenever RequestBuilder.send() is invoked. */ w.println(callbackName + ".onFailure(" + exceptionName + ");"); } if (asyncReturnType.getQualifiedSourceName().equals(RequestBuilder.class.getName())) { w.println( "return new " + FailingRequestBuilder.class.getName() + "(" + exceptionName + ", " + callbackName + ");"); } else if (asyncReturnType.getQualifiedSourceName().equals(Request.class.getName())) { w.println("return new " + FailedRequest.class.getName() + "();"); } else { assert asyncReturnType == JPrimitiveType.VOID; } w.outdent(); w.println("}"); w.outdent(); w.println("}"); }
@Override public String getName() { return parameter.getName(); }
private void writeMethodImpl(JMethod method) throws UnableToCompleteException { if (method.getReturnType().isPrimitive() != JPrimitiveType.VOID) { error( "Invalid rest method. Method must have void return type: " + method.getReadableDeclaration()); } 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()) { error( "Invalid rest method. Method must declare at least a callback argument: " + method.getReadableDeclaration()); } JParameter callbackArg = args.removeLast(); JClassType callbackType = callbackArg.getType().isClassOrInterface(); JClassType methodCallbackType = METHOD_CALLBACK_TYPE; if (callbackType == null || !callbackType.isAssignableTo(methodCallbackType)) { error( "Invalid rest method. Last argument must be a " + methodCallbackType.getName() + " type: " + method.getReadableDeclaration()); } 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> headerParams = new HashMap<String, JParameter>(); for (JParameter arg : args) { PathParam paramPath = arg.getAnnotation(PathParam.class); if (paramPath != null) { if (pathExpression == null) { error( "Invalid rest method. Invalid @PathParam annotation. Method is missing the @Path annotation: " + method.getReadableDeclaration()); } pathExpression = pathExpression.replaceAll( Pattern.quote("{" + paramPath.value() + "}"), "\"+" + toStringExpression(arg) + "+\""); continue; } QueryParam queryParam = arg.getAnnotation(QueryParam.class); if (queryParam != null) { queryParams.put(queryParam.value(), arg); continue; } HeaderParam headerParam = arg.getAnnotation(HeaderParam.class); if (headerParam != null) { headerParams.put(headerParam.value(), arg); continue; } if (contentArg != null) { error( "Invalid rest method. Only one content parameter is supported: " + method.getReadableDeclaration()); } 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("this.resource"); if (pathExpression != null) { p(".resolve(" + pathExpression + ")"); } for (Map.Entry<String, JParameter> entry : queryParams.entrySet()) { String expr = entry.getValue().getName(); p( ".addQueryParam(" + wrap(entry.getKey()) + ", " + toStringExpression(entry.getValue().getType(), expr) + ")"); } // example: .get() p("." + restMethod + "();"); // Handle JSONP specific configuration... JSONP jsonpAnnotation = method.getAnnotation(JSONP.class); if (restMethod.equals(METHOD_JSONP) && jsonpAnnotation != null) { 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()) + ");"); } } // 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() + ");"); } 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 (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) { error("Content argument must be a class."); } 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) + ");"); } } if (acceptTypeBuiltIn != null) { p("__method.send(" + callbackArg.getName() + ");"); } else { p("try {").i(1); { p("__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) new java.lang.Object();"); } 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);"); } i(-1).p("}"); } } i(-1).p("}"); }