From d727461bf004cdaeb9f645cf5b071c7cf666e9c7 Mon Sep 17 00:00:00 2001 From: MarsMuse <13889146832@163.com> Date: Wed, 17 Jul 2019 14:29:58 +0800 Subject: [PATCH] fix bug about the generateReturnAndInvocation method of the class AdaptiveClassCodeGenerator (#4339) * fix bug about the proxy method is called with the old parameter name * fix bug about the proxy method is called with the old parameter name --- .../extension/AdaptiveClassCodeGenerator.java | 765 +++++++++--------- 1 file changed, 384 insertions(+), 381 deletions(-) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java index 50bf9508359..239f862d1c9 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java @@ -1,381 +1,384 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.dubbo.common.extension; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.util.Arrays; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.StringUtils; - -/** - * Code generator for Adaptive class - */ -public class AdaptiveClassCodeGenerator { - - private static final Logger logger = LoggerFactory.getLogger(AdaptiveClassCodeGenerator.class); - - private static final String CLASSNAME_INVOCATION = "org.apache.dubbo.rpc.Invocation"; - - private static final String CODE_PACKAGE = "package %s;\n"; - - private static final String CODE_IMPORTS = "import %s;\n"; - - private static final String CODE_CLASS_DECLARATION = "public class %s$Adaptive implements %s {\n"; - - private static final String CODE_METHOD_DECLARATION = "public %s %s(%s) %s {\n%s}\n"; - - private static final String CODE_METHOD_ARGUMENT = "%s arg%d"; - - private static final String CODE_METHOD_THROWS = "throws %s"; - - private static final String CODE_UNSUPPORTED = "throw new UnsupportedOperationException(\"The method %s of interface %s is not adaptive method!\");\n"; - - private static final String CODE_URL_NULL_CHECK = "if (arg%d == null) throw new IllegalArgumentException(\"url == null\");\n%s url = arg%d;\n"; - - private static final String CODE_EXT_NAME_ASSIGNMENT = "String extName = %s;\n"; - - private static final String CODE_EXT_NAME_NULL_CHECK = "if(extName == null) " - + "throw new IllegalStateException(\"Failed to get extension (%s) name from url (\" + url.toString() + \") use keys(%s)\");\n"; - - private static final String CODE_INVOCATION_ARGUMENT_NULL_CHECK = "if (arg%d == null) throw new IllegalArgumentException(\"invocation == null\"); " - + "String methodName = arg%d.getMethodName();\n"; - - - private static final String CODE_EXTENSION_ASSIGNMENT = "%s extension = (% type; - - private String defaultExtName; - - public AdaptiveClassCodeGenerator(Class type, String defaultExtName) { - this.type = type; - this.defaultExtName = defaultExtName; - } - - /** - * test if given type has at least one method annotated with SPI - */ - private boolean hasAdaptiveMethod() { - return Arrays.stream(type.getMethods()).anyMatch(m -> m.isAnnotationPresent(Adaptive.class)); - } - - /** - * generate and return class code - */ - public String generate() { - // no need to generate adaptive class since there's no adaptive method found. - if (!hasAdaptiveMethod()) { - throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!"); - } - - StringBuilder code = new StringBuilder(); - code.append(generatePackageInfo()); - code.append(generateImports()); - code.append(generateClassDeclaration()); - - Method[] methods = type.getMethods(); - for (Method method : methods) { - code.append(generateMethod(method)); - } - code.append("}"); - - if (logger.isDebugEnabled()) { - logger.debug(code.toString()); - } - return code.toString(); - } - - /** - * generate package info - */ - private String generatePackageInfo() { - return String.format(CODE_PACKAGE, type.getPackage().getName()); - } - - /** - * generate imports - */ - private String generateImports() { - return String.format(CODE_IMPORTS, ExtensionLoader.class.getName()); - } - - /** - * generate class declaration - */ - private String generateClassDeclaration() { - return String.format(CODE_CLASS_DECLARATION, type.getSimpleName(), type.getCanonicalName()); - } - - /** - * generate method not annotated with Adaptive with throwing unsupported exception - */ - private String generateUnsupported(Method method) { - return String.format(CODE_UNSUPPORTED, method, type.getName()); - } - - /** - * get index of parameter with type URL - */ - private int getUrlTypeIndex(Method method) { - int urlTypeIndex = -1; - Class[] pts = method.getParameterTypes(); - for (int i = 0; i < pts.length; ++i) { - if (pts[i].equals(URL.class)) { - urlTypeIndex = i; - break; - } - } - return urlTypeIndex; - } - - /** - * generate method declaration - */ - private String generateMethod(Method method) { - String methodReturnType = method.getReturnType().getCanonicalName(); - String methodName = method.getName(); - String methodContent = generateMethodContent(method); - String methodArgs = generateMethodArguments(method); - String methodThrows = generateMethodThrows(method); - return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent); - } - - /** - * generate method arguments - */ - private String generateMethodArguments(Method method) { - Class[] pts = method.getParameterTypes(); - return IntStream.range(0, pts.length) - .mapToObj(i -> String.format(CODE_METHOD_ARGUMENT, pts[i].getCanonicalName(), i)) - .collect(Collectors.joining(", ")); - } - - /** - * generate method throws - */ - private String generateMethodThrows(Method method) { - Class[] ets = method.getExceptionTypes(); - if (ets.length > 0) { - String list = Arrays.stream(ets).map(Class::getCanonicalName).collect(Collectors.joining(", ")); - return String.format(CODE_METHOD_THROWS, list); - } else { - return ""; - } - } - - /** - * generate method URL argument null check - */ - private String generateUrlNullCheck(int index) { - return String.format(CODE_URL_NULL_CHECK, index, URL.class.getName(), index); - } - - /** - * generate method content - */ - private String generateMethodContent(Method method) { - Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); - StringBuilder code = new StringBuilder(512); - if (adaptiveAnnotation == null) { - return generateUnsupported(method); - } else { - int urlTypeIndex = getUrlTypeIndex(method); - - // found parameter in URL type - if (urlTypeIndex != -1) { - // Null Point check - code.append(generateUrlNullCheck(urlTypeIndex)); - } else { - // did not find parameter in URL type - code.append(generateUrlAssignmentIndirectly(method)); - } - - String[] value = getMethodAdaptiveValue(adaptiveAnnotation); - - boolean hasInvocation = hasInvocationArgument(method); - - code.append(generateInvocationArgumentNullCheck(method)); - - code.append(generateExtNameAssignment(value, hasInvocation)); - // check extName == null? - code.append(generateExtNameNullCheck(value)); - - code.append(generateExtensionAssignment()); - - // return statement - code.append(generateReturnAndInvocation(method)); - } - - return code.toString(); - } - - /** - * generate code for variable extName null check - */ - private String generateExtNameNullCheck(String[] value) { - return String.format(CODE_EXT_NAME_NULL_CHECK, type.getName(), Arrays.toString(value)); - } - - /** - * generate extName assigment code - */ - private String generateExtNameAssignment(String[] value, boolean hasInvocation) { - // TODO: refactor it - String getNameCode = null; - for (int i = value.length - 1; i >= 0; --i) { - if (i == value.length - 1) { - if (null != defaultExtName) { - if (!"protocol".equals(value[i])) { - if (hasInvocation) { - getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); - } else { - getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName); - } - } else { - getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName); - } - } else { - if (!"protocol".equals(value[i])) { - if (hasInvocation) { - getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); - } else { - getNameCode = String.format("url.getParameter(\"%s\")", value[i]); - } - } else { - getNameCode = "url.getProtocol()"; - } - } - } else { - if (!"protocol".equals(value[i])) { - if (hasInvocation) { - getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); - } else { - getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode); - } - } else { - getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode); - } - } - } - - return String.format(CODE_EXT_NAME_ASSIGNMENT, getNameCode); - } - - /** - * @return - */ - private String generateExtensionAssignment() { - return String.format(CODE_EXTENSION_ASSIGNMENT, type.getName(), ExtensionLoader.class.getSimpleName(), type.getName()); - } - - /** - * generate method invocation statement and return it if necessary - */ - private String generateReturnAndInvocation(Method method) { - String returnStatement = method.getReturnType().equals(void.class) ? "" : "return "; - - String args = Arrays.stream(method.getParameters()).map(Parameter::getName).collect(Collectors.joining(", ")); - - return returnStatement + String.format("extension.%s(%s);\n", method.getName(), args); - } - - /** - * test if method has argument of type Invocation - */ - private boolean hasInvocationArgument(Method method) { - Class[] pts = method.getParameterTypes(); - return Arrays.stream(pts).anyMatch(p -> CLASSNAME_INVOCATION.equals(p.getName())); - } - - /** - * generate code to test argument of type Invocation is null - */ - private String generateInvocationArgumentNullCheck(Method method) { - Class[] pts = method.getParameterTypes(); - return IntStream.range(0, pts.length).filter(i -> CLASSNAME_INVOCATION.equals(pts[i].getName())) - .mapToObj(i -> String.format(CODE_INVOCATION_ARGUMENT_NULL_CHECK, i, i)) - .findFirst().orElse(""); - } - - /** - * get value of adaptive annotation or if empty return splitted simple name - */ - private String[] getMethodAdaptiveValue(Adaptive adaptiveAnnotation) { - String[] value = adaptiveAnnotation.value(); - // value is not set, use the value generated from class name as the key - if (value.length == 0) { - String splitName = StringUtils.camelToSplitName(type.getSimpleName(), "."); - value = new String[]{splitName}; - } - return value; - } - - /** - * get parameter with type URL from method parameter: - *

- * test if parameter has method which returns type URL - *

- * if not found, throws IllegalStateException - */ - private String generateUrlAssignmentIndirectly(Method method) { - Class[] pts = method.getParameterTypes(); - - // find URL getter method - for (int i = 0; i < pts.length; ++i) { - for (Method m : pts[i].getMethods()) { - String name = m.getName(); - if ((name.startsWith("get") || name.length() > 3) - && Modifier.isPublic(m.getModifiers()) - && !Modifier.isStatic(m.getModifiers()) - && m.getParameterTypes().length == 0 - && m.getReturnType() == URL.class) { - return generateGetUrlNullCheck(i, pts[i], name); - } - } - } - - // getter method not found, throw - throw new IllegalStateException("Failed to create adaptive class for interface " + type.getName() - + ": not found url parameter or url attribute in parameters of method " + method.getName()); - - } - - /** - * 1, test if argi is null - * 2, test if argi.getXX() returns null - * 3, assign url with argi.getXX() - */ - private String generateGetUrlNullCheck(int index, Class type, String method) { - // Null point check - StringBuilder code = new StringBuilder(); - code.append(String.format("if (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");\n", - index, type.getName())); - code.append(String.format("if (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");\n", - index, method, type.getName(), method)); - - code.append(String.format("%s url = arg%d.%s();\n", URL.class.getName(), index, method)); - return code.toString(); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.dubbo.common.extension; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; + +/** + * Code generator for Adaptive class + */ +public class AdaptiveClassCodeGenerator { + + private static final Logger logger = LoggerFactory.getLogger(AdaptiveClassCodeGenerator.class); + + private static final String CLASSNAME_INVOCATION = "org.apache.dubbo.rpc.Invocation"; + + private static final String CODE_PACKAGE = "package %s;\n"; + + private static final String CODE_IMPORTS = "import %s;\n"; + + private static final String CODE_CLASS_DECLARATION = "public class %s$Adaptive implements %s {\n"; + + private static final String CODE_METHOD_DECLARATION = "public %s %s(%s) %s {\n%s}\n"; + + private static final String CODE_METHOD_ARGUMENT = "%s arg%d"; + + private static final String CODE_METHOD_THROWS = "throws %s"; + + private static final String CODE_UNSUPPORTED = "throw new UnsupportedOperationException(\"The method %s of interface %s is not adaptive method!\");\n"; + + private static final String CODE_URL_NULL_CHECK = "if (arg%d == null) throw new IllegalArgumentException(\"url == null\");\n%s url = arg%d;\n"; + + private static final String CODE_EXT_NAME_ASSIGNMENT = "String extName = %s;\n"; + + private static final String CODE_EXT_NAME_NULL_CHECK = "if(extName == null) " + + "throw new IllegalStateException(\"Failed to get extension (%s) name from url (\" + url.toString() + \") use keys(%s)\");\n"; + + private static final String CODE_INVOCATION_ARGUMENT_NULL_CHECK = "if (arg%d == null) throw new IllegalArgumentException(\"invocation == null\"); " + + "String methodName = arg%d.getMethodName();\n"; + + + private static final String CODE_EXTENSION_ASSIGNMENT = "%s extension = (% type; + + private String defaultExtName; + + public AdaptiveClassCodeGenerator(Class type, String defaultExtName) { + this.type = type; + this.defaultExtName = defaultExtName; + } + + /** + * test if given type has at least one method annotated with SPI + */ + private boolean hasAdaptiveMethod() { + return Arrays.stream(type.getMethods()).anyMatch(m -> m.isAnnotationPresent(Adaptive.class)); + } + + /** + * generate and return class code + */ + public String generate() { + // no need to generate adaptive class since there's no adaptive method found. + if (!hasAdaptiveMethod()) { + throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!"); + } + + StringBuilder code = new StringBuilder(); + code.append(generatePackageInfo()); + code.append(generateImports()); + code.append(generateClassDeclaration()); + + Method[] methods = type.getMethods(); + for (Method method : methods) { + code.append(generateMethod(method)); + } + code.append("}"); + + if (logger.isDebugEnabled()) { + logger.debug(code.toString()); + } + return code.toString(); + } + + /** + * generate package info + */ + private String generatePackageInfo() { + return String.format(CODE_PACKAGE, type.getPackage().getName()); + } + + /** + * generate imports + */ + private String generateImports() { + return String.format(CODE_IMPORTS, ExtensionLoader.class.getName()); + } + + /** + * generate class declaration + */ + private String generateClassDeclaration() { + return String.format(CODE_CLASS_DECLARATION, type.getSimpleName(), type.getCanonicalName()); + } + + /** + * generate method not annotated with Adaptive with throwing unsupported exception + */ + private String generateUnsupported(Method method) { + return String.format(CODE_UNSUPPORTED, method, type.getName()); + } + + /** + * get index of parameter with type URL + */ + private int getUrlTypeIndex(Method method) { + int urlTypeIndex = -1; + Class[] pts = method.getParameterTypes(); + for (int i = 0; i < pts.length; ++i) { + if (pts[i].equals(URL.class)) { + urlTypeIndex = i; + break; + } + } + return urlTypeIndex; + } + + /** + * generate method declaration + */ + private String generateMethod(Method method) { + String methodReturnType = method.getReturnType().getCanonicalName(); + String methodName = method.getName(); + String methodContent = generateMethodContent(method); + String methodArgs = generateMethodArguments(method); + String methodThrows = generateMethodThrows(method); + return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent); + } + + /** + * generate method arguments + */ + private String generateMethodArguments(Method method) { + Class[] pts = method.getParameterTypes(); + return IntStream.range(0, pts.length) + .mapToObj(i -> String.format(CODE_METHOD_ARGUMENT, pts[i].getCanonicalName(), i)) + .collect(Collectors.joining(", ")); + } + + /** + * generate method throws + */ + private String generateMethodThrows(Method method) { + Class[] ets = method.getExceptionTypes(); + if (ets.length > 0) { + String list = Arrays.stream(ets).map(Class::getCanonicalName).collect(Collectors.joining(", ")); + return String.format(CODE_METHOD_THROWS, list); + } else { + return ""; + } + } + + /** + * generate method URL argument null check + */ + private String generateUrlNullCheck(int index) { + return String.format(CODE_URL_NULL_CHECK, index, URL.class.getName(), index); + } + + /** + * generate method content + */ + private String generateMethodContent(Method method) { + Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); + StringBuilder code = new StringBuilder(512); + if (adaptiveAnnotation == null) { + return generateUnsupported(method); + } else { + int urlTypeIndex = getUrlTypeIndex(method); + + // found parameter in URL type + if (urlTypeIndex != -1) { + // Null Point check + code.append(generateUrlNullCheck(urlTypeIndex)); + } else { + // did not find parameter in URL type + code.append(generateUrlAssignmentIndirectly(method)); + } + + String[] value = getMethodAdaptiveValue(adaptiveAnnotation); + + boolean hasInvocation = hasInvocationArgument(method); + + code.append(generateInvocationArgumentNullCheck(method)); + + code.append(generateExtNameAssignment(value, hasInvocation)); + // check extName == null? + code.append(generateExtNameNullCheck(value)); + + code.append(generateExtensionAssignment()); + + // return statement + code.append(generateReturnAndInvocation(method)); + } + + return code.toString(); + } + + /** + * generate code for variable extName null check + */ + private String generateExtNameNullCheck(String[] value) { + return String.format(CODE_EXT_NAME_NULL_CHECK, type.getName(), Arrays.toString(value)); + } + + /** + * generate extName assigment code + */ + private String generateExtNameAssignment(String[] value, boolean hasInvocation) { + // TODO: refactor it + String getNameCode = null; + for (int i = value.length - 1; i >= 0; --i) { + if (i == value.length - 1) { + if (null != defaultExtName) { + if (!"protocol".equals(value[i])) { + if (hasInvocation) { + getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); + } else { + getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName); + } + } else { + getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName); + } + } else { + if (!"protocol".equals(value[i])) { + if (hasInvocation) { + getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); + } else { + getNameCode = String.format("url.getParameter(\"%s\")", value[i]); + } + } else { + getNameCode = "url.getProtocol()"; + } + } + } else { + if (!"protocol".equals(value[i])) { + if (hasInvocation) { + getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); + } else { + getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode); + } + } else { + getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode); + } + } + } + + return String.format(CODE_EXT_NAME_ASSIGNMENT, getNameCode); + } + + /** + * @return + */ + private String generateExtensionAssignment() { + return String.format(CODE_EXTENSION_ASSIGNMENT, type.getName(), ExtensionLoader.class.getSimpleName(), type.getName()); + } + + /** + * generate method invocation statement and return it if necessary + */ + private String generateReturnAndInvocation(Method method) { + String returnStatement = method.getReturnType().equals(void.class) ? "" : "return "; + + String args = IntStream.range(0, method.getParameters().length) + .mapToObj(i -> String.format(CODE_EXTENSION_METHOD_INVOKE_ARGUMENT, i)) + .collect(Collectors.joining(", ")); + + return returnStatement + String.format("extension.%s(%s);\n", method.getName(), args); + } + + /** + * test if method has argument of type Invocation + */ + private boolean hasInvocationArgument(Method method) { + Class[] pts = method.getParameterTypes(); + return Arrays.stream(pts).anyMatch(p -> CLASSNAME_INVOCATION.equals(p.getName())); + } + + /** + * generate code to test argument of type Invocation is null + */ + private String generateInvocationArgumentNullCheck(Method method) { + Class[] pts = method.getParameterTypes(); + return IntStream.range(0, pts.length).filter(i -> CLASSNAME_INVOCATION.equals(pts[i].getName())) + .mapToObj(i -> String.format(CODE_INVOCATION_ARGUMENT_NULL_CHECK, i, i)) + .findFirst().orElse(""); + } + + /** + * get value of adaptive annotation or if empty return splitted simple name + */ + private String[] getMethodAdaptiveValue(Adaptive adaptiveAnnotation) { + String[] value = adaptiveAnnotation.value(); + // value is not set, use the value generated from class name as the key + if (value.length == 0) { + String splitName = StringUtils.camelToSplitName(type.getSimpleName(), "."); + value = new String[]{splitName}; + } + return value; + } + + /** + * get parameter with type URL from method parameter: + *

+ * test if parameter has method which returns type URL + *

+ * if not found, throws IllegalStateException + */ + private String generateUrlAssignmentIndirectly(Method method) { + Class[] pts = method.getParameterTypes(); + + // find URL getter method + for (int i = 0; i < pts.length; ++i) { + for (Method m : pts[i].getMethods()) { + String name = m.getName(); + if ((name.startsWith("get") || name.length() > 3) + && Modifier.isPublic(m.getModifiers()) + && !Modifier.isStatic(m.getModifiers()) + && m.getParameterTypes().length == 0 + && m.getReturnType() == URL.class) { + return generateGetUrlNullCheck(i, pts[i], name); + } + } + } + + // getter method not found, throw + throw new IllegalStateException("Failed to create adaptive class for interface " + type.getName() + + ": not found url parameter or url attribute in parameters of method " + method.getName()); + + } + + /** + * 1, test if argi is null + * 2, test if argi.getXX() returns null + * 3, assign url with argi.getXX() + */ + private String generateGetUrlNullCheck(int index, Class type, String method) { + // Null point check + StringBuilder code = new StringBuilder(); + code.append(String.format("if (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");\n", + index, type.getName())); + code.append(String.format("if (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");\n", + index, method, type.getName(), method)); + + code.append(String.format("%s url = arg%d.%s();\n", URL.class.getName(), index, method)); + return code.toString(); + } + +}