This is an automated email from the ASF dual-hosted git repository.
iluo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/master by this push:
new d727461 fix bug about the generateReturnAndInvocation method of the
class AdaptiveClassCodeGenerator (#4339)
d727461 is described below
commit d727461bf004cdaeb9f645cf5b071c7cf666e9c7
Author: MarsMuse <[email protected]>
AuthorDate: Wed Jul 17 14:29:58 2019 +0800
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 50bf950..239f862 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 =
(%<s)%s.getExtensionLoader(%s.class).getExtension(extName);\n";
-
- private final Class<?> 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
<code>SPI</code>
- */
- 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 <code>Invocation</code>
- */
- 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 <code>Invocation</code> 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 <code>URL</code> from method parameter:
- * <p>
- * test if parameter has method which returns type <code>URL</code>
- * <p>
- * 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 =
(%<s)%s.getExtensionLoader(%s.class).getExtension(extName);\n";
+
+ private static final String CODE_EXTENSION_METHOD_INVOKE_ARGUMENT = "arg%d
";
+
+ private final Class<?> 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
<code>SPI</code>
+ */
+ 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 <code>Invocation</code>
+ */
+ 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 <code>Invocation</code> 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 <code>URL</code> from method parameter:
+ * <p>
+ * test if parameter has method which returns type <code>URL</code>
+ * <p>
+ * 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();
+ }
+
+}