deprecated processor
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7ddde64
--- /dev/null
+++ b/README.md
@@ -0,0 +1,46 @@
+# dubbo-async-processor
+Async source processor for Dubbo service.
+
+This extension provides a more convenient way to use Dubbo service on consumer side by adding future-style counterpart for each sync method.
+
+For example, you have a normal Dubbo service, you have to do the following three steps:**(Please notice that all these should be done by developers defining the interface, normally it's service provider on Dubbo)**
+1. Add @DubboAsync to your interface.
+```java
+@DubboAsync
+public interface GreetingsService {
+ String sayHi(String name);
+}
+```
+2. Add the following configuration to your pom:
+```xml
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-async-processer</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </dependency>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.7.0</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>com.alibaba</groupId>
+ <artifactId>dubbo-async-processer</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+```
+
+3. Now you can package your service (xxx-api.jar) as normal, the processor will help you generating an Async Dubbo service besides the sync interface:
+```java
+@javax.annotation.Generated("com.alibaba.dubbo.async.processor.AsyncAnnotationProcessor")
+@com.alibaba.dubbo.config.annotation.AsyncFor(com.alibaba.dubbo.samples.api.GreetingsService.class)
+public interface GreetingsServiceAsync extends GreetingsService {
+CompletableFuture<java.lang.String> sayHiAsync(java.lang.String name);
+}
+```
diff --git a/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java b/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java
new file mode 100644
index 0000000..5bbd8ad
--- /dev/null
+++ b/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java
@@ -0,0 +1,331 @@
+/*
+ * 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 com.alibaba.dubbo.config.async;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@SupportedAnnotationTypes({"com.alibaba.dubbo.config.async.DubboAsync"})
+public class AsyncAnnotationProcessor extends AbstractProcessor {
+
+ private static final String OBJECT_NAME = "java.lang.Object";
+
+ private static final String FUTURE_NAME = "CompletableFuture";
+
+ @Override
+ public synchronized void init(ProcessingEnvironment processingEnv) {
+ super.init(processingEnv);
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver()) return false;
+ Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(DubboAsync.class);
+ if (elements == null || elements.isEmpty()) return false;
+
+ for (Element element : elements) {
+ if (element.getKind() == ElementKind.INTERFACE) {
+ generateAsyncInterface((TypeElement) element);
+ }
+ }
+
+ return false;
+ }
+
+ private void generateAsyncInterface(TypeElement element) {
+ Name qualified = element.getQualifiedName();
+ if (qualified == null) return;
+ String qualifiedName = qualified.toString();
+ if (qualifiedName.length() == 0) return;
+
+
+ String className = element.getSimpleName().toString();
+ PackageElement packageElement = (PackageElement) element.getEnclosingElement();
+ String packageName = packageElement.getQualifiedName().toString();
+
+
+ StringBuilder result = new StringBuilder();
+ startAsyncInterface(result, qualifiedName, className, packageName);
+ generateAsyncMethods(result, element);
+ endAsyncInterface(result);
+
+ Writer writer = null;
+ try {
+ JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(qualifiedName + "Async");
+ if (sourceFile.getLastModified() > 0) return;
+
+ writer = sourceFile.openWriter();
+ writer.write(result.toString());
+ writer.close();
+ } catch (IOException e) {
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Failed to generate async interface.");
+ } finally {
+ close(writer);
+ }
+ }
+
+ private void generateAsyncMethods(StringBuilder result, TypeElement typeElement) {
+ List<? extends Element> elements = typeElement.getEnclosedElements();
+ Set<String> existMethods = extractExistMethods(elements);
+ for (Element element : elements) {
+ if (element.getKind() != ElementKind.METHOD) continue;
+ generateAsyncMethod(result, (ExecutableElement) element, existMethods);
+ }
+ }
+
+ private Set<String> extractExistMethods(List<? extends Element> elements) {
+ Set<String> result = new HashSet<String>();
+ for (Element element : elements) {
+ result.add(element.getSimpleName().toString());
+ }
+ return result;
+ }
+
+ private void generateAsyncMethod(StringBuilder result, ExecutableElement element, Set<String> existMethods) {
+ String asyncMethodName = element.getSimpleName().toString() + "Async";
+ if (existMethods.contains(asyncMethodName)) return;
+
+ appendTypeParameters(result, element);
+ appendReturnType(result, element);
+ result.append(asyncMethodName).append('(');
+ appendParameters(result, element);
+ result.append(");");
+ }
+
+ // generic parameter type
+ private void appendTypeParameters(StringBuilder result, ExecutableElement element) {
+ List<? extends TypeParameterElement> typeParameters = element.getTypeParameters();
+ if (typeParameters == null || typeParameters.size() == 0) return;
+
+ result.append("<");
+ int i = 1;
+ for (TypeParameterElement typeParameter : typeParameters) {
+ result.append(typeParameter.getSimpleName().toString());
+ appendBounds(result, typeParameter);
+ if (i++ < typeParameters.size()) result.append(",");
+ }
+ result.append("> ");
+ }
+
+ // return type
+ private void appendReturnType(StringBuilder result, ExecutableElement element) {
+ TypeMirror returnType = element.getReturnType();
+ if (returnType.getKind() == TypeKind.VOID) {
+ result.append(FUTURE_NAME).append(" ");
+ } else {
+ result.append(FUTURE_NAME).append('<').append(type2ReturnName(returnType)).append("> ");
+ }
+ }
+
+ // parameters
+ private void appendParameters(StringBuilder result, ExecutableElement method) {
+ List<? extends VariableElement> parameters = method.getParameters();
+ int i = 1;
+ for (VariableElement element : parameters) {
+ result.append(type2ParameterName(element.asType())).append(" ").append(element.getSimpleName().toString());
+ if (i++ < parameters.size()) {
+ result.append(",");
+ }
+ }
+ }
+
+ private void appendBounds(StringBuilder result, TypeParameterElement typeParameter) {
+ List<? extends TypeMirror> bounds = typeParameter.getBounds();
+ if (bounds == null || bounds.size() == 0) return;
+ if (bounds.size() == 1) {
+ String boundName = type2ReturnName(bounds.get(0));
+ if (OBJECT_NAME.equals(boundName)) return;
+ }
+
+ result.append(" extends ");
+ int i = 1;
+ for (TypeMirror bound : bounds) {
+ String boundName = type2ReturnName(bound);
+ result.append(boundName);
+ if (i < bounds.size()) result.append(",");
+ }
+ }
+
+ private String type2ReturnName(TypeMirror typeMirror) {
+ TypeKind kind = typeMirror.getKind();
+ if (kind == TypeKind.VOID) return "";
+ if (kind == TypeKind.ARRAY) {
+ ArrayType arrayType = (ArrayType) typeMirror;
+ TypeMirror componentType = arrayType.getComponentType();
+ return type2ReturnName(componentType) + "[]";
+ }
+ if (kind == TypeKind.BOOLEAN) {
+ return "Boolean";
+ }
+ if (kind == TypeKind.BYTE) {
+ return "Byte";
+ }
+ if (kind == TypeKind.CHAR) {
+ return "Char";
+ }
+ if (kind == TypeKind.DOUBLE) {
+ return "Double";
+ }
+ if (kind == TypeKind.FLOAT) {
+ return "Float";
+ }
+ if (kind == TypeKind.INT) {
+ return "Integer";
+ }
+ if (kind == TypeKind.LONG) {
+ return "Long";
+ }
+ if (kind == TypeKind.SHORT) {
+ return "Short";
+ }
+ if (kind == TypeKind.DECLARED) {
+ DeclaredType declaredType = (DeclaredType) typeMirror;
+ Element element = declaredType.asElement();
+ List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
+ if (typeArguments == null || typeArguments.size() == 0) {
+ return typeName(element);
+ }
+
+ StringBuilder result = new StringBuilder();
+ result.append(typeName(element)).append("<");
+ int i = 1;
+ for (TypeMirror typeArgument : typeArguments) {
+ result.append(type2ReturnName(typeArgument));
+ if (i++ < typeArguments.size()) result.append(",");
+ }
+ result.append(">");
+ return result.toString();
+ }
+ if (kind == TypeKind.TYPEVAR) {
+ TypeVariable typeVariable = (TypeVariable) typeMirror;
+ return typeVariable.asElement().getSimpleName().toString();
+ }
+ if (kind == TypeKind.WILDCARD) {
+ WildcardType wildcardType = (WildcardType) typeMirror;
+ StringBuilder result = new StringBuilder();
+ result.append("?");
+ appendSuperBound(result, wildcardType.getSuperBound());
+ appendExtendsBound(result, wildcardType.getExtendsBound());
+ return result.toString();
+ }
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, kind.toString());
+ return "";
+ }
+
+ private void appendExtendsBound(StringBuilder resut, TypeMirror extendsBound) {
+ if (extendsBound == null) return;
+ String name = type2ReturnName(extendsBound);
+ if (name.equals(OBJECT_NAME)) return;
+ resut.append(" extends ").append(name);
+ }
+
+ private void appendSuperBound(StringBuilder result, TypeMirror superBound) {
+ if (superBound == null) return;
+ String name = type2ReturnName(superBound);
+ if (name.equals(OBJECT_NAME)) return;
+ result.append(" super ").append(name);
+ }
+
+ private String type2ParameterName(TypeMirror typeMirror) {
+ TypeKind kind = typeMirror.getKind();
+ if (kind == TypeKind.BOOLEAN) {
+ return "boolean";
+ }
+ if (kind == TypeKind.BYTE) {
+ return "byte";
+ }
+ if (kind == TypeKind.CHAR) {
+ return "char";
+ }
+ if (kind == TypeKind.DOUBLE) {
+ return "double";
+ }
+ if (kind == TypeKind.FLOAT) {
+ return "float";
+ }
+ if (kind == TypeKind.INT) {
+ return "int";
+ }
+ if (kind == TypeKind.LONG) {
+ return "long";
+ }
+ if (kind == TypeKind.SHORT) {
+ return "short";
+ }
+ return type2ReturnName(typeMirror);
+ }
+
+ private String typeName(Element element) {
+ if (element.getKind() == ElementKind.CLASS
+ || element.getKind() == ElementKind.INTERFACE
+ || element.getKind() == ElementKind.ENUM) {
+ return ((TypeElement) element).getQualifiedName().toString();
+ }
+ return element.getSimpleName().toString();
+ }
+
+ private void endAsyncInterface(StringBuilder result) {
+ result.append("\n}");
+ }
+
+ private void startAsyncInterface(StringBuilder result, String qualifiedName, String className, String packageName) {
+ result.append("package ").append(packageName).append(";\n");
+ result.append("import java.util.concurrent.CompletableFuture;\n");
+ result.append("@javax.annotation.Generated(\"com.alibaba.dubbo.async.processor.AsyncAnnotationProcessor\")\n");
+ result.append("@org.apache.dubbo.common.config.AsyncFor(").append(qualifiedName).append(".class)\n");
+ result.append("public interface ").append(className).append("Async extends ").append(className).append(" {\n");
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ private void close(Writer writer) {
+ if (writer == null) return;
+ try {
+ writer.close();
+ } catch (IOException e) {
+
+ }
+ }
+}
+
diff --git a/src/main/java/com/alibaba/dubbo/config/async/AsyncSignal.java b/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java
similarity index 73%
rename from src/main/java/com/alibaba/dubbo/config/async/AsyncSignal.java
rename to src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java
index 82d7ecd..847f6a3 100644
--- a/src/main/java/com/alibaba/dubbo/config/async/AsyncSignal.java
+++ b/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java
@@ -16,9 +16,17 @@
*/
package com.alibaba.dubbo.config.async;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
/**
*
*/
-public enum AsyncSignal {
- SIGNAL
+@Documented
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface DubboAsync {
}
diff --git a/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/src/main/resources/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..103cc2d
--- /dev/null
+++ b/src/main/resources/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+com.alibaba.dubbo.config.async.AsyncAnnotationProcessor
\ No newline at end of file