From fbc0a5ff0a8fe86816d06cb57a69e2f776bd74bd Mon Sep 17 00:00:00 2001 From: Hari Nair Date: Sat, 24 Sep 2022 14:47:47 +0000 Subject: [PATCH] Resolve "Allow multi line strings in comment" --- .../main/java/jackfruit/demo/DemoClass.java | 15 +- .../java/jackfruit/demo/DemoInterface.java | 17 +- .../java/jackfruit/demo/JackfruitDemo.java | 2 +- jackfruit/pom.xml | 5 + .../jackfruit/processor/AnnotationBundle.java | 4 +- .../jackfruit/processor/ConfigProcessor.java | 161 +++++++++--------- 6 files changed, 114 insertions(+), 90 deletions(-) diff --git a/demo/src/main/java/jackfruit/demo/DemoClass.java b/demo/src/main/java/jackfruit/demo/DemoClass.java index 53d4407..016c04c 100644 --- a/demo/src/main/java/jackfruit/demo/DemoClass.java +++ b/demo/src/main/java/jackfruit/demo/DemoClass.java @@ -11,17 +11,24 @@ import jackfruit.annotations.ParserClass; public abstract class DemoClass { @Key("key") - @Comment("field comment") - @DefaultValue("0") + @Comment("One line comment") + @DefaultValue("1") public abstract int intMethod(); + @Comment("This is a very long comment line that really should be wrapped into more than one line") @DefaultValue("0.") public abstract Double doubleMethod(); + @Comment(""" + This is a multiline + java text block. + + This is a new paragraph. + """) @DefaultValue("Default String") public abstract String StringMethod(); - @Comment("This string is serialized into an object") + @Comment("This string is serialized into an object\n\tThis comment contains a newline character, and this line starts with a tab.") @DefaultValue("serialized string") @ParserClass(SomeRandomClassParser.class) public abstract SomeRandomClass randomClass(); @@ -38,5 +45,5 @@ public abstract class DemoClass { public void noAnnotationsOnThisMethod() { System.out.println("This method was not processed"); } - + } diff --git a/demo/src/main/java/jackfruit/demo/DemoInterface.java b/demo/src/main/java/jackfruit/demo/DemoInterface.java index bc3b941..8ab0a97 100644 --- a/demo/src/main/java/jackfruit/demo/DemoInterface.java +++ b/demo/src/main/java/jackfruit/demo/DemoInterface.java @@ -45,17 +45,24 @@ public interface DemoInterface { // default key is field name @Key("key") - @Comment("field comment") - @DefaultValue("0") + @Comment("One line comment") + @DefaultValue("1") int intMethod(); + @Comment("This is a very long comment line that really should be wrapped into more than one line") @DefaultValue("0.") Double doubleMethod(); + @Comment(""" + This is a multiline + java text block. + + This is a new paragraph. + """) @DefaultValue("Default String") String StringMethod(); - @Comment("This string is serialized into an object") + @Comment("This string is serialized into an object\n\tThis comment contains a newline character, and this line starts with a tab.") @DefaultValue("serialized string") @ParserClass(SomeRandomClassParser.class) SomeRandomClass randomClass(); @@ -63,10 +70,10 @@ public interface DemoInterface { @Comment("List of Doubles") @DefaultValue("0. 5.34 17") List doubles(); - + @Comment("List of RandomClass") @DefaultValue("obj1 obj2") @ParserClass(SomeRandomClassParser.class) List randoms(); - + } diff --git a/demo/src/main/java/jackfruit/demo/JackfruitDemo.java b/demo/src/main/java/jackfruit/demo/JackfruitDemo.java index 8bc9aa6..9774e2e 100644 --- a/demo/src/main/java/jackfruit/demo/JackfruitDemo.java +++ b/demo/src/main/java/jackfruit/demo/JackfruitDemo.java @@ -19,7 +19,7 @@ public class JackfruitDemo { // get an example config object DemoClass template = factory.getTemplate(); - + /*- // or if you prefer, use an interface DemoInterfaceFactory factory = new DemoInterfaceFactory(); diff --git a/jackfruit/pom.xml b/jackfruit/pom.xml index 9cc1328..54db0b9 100644 --- a/jackfruit/pom.xml +++ b/jackfruit/pom.xml @@ -55,6 +55,11 @@ log4j-api 2.18.0 + + org.apache.commons + commons-text + 1.8 + org.apache.logging.log4j log4j-core diff --git a/jackfruit/src/main/java/jackfruit/processor/AnnotationBundle.java b/jackfruit/src/main/java/jackfruit/processor/AnnotationBundle.java index 1f1bd88..3bdabb2 100644 --- a/jackfruit/src/main/java/jackfruit/processor/AnnotationBundle.java +++ b/jackfruit/src/main/java/jackfruit/processor/AnnotationBundle.java @@ -18,14 +18,14 @@ public abstract class AnnotationBundle { /** * * @return the return type of this method without any parameters (e.g. return List rather than - * List} + * List<String>) */ public abstract TypeMirror erasure(); /** * * @return the parameterized types, if any of this method (e.g. return String if the annotated - * method returns List) + * method returns List<String>) */ public abstract List typeArgs(); diff --git a/jackfruit/src/main/java/jackfruit/processor/ConfigProcessor.java b/jackfruit/src/main/java/jackfruit/processor/ConfigProcessor.java index c1bbcf8..729da01 100644 --- a/jackfruit/src/main/java/jackfruit/processor/ConfigProcessor.java +++ b/jackfruit/src/main/java/jackfruit/processor/ConfigProcessor.java @@ -31,6 +31,7 @@ import javax.lang.model.util.Types; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import org.apache.commons.configuration2.Configuration; +import org.apache.commons.text.WordUtils; import com.google.auto.service.AutoService; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; @@ -271,7 +272,7 @@ public class ConfigProcessor extends AbstractProcessor { AnnotationBundle ab = annotationsMap.get(method); String key = prefix + ab.key(); if (needBlank) { - methodBuilder.addStatement(String.format("$N.setBlancLinesBefore(\"%s\", 1)", key), layout); + methodBuilder.addStatement("$N.setBlancLinesBefore($S, 1)", layout, key); needBlank = false; } @@ -292,33 +293,54 @@ public class ConfigProcessor extends AbstractProcessor { ParameterizedTypeName.get(ClassName.get(java.util.ArrayList.class), stringType); String listName = method.getSimpleName() + "List"; methodBuilder.addStatement("$T " + listName + " = new $T()", listType, arrayListType); - methodBuilder - .beginControlFlow(String.format("for (var element : t.%s())", method.getSimpleName())); + methodBuilder.beginControlFlow("for (var element : t.$L())", method.getSimpleName()); if (ab.parserClass().isPresent()) { - methodBuilder - .addStatement(String.format("%s.add(%s.toString(element))", listName, parserName)); + methodBuilder.addStatement("$L.add($L.toString(element))", listName, parserName); } else { - methodBuilder - .addStatement(String.format("%s.add(String.format(\"%%s\", element))", listName)); + TypeMirror typeArg = ab.typeArgs().get(0); + if (ConfigProcessorUtils.isByte(typeArg, processingEnv)) + methodBuilder.addStatement("$L.add($T.toString(element))", listName, + java.lang.Byte.class); + if (ConfigProcessorUtils.isBoolean(typeArg, processingEnv)) + methodBuilder.addStatement("$L.add($T.toString(element))", listName, + java.lang.Boolean.class); + if (ConfigProcessorUtils.isDouble(typeArg, processingEnv)) + methodBuilder.addStatement("$L.add($T.toString(element))", listName, + java.lang.Double.class); + if (ConfigProcessorUtils.isFloat(typeArg, processingEnv)) + methodBuilder.addStatement("$L.add($T.toString(element))", listName, + java.lang.Float.class); + if (ConfigProcessorUtils.isInteger(typeArg, processingEnv)) + methodBuilder.addStatement("$L.add($T.toString(element))", listName, + java.lang.Integer.class); + if (ConfigProcessorUtils.isLong(typeArg, processingEnv)) + methodBuilder.addStatement("$L.add($T.toString(element))", listName, + java.lang.Long.class); + if (ConfigProcessorUtils.isShort(typeArg, processingEnv)) + methodBuilder.addStatement("$L.add($T.toString(element))", listName, + java.lang.Short.class); + if (ConfigProcessorUtils.isString(typeArg, processingEnv)) + methodBuilder.addStatement("$L.add(element)", listName); } methodBuilder.endControlFlow(); - methodBuilder.addStatement(String.format("config.setProperty(\"%s\", %s)", key, listName)); + methodBuilder.addStatement("config.setProperty($S, $L)", key, listName); } else { if (ab.parserClass().isPresent()) { // store the serialized string as the property - methodBuilder - .addStatement(String.format("config.setProperty(\"%s\", %s.toString($N.%s()))", key, - parserName, method.getSimpleName()), ps); + methodBuilder.addStatement("config.setProperty($S, $L.toString($N.$L()))", key, + parserName, ps, method.getSimpleName()); } else { - methodBuilder.addStatement( - String.format("config.setProperty(\"%s\", t.%s())", key, method.getSimpleName())); + methodBuilder.addStatement("config.setProperty($S, t.$L())", key, method.getSimpleName()); } } // add the comment - if (ab.comment().length() > 0) - methodBuilder.addStatement( - String.format("$N.setComment(\"%s\", \"%s\")", key, ab.comment()), layout); + if (ab.comment().length() > 0) { + String commentName = String.format("%sComment", method.getSimpleName()); + methodBuilder.addStatement("$T $L = $S", String.class, commentName, ab.comment()); + methodBuilder.addStatement("$N.setComment($S, $T.wrap($L, 80))", layout, key, + WordUtils.class, commentName); + } } methodBuilder.addCode("return config;"); @@ -347,7 +369,7 @@ public class ConfigProcessor extends AbstractProcessor { if (bundle.parserClass().isPresent()) { parser = bundle.parserClass().get(); parserName = method.getSimpleName() + "Parser"; - builder.addStatement(String.format("$T %s = new $T()", parserName), parser, parser); + builder.addStatement("$T $L = new $T()", parser, parserName, parser); } if (ConfigProcessorUtils.isList(bundle.erasure(), processingEnv)) { @@ -360,49 +382,46 @@ public class ConfigProcessor extends AbstractProcessor { String listName = method.getSimpleName() + "List"; builder.addStatement("$T " + listName + " = new $T()", listType, arrayListType); - builder.addStatement( - String.format("String [] parts = \"%s\".split(\"\\\\s+\")", bundle.defaultValue())); + builder.addStatement("String [] parts = $S.split($S)", bundle.defaultValue(), "\\s+"); builder.beginControlFlow("for (String part : parts)"); + builder.beginControlFlow("if (part.trim().length() > 0)"); if (bundle.parserClass().isPresent()) { - builder.addStatement(String.format("%s.add(%s.fromString(part))", listName, parserName)); + builder.addStatement("$L.add($L.fromString(part))", listName, parserName); } else { TypeMirror typeArg = bundle.typeArgs().get(0); if (ConfigProcessorUtils.isByte(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Byte.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Byte.class); if (ConfigProcessorUtils.isBoolean(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Boolean.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Boolean.class); if (ConfigProcessorUtils.isDouble(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Double.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Double.class); if (ConfigProcessorUtils.isFloat(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Float.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Float.class); if (ConfigProcessorUtils.isInteger(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Integer.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Integer.class); if (ConfigProcessorUtils.isLong(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Long.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Long.class); if (ConfigProcessorUtils.isShort(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Short.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Short.class); if (ConfigProcessorUtils.isString(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add(part)", listName)); + builder.addStatement("$L.add(part)", listName); } builder.endControlFlow(); - builder.addStatement(String.format("return %s", listName)); + builder.endControlFlow(); + builder.addStatement("return $L", listName); } else { if (bundle.parserClass().isPresent()) { - builder.addStatement( - String.format("return %s.fromString(\"%s\")", parserName, bundle.defaultValue())); + builder.addStatement("return $L.fromString($S)", parserName, bundle.defaultValue()); } else { if (ConfigProcessorUtils.isString(bundle.erasure(), processingEnv)) { - builder.addStatement(String.format("return \"%s\"", bundle.defaultValue())); + builder.addStatement("return $S", bundle.defaultValue()); } else { - builder.addStatement(String.format("return %s", bundle.defaultValue())); + if (bundle.defaultValue().trim().length() == 0) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + String.format("Default value on method %s is blank!", method.getSimpleName())); + } + builder.addStatement("return $L", bundle.defaultValue()); } } } @@ -432,7 +451,7 @@ public class ConfigProcessor extends AbstractProcessor { if (bundle.parserClass().isPresent()) { parser = bundle.parserClass().get(); parserName = method.getSimpleName() + "Parser"; - builder.addStatement(String.format("$T %s = new $T()", parserName), parser, parser); + builder.addStatement("$T $L = new $T()", parser, parserName, parser); } if (ConfigProcessorUtils.isList(bundle.erasure(), processingEnv)) { @@ -443,68 +462,54 @@ public class ConfigProcessor extends AbstractProcessor { ParameterizedTypeName.get(ClassName.get(java.util.ArrayList.class), argType); String listName = method.getSimpleName() + "List"; builder.addStatement("$T " + listName + " = new $T()", listType, arrayListType); - builder.addStatement(String.format("String [] parts = config.getStringArray(\"%s\")", - prefix + bundle.key())); + builder.addStatement("String [] parts = config.getStringArray($S)", prefix + bundle.key()); builder.beginControlFlow("for (String part : parts)"); + builder.beginControlFlow("if (part.trim().length() > 0)"); if (bundle.parserClass().isPresent()) { - builder.addStatement(String.format("%s.add(%s.fromString(part))", listName, parserName)); + builder.addStatement("$L.add($L.fromString(part))", listName, parserName); } else { TypeMirror typeArg = bundle.typeArgs().get(0); if (ConfigProcessorUtils.isByte(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Byte.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Byte.class); if (ConfigProcessorUtils.isBoolean(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Boolean.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Boolean.class); if (ConfigProcessorUtils.isDouble(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Double.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Double.class); if (ConfigProcessorUtils.isFloat(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Float.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Float.class); if (ConfigProcessorUtils.isInteger(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Integer.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Integer.class); if (ConfigProcessorUtils.isLong(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Long.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Long.class); if (ConfigProcessorUtils.isShort(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add($T.valueOf(part))", listName), - java.lang.Short.class); + builder.addStatement("$L.add($T.valueOf(part))", listName, java.lang.Short.class); if (ConfigProcessorUtils.isString(typeArg, processingEnv)) - builder.addStatement(String.format("%s.add(part)", listName)); + builder.addStatement("$L.add(part)", listName); } builder.endControlFlow(); - builder.addStatement(String.format("return %s", listName)); + builder.endControlFlow(); + builder.addStatement("return $L", listName); } else { if (bundle.parserClass().isPresent()) { - builder.addStatement(String.format("return %s.fromString(config.getString(\"%s\"))", - parserName, prefix + bundle.key())); + builder.addStatement("return $L.fromString(config.getString($S))", parserName, + prefix + bundle.key()); } else { if (ConfigProcessorUtils.isBoolean(bundle.erasure(), processingEnv)) { - builder.addStatement( - String.format("return config.getBoolean(\"%s\")", prefix + bundle.key())); + builder.addStatement("return config.getBoolean($S)", prefix + bundle.key()); } else if (ConfigProcessorUtils.isByte(bundle.erasure(), processingEnv)) { - builder.addStatement( - String.format("return config.getByte(\"%s\")", prefix + bundle.key())); + builder.addStatement("return config.getByte($S)", prefix + bundle.key()); } else if (ConfigProcessorUtils.isDouble(bundle.erasure(), processingEnv)) { - builder.addStatement( - String.format("return config.getDouble(\"%s\")", prefix + bundle.key())); + builder.addStatement("return config.getDouble($S)", prefix + bundle.key()); } else if (ConfigProcessorUtils.isFloat(bundle.erasure(), processingEnv)) { - builder.addStatement( - String.format("return config.getFloat(\"%s\")", prefix + bundle.key())); + builder.addStatement("return config.getFloat($S)", prefix + bundle.key()); } else if (ConfigProcessorUtils.isInteger(bundle.erasure(), processingEnv)) { - builder - .addStatement(String.format("return config.getInt(\"%s\")", prefix + bundle.key())); + builder.addStatement("return config.getInt($S)", prefix + bundle.key()); } else if (ConfigProcessorUtils.isLong(bundle.erasure(), processingEnv)) { - builder.addStatement( - String.format("return config.getLong(\"%s\")", prefix + bundle.key())); + builder.addStatement("return config.getLong($S)", prefix + bundle.key()); } else if (ConfigProcessorUtils.isShort(bundle.erasure(), processingEnv)) { - builder.addStatement( - String.format("return config.getShort(\"%s\")", prefix + bundle.key())); + builder.addStatement("return config.getShort($S)", prefix + bundle.key()); } else if (ConfigProcessorUtils.isString(bundle.erasure(), processingEnv)) { - builder.addStatement( - String.format("return config.getString(\"%s\")", prefix + bundle.key())); + builder.addStatement("return config.getString($S)", prefix + bundle.key()); } else { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't handle return type " + m.getReturnType().getCanonicalName());