This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new 5f4530c  [CAMEL-12688] Fix generation and improve the generated code
5f4530c is described below

commit 5f4530c7077e9871f56b49a59ea8f11f2cdd03eb
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Wed Nov 21 18:05:10 2018 +0100

    [CAMEL-12688] Fix generation and improve the generated code
---
 .../apache/camel/tools/apt/ConverterProcessor.java | 161 ++++++++++++++++-----
 1 file changed, 127 insertions(+), 34 deletions(-)

diff --git 
a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java 
b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
index ac372e1..1757f21 100644
--- 
a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
+++ 
b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
@@ -21,9 +21,12 @@ import java.io.FileOutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.io.Writer;
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -33,6 +36,8 @@ import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.annotation.processing.SupportedSourceVersion;
 import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -50,20 +55,25 @@ public class ConverterProcessor extends AbstractProcessor {
     @Override
     public boolean process(Set<? extends TypeElement> annotations, 
RoundEnvironment roundEnv) {
         try {
-            if 
(this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.impl.converter.CoreFallbackConverter")
 != null) {
+            if (roundEnv.processingOver()) {
                 return false;
             }
 
-            if (roundEnv.processingOver()) {
+            if 
(this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.impl.converter.CoreStaticTypeConverterLoader")
 != null) {
+                return false;
+            }
+
+            // We're in tests, do not generate anything
+            if 
(this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.converter.ObjectConverter")
 == null) {
                 return false;
             }
 
             Comparator<TypeMirror> comparator = (o1, o2) -> 
processingEnv.getTypeUtils().isAssignable(o1, o2)
                     ? -1 : processingEnv.getTypeUtils().isAssignable(o2, o1) ? 
+1 : o1.toString().compareTo(o2.toString());
 
-            Map<String, Map<TypeMirror, ExecutableElement>> converters = new 
HashMap<>();
-            TypeElement annotationType = 
this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.Converter");
-            for (Element element : 
roundEnv.getElementsAnnotatedWith(annotationType)) {
+            Map<String, Map<TypeMirror, ExecutableElement>> converters = new 
TreeMap<>();
+            TypeElement converterAnnotationType = 
this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.Converter");
+            for (Element element : 
roundEnv.getElementsAnnotatedWith(converterAnnotationType)) {
                 if (element.getKind() == ElementKind.METHOD) {
                     ExecutableElement ee = (ExecutableElement) element;
                     TypeMirror to = ee.getReturnType();
@@ -81,57 +91,127 @@ public class ConverterProcessor extends AbstractProcessor {
                     converters.computeIfAbsent(toString(to), c -> new 
TreeMap<>(comparator)).put(from, ee);
                 }
             }
-
-            // We're in tests, do not generate anything
-            if 
(this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.converter.ObjectConverter")
 == null) {
-                return false;
+            TypeElement fallbackAnnotationType = 
this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.FallbackConverter");
+            List<ExecutableElement> fallbackConverters = new ArrayList<>();
+            for (Element element : 
roundEnv.getElementsAnnotatedWith(fallbackAnnotationType)) {
+                if (element.getKind() == ElementKind.METHOD) {
+                    ExecutableElement ee = (ExecutableElement) element;
+                    fallbackConverters.add(ee);
+                }
             }
 
             String p = "org.apache.camel.impl.converter";
-            String c = "CoreFallbackConverter";
+            String c = "CoreStaticTypeConverterLoader";
             JavaFileObject jfo = processingEnv.getFiler().createSourceFile(p + 
"." + c);
             Set<String> converterClasses = new LinkedHashSet<>();
             try (Writer writer = jfo.openWriter()) {
 
                 writer.append("package ").append(p).append(";\n");
                 writer.append("\n");
-                writer.append("import 
org.apache.camel.support.TypeConverterSupport;\n");
                 writer.append("import org.apache.camel.Exchange;\n");
                 writer.append("import 
org.apache.camel.TypeConversionException;\n");
+                writer.append("import 
org.apache.camel.TypeConverterLoaderException;\n");
+                writer.append("import 
org.apache.camel.spi.TypeConverterLoader;\n");
+                writer.append("import 
org.apache.camel.spi.TypeConverterRegistry;\n");
+                writer.append("import 
org.apache.camel.support.TypeConverterSupport;\n");
                 writer.append("\n");
                 writer.append("@SuppressWarnings(\"unchecked\")\n");
-                writer.append("public class ").append(c).append(" extends 
TypeConverterSupport {\n");
+                writer.append("public class ").append(c).append(" implements 
TypeConverterLoader {\n");
+                writer.append("\n");
+                writer.append("    static abstract class SimpleTypeConverter 
extends TypeConverterSupport {\n");
+                writer.append("        private final boolean allowNull;\n");
                 writer.append("\n");
-                writer.append("    public <T> T convertTo(Class<T> type, 
Exchange exchange, Object value) throws TypeConversionException {\n");
-                writer.append("        try {\n");
-                writer.append("            return (T) doConvert(type, 
exchange, value);\n");
-                writer.append("        } catch (TypeConversionException e) 
{\n");
-                writer.append("            throw e;\n");
-                writer.append("        } catch (Exception e) {\n");
-                writer.append("            throw new 
TypeConversionException(value, type, e);\n");
+                writer.append("        public SimpleTypeConverter(boolean 
allowNull) {\n");
+                writer.append("            this.allowNull = allowNull;\n");
                 writer.append("        }\n");
-                writer.append("    }\n");
                 writer.append("\n");
-                writer.append("    private Object doConvert(Class<?> type, 
Exchange exchange, Object value) throws Exception {\n");
-                writer.append("        switch (type.getName()) {\n");
+                writer.append("        @Override\n");
+                writer.append("        public boolean allowNull() {\n");
+                writer.append("            return allowNull;\n");
+                writer.append("        }\n");
+                writer.append("\n");
+                writer.append("        @Override\n");
+                writer.append("        public <T> T convertTo(Class<T> type, 
Exchange exchange, Object value) throws TypeConversionException {\n");
+                writer.append("            try {\n");
+                writer.append("                return (T) doConvert(exchange, 
value);\n");
+                writer.append("            } catch (TypeConversionException e) 
{\n");
+                writer.append("                throw e;\n");
+                writer.append("            } catch (Exception e) {\n");
+                writer.append("                throw new 
TypeConversionException(value, type, e);\n");
+                writer.append("            }\n");
+                writer.append("        }\n");
+                writer.append("        protected abstract Object 
doConvert(Exchange exchange, Object value) throws Exception;\n");
+                writer.append("    };\n");
+                writer.append("\n");
+                writer.append("    @Override\n");
+                writer.append("    public void load(TypeConverterRegistry 
registry) throws TypeConverterLoaderException {\n");
+
                 for (Map.Entry<String, Map<TypeMirror, ExecutableElement>> to 
: converters.entrySet()) {
-                    writer.append("            case 
\"").append(to.getKey()).append("\": {\n");
                     for (Map.Entry<TypeMirror, ExecutableElement> from : 
to.getValue().entrySet()) {
-                        String name = toString(from.getKey());
-                        if ("java.lang.Object".equals(name)) {
-                            writer.append("                if (value != null) 
{\n");
-                        } else {
-                            writer.append("                if (value 
instanceof ").append(name).append(") {\n");
+                        boolean allowNull = false;
+                        for (AnnotationMirror ann : 
from.getValue().getAnnotationMirrors()) {
+                            if (ann.getAnnotationType().asElement() == 
converterAnnotationType) {
+                                for (Map.Entry<? extends ExecutableElement, ? 
extends AnnotationValue> entry : ann.getElementValues().entrySet()) {
+                                    switch 
(entry.getKey().getSimpleName().toString()) {
+                                        case "allowNull":
+                                            allowNull = (Boolean) 
entry.getValue().getValue();
+                                            break;
+                                        default:
+                                            throw new IllegalStateException();
+                                    }
+                                }
+                            }
+                        }
+                        writer.append("        
registry.addTypeConverter(").append(to.getKey()).append(".class").append(", ")
+                                
.append(toString(from.getKey())).append(".class, new SimpleTypeConverter(")
+                                .append(Boolean.toString(allowNull)).append(") 
{\n");
+                        writer.append("            @Override\n");
+                        writer.append("            public Object 
doConvert(Exchange exchange, Object value) throws Exception {\n");
+                        writer.append("                return 
").append(toJava(from.getValue(), converterClasses)).append(";\n");
+                        writer.append("            }\n");
+                        writer.append("        });\n");
+                    }
+                }
+
+                for (ExecutableElement ee : fallbackConverters) {
+                    boolean allowNull = false;
+                    boolean canPromote = false;
+                    for (AnnotationMirror ann : ee.getAnnotationMirrors()) {
+                        if (ann.getAnnotationType().asElement() == 
fallbackAnnotationType) {
+                            for (Map.Entry<? extends ExecutableElement, ? 
extends AnnotationValue> entry : ann.getElementValues().entrySet()) {
+                                switch 
(entry.getKey().getSimpleName().toString()) {
+                                    case "allowNull":
+                                        allowNull = (Boolean) 
entry.getValue().getValue();
+                                        break;
+                                    case "canPromote":
+                                        canPromote = (Boolean) 
entry.getValue().getValue();
+                                        break;
+                                    default:
+                                        throw new IllegalStateException();
+                                }
+                            }
                         }
-                        writer.append("                    return 
").append(toJava(from.getValue(), converterClasses)).append(";\n");
-                        writer.append("                }\n");
                     }
-                    writer.append("                break;\n");
+                    writer.append("        
registry.addFallbackTypeConverter(new TypeConverterSupport() {\n");
+                    writer.append("            @Override\n");
+                    writer.append("            public boolean allowNull() 
{\n");
+                    writer.append("                return 
").append(Boolean.toString(allowNull)).append(";\n");
                     writer.append("            }\n");
+                    writer.append("            @Override\n");
+                    writer.append("            public <T> T convertTo(Class<T> 
type, Exchange exchange, Object value) throws TypeConversionException {\n");
+                    writer.append("                try {\n");
+                    writer.append("                    return (T) 
").append(toJavaFallback(ee, converterClasses)).append(";\n");
+                    writer.append("                } catch 
(TypeConversionException e) {\n");
+                    writer.append("                    throw e;\n");
+                    writer.append("                } catch (Exception e) {\n");
+                    writer.append("                    throw new 
TypeConversionException(value, type, e);\n");
+                    writer.append("                }\n");
+                    writer.append("            }\n");
+                    writer.append("        }, 
").append(Boolean.toString(canPromote)).append(");\n");
                 }
-                writer.append("        }\n");
-                writer.append("        return null;\n");
+                writer.append("\n");
                 writer.append("    }\n");
+                writer.append("\n");
 
                 for (String f : converterClasses) {
                     String s = f.substring(f.lastIndexOf('.') + 1);
@@ -154,7 +234,7 @@ public class ConverterProcessor extends AbstractProcessor {
             }
 
         } catch (Throwable e) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, "Unable to 
process elements annotated with @UriEndpoint: " + e.getMessage());
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Unable to 
process elements annotated with @Converter: " + e.getMessage());
             dumpExceptionToErrorFile("camel-apt-error.log", "Error processing 
@Converter", e);
         }
         return false;
@@ -177,6 +257,19 @@ public class ConverterProcessor extends AbstractProcessor {
         return pfx + "(" + cast + "value" + (converter.getParameters().size() 
== 2 ? ", exchange" : "") + ")";
     }
 
+    private String toJavaFallback(ExecutableElement converter, Set<String> 
converterClasses) {
+        String pfx;
+        if (converter.getModifiers().contains(Modifier.STATIC)) {
+            pfx = converter.getEnclosingElement().toString() + "." + 
converter.getSimpleName();
+        } else {
+            converterClasses.add(converter.getEnclosingElement().toString());
+            pfx = "get" + converter.getEnclosingElement().getSimpleName() + 
"()." + converter.getSimpleName();
+        }
+        String type = 
toString(converter.getParameters().get(converter.getParameters().size() - 
2).asType());
+        String cast = type.equals("java.lang.Object") ? "" : "(" + type + ") ";
+        return pfx + "(type, " + (converter.getParameters().size() == 4 ? 
"exchange, " : "") + cast + "value" + ", registry)";
+    }
+
     public static void dumpExceptionToErrorFile(String fileName, String 
message, Throwable e) {
         File file = new File(fileName);
         try {

Reply via email to