You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2020/09/16 07:17:15 UTC

[camel] 03/04: CAMEL-15478: Java source parser should resolve return type that may be generic and parameterized.

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

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

commit 6f6c1b98802e0cc21a73820696bec59c0de52076
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Sep 16 09:03:28 2020 +0200

    CAMEL-15478: Java source parser should resolve return type that may be generic and parameterized.
---
 .../org/apache/camel/maven/JavaSourceParser.java   | 187 ++++++++-------------
 1 file changed, 67 insertions(+), 120 deletions(-)

diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavaSourceParser.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavaSourceParser.java
index a05596e..dbc3fa0 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavaSourceParser.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavaSourceParser.java
@@ -57,65 +57,6 @@ public class JavaSourceParser {
     private String apiDescription;
     private final Map<String, String> methodDescriptions = new HashMap<>();
 
-    private static String resolveParameterizedType(
-            AbstractGenericCapableJavaSource clazz, MethodSource ms, ParameterSource ps, Type type) {
-        String answer = resolveType(clazz, clazz, ms, type);
-
-        if (type.isParameterized()) {
-            // for parameterized types then it can get complex if they are variables (T, T extends Foo etc)
-            // or if there are no bounds for these types which we then can't resolve.
-            List<Type> types = type.getTypeArguments();
-            boolean bounds = false;
-            boolean found = false;
-            for (Type t : types) {
-                if (hasTypeVariableBounds(ms, clazz, t.getName())) {
-                    bounds = true;
-                    // okay now it gets complex as we have a type like T which is a type variable and we need to resolve that into
-                    // what base class that is
-                    String tn = resolveTypeVariable(ms, clazz, t.getName());
-                    if (tn != null) {
-                        answer = answer.replace(t.getName(), tn);
-                        found = true;
-                    }
-                }
-            }
-            if (!bounds && !found) {
-                // argh this is getting complex, it may be T or just java.lang.String but this **** generics and roaster
-                // does not make this easy, so let see if we can find out if all the types are a qualified type or only a variable
-                boolean fqn = types.stream().allMatch(t -> {
-                    // if its from java itself then its okay
-                    if (t.getQualifiedName().startsWith("java")) {
-                        return true;
-                    }
-                    // okay lets assume its a type variable if the name is upper case only
-                    boolean upperOnly = isUpperCaseOnly(t.getName());
-                    return !upperOnly && t.getQualifiedName().indexOf('.') != -1;
-                });
-                if (!fqn) {
-                    // remove generics we could not resolve that even if we have bounds information
-                    bounds = true;
-                    found = false;
-                }
-            }
-            if (bounds && !found) {
-                // remove generics we could not resolve that even if we have bounds information
-                answer = type.getQualifiedName();
-            }
-        } else if (ms.hasTypeVariable(answer) || clazz.hasTypeVariable(answer)) {
-            // okay now it gets complex as we have a type like T which is a type variable and we need to resolve that into
-            // what base class that is
-            answer = resolveTypeVariable(ms, clazz, answer);
-        }
-        if ((ps != null && ps.isVarArgs()) || type.isArray()) {
-            // the old way with javadoc did not use varargs in the signature, so lets transform this to an array style
-            answer = answer + "[]";
-        }
-
-        // remove java.lang. prefix as it should not be there
-        answer = answer.replaceAll("java.lang.", "");
-        return answer;
-    }
-
     @SuppressWarnings("unchecked")
     public synchronized void parse(InputStream in, String innerClass) throws Exception {
         AbstractGenericCapableJavaSource rootClazz = (AbstractGenericCapableJavaSource) Roaster.parse(in);
@@ -165,7 +106,7 @@ public class JavaSourceParser {
                 methodDescriptions.put(ms.getName(), doc);
             }
 
-            String result = resolveParameterizedType(clazz, ms, null, ms.getReturnType());
+            String result = resolveParameterizedType(rootClazz, clazz, ms, null, ms.getReturnType());
             if (result.isEmpty()) {
                 result = "void";
             }
@@ -181,63 +122,9 @@ public class JavaSourceParser {
             for (int i = 0; i < list.size(); i++) {
                 ParameterSource ps = list.get(i);
                 String name = ps.getName();
-                String type = resolveType(rootClazz, clazz, ms, ps.getType());
+                String type = resolveParameterizedType(rootClazz, clazz, ms, ps, ps.getType());
                 LOG.trace("Parsing parameter #{} ({} {})", i, type, name);
 
-                // TODO: Call that other method
-                if (ps.getType().isParameterized()) {
-                    // for parameterized types then it can get complex if they are variables (T, T extends Foo etc)
-                    // or if there are no bounds for these types which we then can't resolve.
-                    List<Type> types = ps.getType().getTypeArguments();
-                    boolean bounds = false;
-                    boolean found = false;
-                    for (Type t : types) {
-                        if (hasTypeVariableBounds(ms, clazz, t.getName())) {
-                            bounds = true;
-                            // okay now it gets complex as we have a type like T which is a type variable and we need to resolve that into
-                            // what base class that is
-                            String tn = resolveTypeVariable(ms, clazz, t.getName());
-                            if (tn != null) {
-                                type = type.replace(t.getName(), tn);
-                                found = true;
-                            }
-                        }
-                    }
-                    if (!bounds && !found) {
-                        // argh this is getting complex, it may be T or just java.lang.String but this **** generics and roaster
-                        // does not make this easy, so let see if we can find out if all the types are a qualified type or only a variable
-                        boolean fqn = types.stream().allMatch(t -> {
-                            // if its from java itself then its okay
-                            if (t.getQualifiedName().startsWith("java")) {
-                                return true;
-                            }
-                            // okay lets assume its a type variable if the name is upper case only
-                            boolean upperOnly = isUpperCaseOnly(t.getName());
-                            return !upperOnly && t.getQualifiedName().indexOf('.') != -1;
-                        });
-                        if (!fqn) {
-                            // remove generics we could not resolve that even if we have bounds information
-                            bounds = true;
-                            found = false;
-                        }
-                    }
-                    if (bounds && !found) {
-                        // remove generics we could not resolve that even if we have bounds information
-                        type = ps.getType().getQualifiedName();
-                    }
-                } else if (ms.hasTypeVariable(type) || clazz.hasTypeVariable(type)) {
-                    // okay now it gets complex as we have a type like T which is a type variable and we need to resolve that into
-                    // what base class that is
-                    type = resolveTypeVariable(ms, clazz, type);
-                }
-                if (ps.isVarArgs() || ps.getType().isArray()) {
-                    // the old way with javadoc did not use varargs in the signature, so lets transform this to an array style
-                    type = type + "[]";
-                }
-
-                // remove all java.lang. prefixes
-                type = type.replaceAll("java.lang.", "");
-
                 sb.append(type);
                 sb.append(" ").append(name);
                 if (i < list.size() - 1) {
@@ -264,13 +151,64 @@ public class JavaSourceParser {
         }
     }
 
-    private static boolean isUpperCaseOnly(String name) {
-        for (int i = 0; i < name.length(); i++) {
-            if (!Character.isUpperCase(name.charAt(i))) {
-                return false;
+    private static String resolveParameterizedType(
+            AbstractGenericCapableJavaSource rootClazz, AbstractGenericCapableJavaSource clazz, MethodSource ms,
+            ParameterSource ps, Type type) {
+        String answer = resolveType(rootClazz, clazz, ms, type);
+
+        if (type.isParameterized()) {
+            // for parameterized types then it can get complex if they are variables (T, T extends Foo etc)
+            // or if there are no bounds for these types which we then can't resolve.
+            List<Type> types = type.getTypeArguments();
+            boolean bounds = false;
+            boolean found = false;
+            for (Type t : types) {
+                if (hasTypeVariableBounds(ms, clazz, t.getName())) {
+                    bounds = true;
+                    // okay now it gets complex as we have a type like T which is a type variable and we need to resolve that into
+                    // what base class that is
+                    String tn = resolveTypeVariable(ms, clazz, t.getName());
+                    if (tn != null) {
+                        answer = answer.replace(t.getName(), tn);
+                        found = true;
+                    }
+                }
+            }
+            if (!bounds && !found) {
+                // argh this is getting complex, it may be T or just java.lang.String but this **** generics and roaster
+                // does not make this easy, so let see if we can find out if all the types are a qualified type or only a variable
+                boolean fqn = types.stream().allMatch(t -> {
+                    // if its from java itself then its okay
+                    if (t.getQualifiedName().startsWith("java")) {
+                        return true;
+                    }
+                    // okay lets assume its a type variable if the name is upper case only
+                    boolean upperOnly = isUpperCaseOnly(t.getName());
+                    return !upperOnly && t.getQualifiedName().indexOf('.') != -1;
+                });
+                if (!fqn) {
+                    // remove generics we could not resolve that even if we have bounds information
+                    bounds = true;
+                    found = false;
+                }
             }
+            if (bounds && !found) {
+                // remove generics we could not resolve that even if we have bounds information
+                answer = type.getQualifiedName();
+            }
+        } else if (ms.hasTypeVariable(answer) || clazz.hasTypeVariable(answer)) {
+            // okay now it gets complex as we have a type like T which is a type variable and we need to resolve that into
+            // what base class that is
+            answer = resolveTypeVariable(ms, clazz, answer);
         }
-        return true;
+        if ((ps != null && ps.isVarArgs()) || type.isArray()) {
+            // the old way with javadoc did not use varargs in the signature, so lets transform this to an array style
+            answer = answer + "[]";
+        }
+
+        // remove java.lang. prefix as it should not be there
+        answer = answer.replaceAll("java.lang.", "");
+        return answer;
     }
 
     private static boolean hasTypeVariableBounds(MethodSource ms, AbstractGenericCapableJavaSource clazz, String type) {
@@ -483,6 +421,15 @@ public class JavaSourceParser {
         return desc;
     }
 
+    private static boolean isUpperCaseOnly(String name) {
+        for (int i = 0; i < name.length(); i++) {
+            if (!Character.isUpperCase(name.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public void reset() {
         methods.clear();
         methodText.clear();