camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gno...@apache.org
Subject [camel] branch master updated: [CAMEL-12688] Fix generation and improve the generated code
Date Wed, 21 Nov 2018 17:05:32 GMT
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 <gnodet@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 {


Mime
View raw message