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 <[email protected]> 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();
