CAMEL-10197: Fixed handling of arrays and enums for spring boot configuration
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/0f7163e9 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/0f7163e9 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/0f7163e9 Branch: refs/heads/master Commit: 0f7163e9f4eb501a8a9d2d53679590d289fa8165 Parents: b26d81c Author: Dhiraj Bokde <dhira...@yahoo.com> Authored: Wed Aug 31 18:37:43 2016 -0700 Committer: Dhiraj Bokde <dhira...@yahoo.com> Committed: Tue Sep 20 07:30:24 2016 -0700 ---------------------------------------------------------------------- .../SpringBootAutoConfigurationMojo.java | 74 ++++++++++++++------ 1 file changed, 51 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/0f7163e9/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java ---------------------------------------------------------------------- diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java index 3a3f9f4..d1529b1 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java @@ -54,11 +54,9 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; import org.jboss.forge.roaster.Roaster; -import org.jboss.forge.roaster.model.JavaEnum; import org.jboss.forge.roaster.model.JavaType; import org.jboss.forge.roaster.model.Type; import org.jboss.forge.roaster.model.source.AnnotationSource; -import org.jboss.forge.roaster.model.source.FieldSource; import org.jboss.forge.roaster.model.source.Import; import org.jboss.forge.roaster.model.source.JavaClassSource; import org.jboss.forge.roaster.model.source.MethodSource; @@ -99,7 +97,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { /** * Classes to exclude when adding {@link NestedConfigurationProperty} annotations. */ - private static final Pattern EXCLUDE_CLASSES_PATTERN = Pattern.compile("^((java\\.)|(javax\\.)).*"); + private static final Pattern EXCLUDE_INNER_PATTERN = Pattern.compile("^((java\\.)|(javax\\.)).*"); private static final Map<String, String> PRIMITIVEMAP; @@ -340,7 +338,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { } PropertySource<JavaClassSource> prop = javaClass.addProperty(type, option.getName()); - if (!type.endsWith(INNER_TYPE_SUFFIX) && !EXCLUDE_CLASSES_PATTERN.matcher(type).matches() && Strings.isBlank(option.getEnumValues())) { + if (!(type.endsWith(INNER_TYPE_SUFFIX) || !(type.indexOf('[') == -1) || EXCLUDE_INNER_PATTERN.matcher(type).matches() || !Strings.isBlank(option.getEnumValues()))) { // add nested configuration annotation for complex properties prop.getField().addAnnotation(NestedConfigurationProperty.class); } @@ -384,20 +382,28 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { // parse option type for (PropertySource<JavaClassSource> sourceProp : nestedType.getProperties()) { - final Type<JavaClassSource> sourcePropType = sourceProp.getType(); final MethodSource<JavaClassSource> mutator = sourceProp.getMutator(); // NOTE: fields with no setters are skipped if (mutator == null) { continue; } - final String optionType = getSimpleJavaType(sourcePropType.getQualifiedNameWithGenerics()); - final FieldSource<JavaClassSource> field = sourceProp.getField(); - - + // strip array dimensions + Type<JavaClassSource> propType = sourceProp.getType(); + final String optionType = getSimpleJavaType(resolveParamType(nestedType, propType.getName())); final PropertySource<JavaClassSource> prop = innerClass.addProperty(optionType, sourceProp.getName()); + boolean anEnum; + Class optionClass; + if (!propType.isArray()) { + optionClass = loadClass(projectClassLoader, optionType); + anEnum = optionClass.isEnum(); + } else { + optionClass = null; + anEnum = false; + } + // add nested configuration annotation for complex properties - if (!EXCLUDE_CLASSES_PATTERN.matcher(optionType).matches() && !isEnum(projectClassLoader, optionType)) { + if (!EXCLUDE_INNER_PATTERN.matcher(optionType).matches() && !propType.isArray() && !anEnum) { prop.getField().addAnnotation(NestedConfigurationProperty.class); } if (sourceProp.hasAnnotation(Deprecated.class)) { @@ -411,8 +417,8 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { String description = null; if (mutator.hasJavaDoc()) { description = mutator.getJavaDoc().getFullText(); - } else if (field != null) { - description = field.getJavaDoc().getFullText(); + } else if (sourceProp.hasField()) { + description = sourceProp.getField().getJavaDoc().getFullText(); } if (!Strings.isBlank(description)) { prop.getField().getJavaDoc().setFullText(description); @@ -429,8 +435,8 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { prop.getField().setStringInitializer(defaultValue); } else if ("integer".equals(optionType) || "boolean".equals(optionType)) { prop.getField().setLiteralInitializer(defaultValue); - } else if (isEnum(projectClassLoader, optionType)) { - String enumShortName = optionType.substring(optionType.lastIndexOf(".") + 1); + } else if (anEnum) { + String enumShortName = optionClass.getSimpleName(); prop.getField().setLiteralInitializer(enumShortName + "." + defaultValue); javaClass.addImport(model.getJavaType()); } @@ -445,13 +451,36 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { writeSourceIfChanged(javaClass, fileName); } - private boolean isEnum(ClassLoader projectClassLoader, String optionType) throws MojoFailureException { - // remove array brackets - try { - return projectClassLoader.loadClass(optionType.replaceAll("[\\[\\]]", "")).isEnum(); - } catch (ClassNotFoundException e) { - throw new MojoFailureException(e.getMessage(), e); + // try loading class, looking for inner classes if needed + private Class loadClass(ClassLoader projectClassLoader, String loadClassName) throws MojoFailureException { + Class optionClass; + while (true) { + try { + optionClass = projectClassLoader.loadClass(loadClassName); + break; + } catch (ClassNotFoundException e) { + int dotIndex = loadClassName.lastIndexOf('.'); + if (dotIndex == -1) { + throw new MojoFailureException(e.getMessage(), e); + } else { + loadClassName = loadClassName.substring(0, dotIndex) + "$" + loadClassName.substring(dotIndex + 1); + } + } + } + return optionClass; + } + + // Roaster doesn't resolve inner classes correctly + private String resolveParamType(JavaClassSource nestedType, String type) { + String result; + int innerStart = type.indexOf('.'); + int arrayStart = type.indexOf('['); + if (innerStart != -1) { + result = nestedType.resolveType(type.substring(0, innerStart)) + type.substring(innerStart); + } else { + result = nestedType.resolveType(type); } + return arrayStart == -1 ? result : result + type.substring(arrayStart); } protected ClassLoader getProjectClassLoader() throws MojoFailureException { @@ -478,10 +507,9 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { // remove <?> as generic type as Roaster (Eclipse JDT) cannot use that type = type.replaceAll("\\<\\?\\>", ""); // use wrapper types for primitive types so a null mean that the option has not been configured - String primitive = type.replaceAll("[\\[\\]]", ""); - String wrapper = PRIMITIVEMAP.get(primitive); + String wrapper = PRIMITIVEMAP.get(type); if (wrapper != null) { - type = type.replaceAll(primitive, wrapper); + type = wrapper; } return type; }