diff --git a/.gitignore b/.gitignore index 485dee6..6db043d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +/target diff --git a/README.md b/README.md index 1d5b88a..d6b967e 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,14 @@ Include Jackfruit in your project with the following POM: ``` - edu.jhuapl.ses.srn + edu.jhuapl.ses jackfruit $VERSION pom ``` -Find the latest version at [Surfshop](http://surfshop:8082/ui/repos/tree/General/libs-snapshot-local/edu/jhuapl/ses/srn/jackfruit/). +Find the latest version at [Maven Central](https://central.sonatype.com/). The annotation processor runs on any interface or abstract class annotated with `@Jackfruit` ``` diff --git a/demo/pom.xml b/demo/pom.xml index fbe8bc3..c0bbae0 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -3,9 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + jackfruit-parent - edu.jhuapl.ses.srn + edu.jhuapl.ses 1.0-SNAPSHOT @@ -29,7 +30,7 @@ 1.9.4 - edu.jhuapl.ses.srn + edu.jhuapl.ses jackfruit ${project.parent.version} diff --git a/demo/src/main/java/crucible/crust/logging/Log4j2Configurator.java b/demo/src/main/java/crucible/crust/logging/Log4j2Configurator.java index 9941b3b..8187a83 100644 --- a/demo/src/main/java/crucible/crust/logging/Log4j2Configurator.java +++ b/demo/src/main/java/crucible/crust/logging/Log4j2Configurator.java @@ -9,9 +9,9 @@ package crucible.crust.logging; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -37,16 +37,16 @@ import org.apache.logging.log4j.core.layout.PatternLayout; /** * A simple configuration class. - *

- * Default settings: - *

- * - * @author nairah1 * + *

Default settings: + * + *

+ * + * @author Hari.Nair@jhuapl.edu */ public class Log4j2Configurator { @@ -56,10 +56,9 @@ public class Log4j2Configurator { private static Log4j2Configurator instance = null; /** - * * @return an instance of this singleton class. */ - synchronized public static Log4j2Configurator getInstance() { + public static synchronized Log4j2Configurator getInstance() { if (instance == null) { instance = new Log4j2Configurator(); } @@ -69,15 +68,17 @@ public class Log4j2Configurator { private Log4j2Configurator() { final LoggerContext loggerContext = LoggerContext.getContext(false); final Configuration config = loggerContext.getConfiguration(); - layout = PatternLayout.newBuilder().withPattern(DefaultConfiguration.DEFAULT_PATTERN) - .withConfiguration(config).build(); + layout = + PatternLayout.newBuilder() + .withPattern(DefaultConfiguration.DEFAULT_PATTERN) + .withConfiguration(config) + .build(); fileAppenders = new HashMap<>(); setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%c{1}:%L] %msg%n%throwable"); setLevel(Level.INFO); } /** - * * @return a map of logger names to {@link LoggerConfig} */ private Map getLoggerMap() { @@ -85,22 +86,25 @@ public class Log4j2Configurator { final Configuration config = loggerContext.getConfiguration(); Map loggerMap = new HashMap<>(config.getLoggers()); - loggerMap.put(LogManager.getRootLogger().getName(), + loggerMap.put( + LogManager.getRootLogger().getName(), config.getLoggerConfig(LogManager.getRootLogger().getName())); return Collections.unmodifiableMap(loggerMap); } /** - * - * * @param filename Append log to named file, or create it if it doesn't exist. */ public void addFile(String filename) { final LoggerContext loggerContext = LoggerContext.getContext(false); Map loggerMap = getLoggerMap(); - FileAppender appender = FileAppender.newBuilder().setName(filename).withFileName(filename) - .setLayout(layout).build(); + FileAppender appender = + FileAppender.newBuilder() + .setName(filename) + .withFileName(filename) + .setLayout(layout) + .build(); appender.start(); for (String loggerName : loggerMap.keySet()) { @@ -112,8 +116,6 @@ public class Log4j2Configurator { } /** - * - * * @param filename Stop logging to named file. */ public void removeFile(String filename) { @@ -132,7 +134,6 @@ public class Log4j2Configurator { } /** - * * @param pattern layout pattern for all {@link ConsoleAppender} and {@link FileAppender} objects. */ public void setPattern(String pattern) { @@ -152,11 +153,20 @@ public class Log4j2Configurator { // there should be a better way to do this - a toBuilder() method on the appender would be // really useful if (oldAppender instanceof ConsoleAppender) { - newAppender = ConsoleAppender.newBuilder().setName(appenderName).setConfiguration(config) - .setLayout(layout).build(); + newAppender = + ConsoleAppender.newBuilder() + .setName(appenderName) + .setConfiguration(config) + .setLayout(layout) + .build(); } else if (oldAppender instanceof FileAppender) { - newAppender = FileAppender.newBuilder().setName(appenderName).setConfiguration(config) - .withFileName(((FileAppender) oldAppender).getFileName()).setLayout(layout).build(); + newAppender = + FileAppender.newBuilder() + .setName(appenderName) + .setConfiguration(config) + .withFileName(((FileAppender) oldAppender).getFileName()) + .setLayout(layout) + .build(); } if (newAppender != null) { newAppender.start(); @@ -169,15 +179,15 @@ public class Log4j2Configurator { } /** - * Sets the levels of parentLogger and all 'child' loggers to the given - * level. This is simply a call to - * + * Sets the levels of parentLogger and all 'child' loggers to the given level + * . This is simply a call to + * *
    * Configurator.setAllLevels(parentLogger, level)
    * 
- * - * @param parentLogger - * @param level + * + * @param parentLogger name of parent logger + * @param level logging level */ public void setLevel(String parentLogger, Level level) { Configurator.setAllLevels(parentLogger, level); @@ -185,15 +195,14 @@ public class Log4j2Configurator { /** * Set all logger levels. This is simply a call to - * + * *
    * setLevel(LogManager.getRootLogger().getName(), level)
    * 
- * - * @param level + * + * @param level logging level */ public void setLevel(Level level) { setLevel(LogManager.getRootLogger().getName(), level); } - } diff --git a/demo/src/main/java/jackfruit/demo/DemoClass.java b/demo/src/main/java/jackfruit/demo/DemoClass.java index a06e072..1ed2bd2 100644 --- a/demo/src/main/java/jackfruit/demo/DemoClass.java +++ b/demo/src/main/java/jackfruit/demo/DemoClass.java @@ -9,9 +9,9 @@ package jackfruit.demo; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,43 +20,42 @@ package jackfruit.demo; * #L% */ -import java.util.List; import jackfruit.annotations.Comment; import jackfruit.annotations.DefaultValue; import jackfruit.annotations.Jackfruit; import jackfruit.annotations.ParserClass; +import java.util.List; /** * @Jackfruit on abstract class - *
    - *
  • prefix is optional
  • - *
- * Method annotations: - *
    - *
  • @Key - *
      - *
    • If omitted value is method name
    • - *
    - *
  • - *
  • @Comment - *
      - *
    • Optional
    • - *
    - *
  • - *
  • @DefaultValue - *
      - *
    • Required, String value
    • - *
    - *
  • - *
  • @Parser - *
      - *
    • Optional, name of class to create object from String using its fromString() method
    • - *
    - *

    - * Inspired by owner. - * - * @author nairah1 * + *

      + *
    • prefix is optional + *
    + * + * Method annotations: + * + *
      + *
    • @Key + *
        + *
      • If omitted value is method name + *
      + *
    • @Comment + *
        + *
      • Optional + *
      + *
    • @DefaultValue + *
        + *
      • Required, String value + *
      + *
    • @Parser + *
        + *
      • Optional, name of class to create object from String using its fromString() method + *
      + *

      Inspired by owner. + *

    + * + * @author Hari.Nair@jhuapl.edu */ @Jackfruit(prefix = "prefix") public abstract class DemoClass extends DemoSuperClass { @@ -66,11 +65,13 @@ public abstract class DemoClass extends DemoSuperClass { @Override public abstract int intMethod(); - @Comment("This is a very long comment line that really should be wrapped into more than one line but that's really up to you.") + @Comment( + "This is a very long comment line that really should be wrapped into more than one line but that's really up to you.") @DefaultValue("0.") public abstract Double doubleMethod(); - @Comment(""" + @Comment( + """ This is a multiline java text block. @@ -100,5 +101,4 @@ public abstract class DemoClass extends DemoSuperClass { public void noAnnotationsOnThisMethod() { System.out.println("This method was not processed since it has no DefaultValue annotation"); } - } diff --git a/demo/src/main/java/jackfruit/demo/DemoInterface.java b/demo/src/main/java/jackfruit/demo/DemoInterface.java index d2661de..f83094b 100644 --- a/demo/src/main/java/jackfruit/demo/DemoInterface.java +++ b/demo/src/main/java/jackfruit/demo/DemoInterface.java @@ -9,9 +9,9 @@ package jackfruit.demo; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,46 +20,44 @@ package jackfruit.demo; * #L% */ -import java.util.List; import jackfruit.annotations.Comment; import jackfruit.annotations.DefaultValue; import jackfruit.annotations.Jackfruit; import jackfruit.annotations.Key; import jackfruit.annotations.ParserClass; +import java.util.List; /** * @Jackfruit on interface - *
      - *
    • prefix is optional
    • - *
    - * Method annotations: - *
      - *
    • @Key - *
        - *
      • If omitted value is method name
      • - *
      - *
    • - *
    • @Comment - *
        - *
      • Optional
      • - *
      - *
    • - *
    • @DefaultValue - *
        - *
      • Required, String value
      • - *
      - *
    • - *
    • @Parser - *
        - *
      • Optional, name of class to create object from String using its fromString() method
      • - *
      - *

      - * Inspired by owner. - * - * @author nairah1 * + *

        + *
      • prefix is optional + *
      + * + * Method annotations: + * + *
        + *
      • @Key + *
          + *
        • If omitted value is method name + *
        + *
      • @Comment + *
          + *
        • Optional + *
        + *
      • @DefaultValue + *
          + *
        • Required, String value + *
        + *
      • @Parser + *
          + *
        • Optional, name of class to create object from String using its fromString() method + *
        + *

        Inspired by owner. + *

      + * + * @author Hari.Nair@jhuapl.edu */ - @Jackfruit(prefix = "prefix") public interface DemoInterface { @@ -69,11 +67,13 @@ public interface DemoInterface { @DefaultValue("1") int intMethod(); - @Comment("This is a very long comment line that really should be wrapped into more than one line but that's really up to you.") + @Comment( + "This is a very long comment line that really should be wrapped into more than one line but that's really up to you.") @DefaultValue("0.") Double doubleMethod(); - @Comment(""" + @Comment( + """ This is a multiline java text block. @@ -82,7 +82,8 @@ public interface DemoInterface { @DefaultValue("Default String") String StringMethod(); - @Comment("This string is serialized into an object\n\tThis comment contains a newline character, and this line starts with a tab.") + @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(); @@ -95,10 +96,9 @@ public interface DemoInterface { @DefaultValue(""" obj1 obj2 - + obj3 obj4 """) @ParserClass(SomeRandomClassParser.class) List randoms(); - } diff --git a/demo/src/main/java/jackfruit/demo/DemoSuperClass.java b/demo/src/main/java/jackfruit/demo/DemoSuperClass.java index 20999c9..c83583b 100644 --- a/demo/src/main/java/jackfruit/demo/DemoSuperClass.java +++ b/demo/src/main/java/jackfruit/demo/DemoSuperClass.java @@ -9,9 +9,9 @@ package jackfruit.demo; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -38,8 +38,9 @@ public abstract class DemoSuperClass extends DemoSuperSuperClass { @DefaultValue("2") @Override public abstract int intMethod(); - - @Comment("This string is serialized into an object\n\tThis comment contains a newline character, and this line starts with a tab.") + + @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(); diff --git a/demo/src/main/java/jackfruit/demo/DemoSuperSuperClass.java b/demo/src/main/java/jackfruit/demo/DemoSuperSuperClass.java index 2cfdb02..6f7134a 100644 --- a/demo/src/main/java/jackfruit/demo/DemoSuperSuperClass.java +++ b/demo/src/main/java/jackfruit/demo/DemoSuperSuperClass.java @@ -9,9 +9,9 @@ package jackfruit.demo; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,7 +31,7 @@ public abstract class DemoSuperSuperClass { @Comment("from DemoSuperSuperClass") @DefaultValue("-3") public abstract int inherited2(); - + @Comment("from DemoSuperSuperClass") @DefaultValue("-2") public abstract int inherited(); diff --git a/demo/src/main/java/jackfruit/demo/JackfruitDemo.java b/demo/src/main/java/jackfruit/demo/JackfruitDemo.java index 3a85452..dc53c62 100644 --- a/demo/src/main/java/jackfruit/demo/JackfruitDemo.java +++ b/demo/src/main/java/jackfruit/demo/JackfruitDemo.java @@ -9,9 +9,9 @@ package jackfruit.demo; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,6 +23,7 @@ package jackfruit.demo; import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.List; import org.apache.commons.configuration2.PropertiesConfiguration; import org.apache.commons.configuration2.PropertiesConfigurationLayout; @@ -89,14 +90,21 @@ public class JackfruitDemo { System.out.println("random.toUpperCase() = " + random.toUpperCase()); // create a new factory with a different prefix, but same parameters + System.out.println(); + System.out.println( + "Create a config with anotherPrefix and retrieve randoms. This will throw an exception."); factory = new DemoClassFactory("anotherPrefix"); template = factory.fromConfig(config); - // this will not find anything, since template was created from the original config, which - // uses the original prefix. - randoms = template.randoms(); + // this will throw an exception since anotherPrefix.randoms is not one of the keys in the + // configuration. + try { + randoms = template.randoms(); + } catch (Exception e) { + System.out.println("Caught expected RuntimeException:\n" + e.getLocalizedMessage()); + randoms = new ArrayList<>(); + } for (SomeRandomClass random : randoms) System.out.println("random.toUpperCase() = " + random.toUpperCase()); } - } diff --git a/demo/src/main/java/jackfruit/demo/SomeRandomClass.java b/demo/src/main/java/jackfruit/demo/SomeRandomClass.java index e812e87..592baa8 100644 --- a/demo/src/main/java/jackfruit/demo/SomeRandomClass.java +++ b/demo/src/main/java/jackfruit/demo/SomeRandomClass.java @@ -9,9 +9,9 @@ package jackfruit.demo; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -35,5 +35,4 @@ public class SomeRandomClass { public String toUpperCase() { return internalString.toUpperCase(); } - } diff --git a/demo/src/test/java/jackfruit/demo/TestProcessor.java b/demo/src/test/java/jackfruit/demo/TestProcessor.java index e77293c..be240e5 100644 --- a/demo/src/test/java/jackfruit/demo/TestProcessor.java +++ b/demo/src/test/java/jackfruit/demo/TestProcessor.java @@ -39,9 +39,8 @@ import org.junit.Test; /** * From https://stackoverflow.com/questions/21427301/debugging-annotation-processors-in-eclipse - * - * @author nairah1 * + * @author Hari.Nair@jhuapl.edu */ public class TestProcessor { diff --git a/jackfruit/pom.xml b/jackfruit/pom.xml index ec3d108..b7dc674 100644 --- a/jackfruit/pom.xml +++ b/jackfruit/pom.xml @@ -3,16 +3,16 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + jackfruit-parent - edu.jhuapl.ses.srn + edu.jhuapl.ses 1.0-SNAPSHOT jackfruit jackfruit - Java Annotations Configuration library @@ -26,7 +26,7 @@ 17 17 - 1.1.0 + 1.1.1 2.9.0 2.20.0 2.9.3 @@ -84,6 +84,9 @@ ${project.basedir}/src/main/bash/createVersionFile.bash + + ${project.version} + diff --git a/jackfruit/src/main/bash/createVersionFile.bash b/jackfruit/src/main/bash/createVersionFile.bash index c747137..98b30af 100755 --- a/jackfruit/src/main/bash/createVersionFile.bash +++ b/jackfruit/src/main/bash/createVersionFile.bash @@ -7,22 +7,10 @@ srcFile="../java/jackfruit/JackfruitVersion.java" cd "$(dirname "$0")" +version=$1 + date=$(date -u +"%y.%m.%d") -rev=$(git rev-parse --verify --short=8 HEAD) -if [ $? -gt 0 ]; then - lastCommit=$(date -u +"%y.%m.%d") - rev="UNVERSIONED" -else - lastCommit=$(git log -1 --format=%cd --date=format:%y.%m.%d) - - if [[ $(git diff --stat) != '' ]]; then - if [[ $(git status -s | grep -v pom.xml | grep -v pom.bak | grep -v .m2 | grep -v $srcFile) != '' ]]; then - rev=${rev}M - fi - fi -fi - mkdir -p "$(dirname "$srcFile")" touch $srcFile @@ -32,9 +20,7 @@ cat < $srcFile package jackfruit; public class JackfruitVersion { - public final static String lastCommit = "$lastCommit"; - // an M at the end of gitRevision means this was built from a "dirty" git repository - public final static String rev = "$rev"; + public final static String version = "$version"; public final static String packageName = "$package"; public final static String dateString = "$date"; } diff --git a/jackfruit/src/main/java/jackfruit/JackfruitVersion.java b/jackfruit/src/main/java/jackfruit/JackfruitVersion.java index 8ad0d61..d5dc6d8 100644 --- a/jackfruit/src/main/java/jackfruit/JackfruitVersion.java +++ b/jackfruit/src/main/java/jackfruit/JackfruitVersion.java @@ -2,10 +2,8 @@ package jackfruit; public class JackfruitVersion { - public final static String lastCommit = "23.06.04"; - // an M at the end of gitRevision means this was built from a "dirty" git repository - public final static String rev = "72908621"; + public final static String version = "1.0-SNAPSHOT"; public final static String packageName = "jackfruit"; - public final static String dateString = "23.06.04"; + public final static String dateString = "23.09.02"; } diff --git a/jackfruit/src/main/java/jackfruit/annotations/Comment.java b/jackfruit/src/main/java/jackfruit/annotations/Comment.java index 84acb13..9c8a485 100644 --- a/jackfruit/src/main/java/jackfruit/annotations/Comment.java +++ b/jackfruit/src/main/java/jackfruit/annotations/Comment.java @@ -28,8 +28,8 @@ import java.lang.annotation.Target; /** * The Comment annotation specifies the comment that appears in the configuration file above the * parameter itself. - * - * @author nairah1 + * + * @author Hari.Nair@jhuapl.edu * */ @Retention(RetentionPolicy.SOURCE) diff --git a/jackfruit/src/main/java/jackfruit/annotations/DefaultValue.java b/jackfruit/src/main/java/jackfruit/annotations/DefaultValue.java index bf3a80f..956fd7f 100644 --- a/jackfruit/src/main/java/jackfruit/annotations/DefaultValue.java +++ b/jackfruit/src/main/java/jackfruit/annotations/DefaultValue.java @@ -32,8 +32,8 @@ import java.lang.annotation.Target; * Strings and primitives (and their corresponding wrapper types) are read natively. Other objects * will need to use the {@link ParserClass} annotation to specify a class which implements the * {@link Parser} interface to convert the object to and from a String. - * - * @author nairah1 + * + * @author Hari.Nair@jhuapl.edu * */ @Retention(RetentionPolicy.SOURCE) diff --git a/jackfruit/src/main/java/jackfruit/annotations/Jackfruit.java b/jackfruit/src/main/java/jackfruit/annotations/Jackfruit.java index 06ced97..dfe10c5 100644 --- a/jackfruit/src/main/java/jackfruit/annotations/Jackfruit.java +++ b/jackfruit/src/main/java/jackfruit/annotations/Jackfruit.java @@ -9,9 +9,9 @@ package jackfruit.annotations; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,16 +27,15 @@ import java.lang.annotation.Target; /** * Use this annotation to signify that it should be run through the annotation processor. There is - * an optional "prefix" argument that can be used to add a prefix to all of the configuration keys + * an optional "prefix" argument that can be used to add a prefix to all the configuration keys * created by the processor. - *

      - * For example:
      - * @Jackfruit(prefix = "myPrefix") - *

      - * Inspired by owner. - * - * @author nairah1 * + *

      For example:
      + * @Jackfruit(prefix = "myPrefix") + * + *

      Inspired by owner. + * + * @author Hari.Nair@jhuapl.edu */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/jackfruit/src/main/java/jackfruit/annotations/Key.java b/jackfruit/src/main/java/jackfruit/annotations/Key.java index 05e7453..30e88cc 100644 --- a/jackfruit/src/main/java/jackfruit/annotations/Key.java +++ b/jackfruit/src/main/java/jackfruit/annotations/Key.java @@ -9,9 +9,9 @@ package jackfruit.annotations; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,9 +28,8 @@ import java.lang.annotation.Target; /** * The Key annotation can be used to specify the name for the configuration key. The default is to * use the name of the method. - * - * @author nairah1 * + * @author Hari.Nair@jhuapl.edu */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.METHOD) diff --git a/jackfruit/src/main/java/jackfruit/annotations/Parser.java b/jackfruit/src/main/java/jackfruit/annotations/Parser.java index f3b1588..69d8df4 100644 --- a/jackfruit/src/main/java/jackfruit/annotations/Parser.java +++ b/jackfruit/src/main/java/jackfruit/annotations/Parser.java @@ -9,9 +9,9 @@ package jackfruit.annotations; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,10 +22,9 @@ package jackfruit.annotations; /** * Interface to serialize/deserialize a string to a custom class. - * - * @author nairah1 * - * @param + * @author Hari.Nair@jhuapl.edu + * @param Type to be serialized/deserialized */ public interface Parser { T fromString(String s); diff --git a/jackfruit/src/main/java/jackfruit/annotations/ParserClass.java b/jackfruit/src/main/java/jackfruit/annotations/ParserClass.java index 8159e76..df7e5b4 100644 --- a/jackfruit/src/main/java/jackfruit/annotations/ParserClass.java +++ b/jackfruit/src/main/java/jackfruit/annotations/ParserClass.java @@ -9,9 +9,9 @@ package jackfruit.annotations; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,9 +28,8 @@ import java.lang.annotation.Target; /** * The ParserClass annotation specifies a class which implements the {@link Parser} interface to * convert an object to and from a String. - * - * @author nairah1 * + * @author Hari.Nair@jhuapl.edu */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.METHOD) diff --git a/jackfruit/src/main/java/jackfruit/processor/AnnotationBundle.java b/jackfruit/src/main/java/jackfruit/processor/AnnotationBundle.java index 86558b8..195adf5 100644 --- a/jackfruit/src/main/java/jackfruit/processor/AnnotationBundle.java +++ b/jackfruit/src/main/java/jackfruit/processor/AnnotationBundle.java @@ -9,9 +9,9 @@ package jackfruit.processor; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -29,7 +29,7 @@ import org.immutables.value.Value; /** * Holds annotation information and other metadata about an annotated method. * - * @author nairah1 + * @author Hari.Nair@jhuapl.edu */ @Value.Immutable public abstract class AnnotationBundle { @@ -65,7 +65,7 @@ public abstract class AnnotationBundle { /** * @return If this configuration parameter is not a string or primitive/boxed type, this class * will convert the string to the proper object and vice versa. This class must implement - * {@link Parser}. + * {@link jackfruit.annotations.Parser}. */ public abstract Optional parserClass(); } diff --git a/jackfruit/src/main/java/jackfruit/processor/ConfigFactory.java b/jackfruit/src/main/java/jackfruit/processor/ConfigFactory.java index 3acbc25..6bc67e0 100644 --- a/jackfruit/src/main/java/jackfruit/processor/ConfigFactory.java +++ b/jackfruit/src/main/java/jackfruit/processor/ConfigFactory.java @@ -9,9 +9,9 @@ package jackfruit.processor; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,8 +28,8 @@ import org.apache.commons.configuration2.PropertiesConfigurationLayout; * This interface converts instances of annotated interfaces of type T to Apache Commons * Configuration files and vice versa. * - * @author nairah1 - * @param + * @author Hari.Nair@jhuapl.edu + * @param configuration class with annotations */ public interface ConfigFactory { diff --git a/jackfruit/src/main/java/jackfruit/processor/ConfigProcessor.java b/jackfruit/src/main/java/jackfruit/processor/ConfigProcessor.java index 4da059c..0f1512d 100644 --- a/jackfruit/src/main/java/jackfruit/processor/ConfigProcessor.java +++ b/jackfruit/src/main/java/jackfruit/processor/ConfigProcessor.java @@ -9,9 +9,9 @@ package jackfruit.processor; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,6 +20,22 @@ package jackfruit.processor; * #L% */ +import com.google.auto.service.AutoService; +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import com.squareup.javapoet.TypeVariableName; +import jackfruit.JackfruitVersion; +import jackfruit.annotations.Comment; +import jackfruit.annotations.DefaultValue; +import jackfruit.annotations.Jackfruit; +import jackfruit.annotations.Key; +import jackfruit.annotations.ParserClass; import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.Annotation; @@ -56,36 +72,20 @@ import javax.lang.model.util.Types; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import org.apache.commons.configuration2.Configuration; -import com.google.auto.service.AutoService; -import com.squareup.javapoet.AnnotationSpec; -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterSpec; -import com.squareup.javapoet.ParameterizedTypeName; -import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import com.squareup.javapoet.TypeVariableName; -import jackfruit.JackfruitVersion; -import jackfruit.annotations.Comment; -import jackfruit.annotations.DefaultValue; -import jackfruit.annotations.Jackfruit; -import jackfruit.annotations.Key; -import jackfruit.annotations.ParserClass; /** * Useful references for writing an annotation processor: - *

      - * - * @author nairah1 * + * + * + * @author Hari.Nair@jhuapl.edu */ @SupportedSourceVersion(SourceVersion.RELEASE_17) @SupportedAnnotationTypes("jackfruit.annotations.Jackfruit") @@ -107,10 +107,14 @@ public class ConfigProcessor extends AbstractProcessor { messager = processingEnv.getMessager(); // find interfaces or abstract classes with the Jackfruit annotation - List annotatedElements = roundEnv.getElementsAnnotatedWith(Jackfruit.class).stream() - .filter(e -> e.getKind() == ElementKind.INTERFACE - || (e.getKind() == ElementKind.CLASS && e.getModifiers().contains(Modifier.ABSTRACT))) - .collect(Collectors.toList()); + List annotatedElements = + roundEnv.getElementsAnnotatedWith(Jackfruit.class).stream() + .filter( + e -> + e.getKind() == ElementKind.INTERFACE + || (e.getKind() == ElementKind.CLASS + && e.getModifiers().contains(Modifier.ABSTRACT))) + .collect(Collectors.toList()); for (Element element : annotatedElements) { @@ -119,16 +123,16 @@ public class ConfigProcessor extends AbstractProcessor { Jackfruit configParams = annotatedType.getAnnotation(Jackfruit.class); String prefix = configParams.prefix().strip(); - if (prefix.length() > 0 && !prefix.endsWith(".")) - prefix += "."; + if (!prefix.isEmpty() && !prefix.endsWith(".")) prefix += "."; // This is the templatized class with annotations to be processed (e.g. // ConfigTemplate) TypeVariableName tvn = TypeVariableName.get(annotatedType.getSimpleName().toString()); // This is the generic class (e.g. ConfigFactory) - ParameterizedTypeName ptn = ParameterizedTypeName - .get(ClassName.get(jackfruit.processor.ConfigFactory.class), tvn); + ParameterizedTypeName ptn = + ParameterizedTypeName.get( + ClassName.get(jackfruit.processor.ConfigFactory.class), tvn); // This is the name of the class to create (e.g. ConfigTemplateFactory) String factoryName = String.format("%sFactory", annotatedType.getSimpleName()); @@ -136,16 +140,21 @@ public class ConfigProcessor extends AbstractProcessor { OffsetDateTime now = OffsetDateTime.now(); DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; - AnnotationSpec generated = AnnotationSpec.builder(Generated.class) - .addMember("value", String.format("\"%s\"", JackfruitVersion.packageName)) - .addMember("date", String.format("\"%s\"", formatter.format(now))) - .addMember("comments", String.format("\"version %s-%s\"", JackfruitVersion.dateString, - JackfruitVersion.rev)) - .build(); + AnnotationSpec generated = + AnnotationSpec.builder(Generated.class) + .addMember("value", String.format("\"%s\"", JackfruitVersion.packageName)) + .addMember("date", String.format("\"%s\"", formatter.format(now))) + .addMember( + "comments", + String.format( + "\"version %s built %s\"", JackfruitVersion.version, JackfruitVersion.dateString)) + .build(); TypeSpec.Builder classBuilder = - TypeSpec.classBuilder(factoryName).addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .addSuperinterface(ptn).addAnnotation(generated); + TypeSpec.classBuilder(factoryName) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addSuperinterface(ptn) + .addAnnotation(generated); /*- // logger for the generated class FieldSpec loggerField = FieldSpec.builder(org.apache.logging.log4j.Logger.class, "logger") @@ -185,8 +194,8 @@ public class ConfigProcessor extends AbstractProcessor { && e instanceof ExecutableElement ex) { enclosedMethods.put(ex.getSimpleName(), ex); AnnotationBundle defaultValues = defaultAnnotationsMap.get(ex.getSimpleName()); - defaultAnnotationsMap.put(ex.getSimpleName(), - buildAnnotationBundle(ex, defaultValues)); + defaultAnnotationsMap.put( + ex.getSimpleName(), buildAnnotationBundle(ex, defaultValues)); } } } @@ -201,28 +210,33 @@ public class ConfigProcessor extends AbstractProcessor { // default constructor; initialize prefix String prefixMemberName = "prefix"; classBuilder.addField(String.class, prefixMemberName, Modifier.PRIVATE, Modifier.FINAL); - MethodSpec constructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC) - .addStatement("this.$N = $S", prefixMemberName, prefix).build(); + MethodSpec constructor = + MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addStatement("this.$N = $S", prefixMemberName, prefix) + .build(); classBuilder.addMethod(constructor); // add a constructor where caller can set prefix constructor = - MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC) + MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) .addParameter(String.class, prefixMemberName) .beginControlFlow("if ($N == null)", prefixMemberName) - .addStatement("$N = \"\"", prefixMemberName).endControlFlow() + .addStatement("$N = \"\"", prefixMemberName) + .endControlFlow() .addStatement("$N = $N.strip()", prefixMemberName, prefixMemberName) - .addStatement("if (!$N.endsWith(\".\")) $N += $S", prefixMemberName, - prefixMemberName, ".") - .addStatement("this.$N = $N", prefixMemberName, prefixMemberName).build(); + .addStatement( + "if (!$N.endsWith(\".\")) $N += $S", prefixMemberName, prefixMemberName, ".") + .addStatement("this.$N = $N", prefixMemberName, prefixMemberName) + .build(); classBuilder.addMethod(constructor); // generate the methods from the interface List methods = new ArrayList<>(); for (Method m : ConfigFactory.class.getMethods()) { - if (m.isDefault()) - continue; + if (m.isDefault()) continue; if (m.getName().equals("toConfig")) { MethodSpec toConfig = buildToConfig(tvn, m, annotationsMap, prefixMemberName); @@ -238,7 +252,6 @@ public class ConfigProcessor extends AbstractProcessor { MethodSpec fromConfig = buildFromConfig(tvn, m, annotationsMap, prefixMemberName); methods.add(fromConfig); } - } methods.addAll(buildWithMethods(tvn, annotationsMap, prefixMemberName)); @@ -254,8 +267,8 @@ public class ConfigProcessor extends AbstractProcessor { try (PrintWriter pw = new PrintWriter(jfo.openWriter())) { javaFile.writeTo(pw); } - messager.printMessage(Diagnostic.Kind.NOTE, - String.format("wrote %s", javaFile.toJavaFileObject().toUri())); + messager.printMessage( + Diagnostic.Kind.NOTE, String.format("wrote %s", javaFile.toJavaFileObject().toUri())); } } catch (IOException e1) { messager.printMessage(Diagnostic.Kind.ERROR, e1.getLocalizedMessage()); @@ -263,17 +276,15 @@ public class ConfigProcessor extends AbstractProcessor { } } return true; - } /** - * * @param e annotated method * @param defaultValues default values for annotations - could be from a parent class * @return annotation values */ - private AnnotationBundle buildAnnotationBundle(ExecutableElement e, - AnnotationBundle defaultValues) { + private AnnotationBundle buildAnnotationBundle( + ExecutableElement e, AnnotationBundle defaultValues) { ImmutableAnnotationBundle.Builder builder = ImmutableAnnotationBundle.builder(); builder.key(e.getSimpleName().toString()); @@ -300,19 +311,22 @@ public class ConfigProcessor extends AbstractProcessor { } else if (erasure.getKind().isPrimitive()) { // no type arguments here } else { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, String.format( - "Unsupported kind %s for type %s!", erasure.getKind().toString(), erasure.toString())); + processingEnv + .getMessager() + .printMessage( + Diagnostic.Kind.ERROR, + String.format( + "Unsupported kind %s for type %s!", + erasure.getKind().toString(), erasure)); } builder.addAllTypeArgs(typeArgs); List methodAnnotations = new ArrayList<>(); - for (var a : supportedMethodAnnotations) - methodAnnotations.add(e.getAnnotation(a)); + for (var a : supportedMethodAnnotations) methodAnnotations.add(e.getAnnotation(a)); for (Annotation annotation : methodAnnotations) { - if (annotation == null) - continue; + if (annotation == null) continue; if (annotation instanceof Key) { builder.key(((Key) annotation).value()); @@ -340,34 +354,45 @@ public class ConfigProcessor extends AbstractProcessor { AnnotationBundle bundle = builder.build(); if (ConfigProcessorUtils.isList(bundle.erasure(), processingEnv) - && bundle.typeArgs().size() == 0) - messager.printMessage(Diagnostic.Kind.ERROR, + && bundle.typeArgs().isEmpty()) + messager.printMessage( + Diagnostic.Kind.ERROR, String.format("No parameter type for List on method %s!", e.getSimpleName())); return bundle; } /** * Build the method to generate an Apache Commons {@link Configuration} from an object - * + * * @param tvn * @param m * @param annotationsMap * @param prefixMemberName * @return */ - private MethodSpec buildToConfig(TypeVariableName tvn, Method m, - Map annotationsMap, String prefixMemberName) { + private MethodSpec buildToConfig( + TypeVariableName tvn, + Method m, + Map annotationsMap, + String prefixMemberName) { ParameterSpec ps = ParameterSpec.builder(tvn, "t").build(); - ParameterSpec layout = ParameterSpec.builder(TypeVariableName.get( - org.apache.commons.configuration2.PropertiesConfigurationLayout.class.getCanonicalName()), - "layout").build(); + ParameterSpec layout = + ParameterSpec.builder( + TypeVariableName.get( + org.apache.commons.configuration2.PropertiesConfigurationLayout.class + .getCanonicalName()), + "layout") + .build(); MethodSpec.Builder methodBuilder = - MethodSpec.methodBuilder(m.getName()).addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC).returns(m.getGenericReturnType()); + MethodSpec.methodBuilder(m.getName()) + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(m.getGenericReturnType()); methodBuilder.addParameter(ps); methodBuilder.addParameter(layout); - methodBuilder.addStatement("$T config = new $T()", + methodBuilder.addStatement( + "$T config = new $T()", org.apache.commons.configuration2.PropertiesConfiguration.class, org.apache.commons.configuration2.PropertiesConfiguration.class); methodBuilder.addStatement("config.setLayout($N)", layout); @@ -377,8 +402,8 @@ public class ConfigProcessor extends AbstractProcessor { AnnotationBundle ab = annotationsMap.get(method); String key = ab.key(); if (needBlank) { - methodBuilder.addStatement("$N.setBlankLinesBefore($N + $S, 1)", layout, prefixMemberName, - key); + methodBuilder.addStatement( + "$N.setBlankLinesBefore($N + $S, 1)", layout, prefixMemberName, key); needBlank = false; } @@ -405,49 +430,54 @@ public class ConfigProcessor extends AbstractProcessor { } else { TypeMirror typeArg = ab.typeArgs().get(0); if (ConfigProcessorUtils.isByte(typeArg, processingEnv)) - methodBuilder.addStatement("$L.add($T.toString(element))", listName, - java.lang.Byte.class); + 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); + 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); + 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); + 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); + 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); + 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); + 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("config.setProperty($N + $S, $L)", prefixMemberName, key, - listName); + methodBuilder.addStatement( + "config.setProperty($N + $S, $L)", prefixMemberName, key, listName); } else { if (ab.parserClass().isPresent()) { // store the serialized string as the property - methodBuilder.addStatement("config.setProperty($N + $S, $L.toString($N.$L()))", - prefixMemberName, key, parserName, ps, method.getSimpleName()); - } else { - methodBuilder.addStatement("config.setProperty($N + $S, t.$L())", prefixMemberName, key, + methodBuilder.addStatement( + "config.setProperty($N + $S, $L.toString($N.$L()))", + prefixMemberName, + key, + parserName, + ps, method.getSimpleName()); + } else { + methodBuilder.addStatement( + "config.setProperty($N + $S, t.$L())", prefixMemberName, key, method.getSimpleName()); } } // add the comment - if (ab.comment().length() > 0) { + if (!ab.comment().isEmpty()) { String commentName = String.format("%sComment", method.getSimpleName()); methodBuilder.addStatement("$T $L = $S", String.class, commentName, ab.comment()); - methodBuilder.addStatement("$N.setComment($N + $S, $L)", layout, prefixMemberName, key, - commentName); + methodBuilder.addStatement( + "$N.setComment($N + $S, $L)", layout, prefixMemberName, key, commentName); } } @@ -458,27 +488,33 @@ public class ConfigProcessor extends AbstractProcessor { /** * Create a method that returns a template object, populated by the default values - * + * * @param tvn * @param m * @param annotationsMap * @return */ - private MethodSpec buildGetTemplate(TypeVariableName tvn, Method m, - Map annotationsMap) { + private MethodSpec buildGetTemplate( + TypeVariableName tvn, Method m, Map annotationsMap) { // this builds the getTemplate() method - MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(m.getName()) - .addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(tvn); + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder(m.getName()) + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(tvn); TypeSpec.Builder typeBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(tvn); for (ExecutableElement method : annotationsMap.keySet()) { AnnotationBundle bundle = annotationsMap.get(method); // this builds the method on the anonymous class - MethodSpec.Builder builder = MethodSpec.methodBuilder(method.getSimpleName().toString()) - .addModifiers(Modifier.PUBLIC).addAnnotation(Override.class) - .returns(TypeName.get(method.getReturnType())).addJavadoc(bundle.comment()); + MethodSpec.Builder builder = + MethodSpec.methodBuilder(method.getSimpleName().toString()) + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns(TypeName.get(method.getReturnType())) + .addJavadoc(bundle.comment()); TypeMirror parser = null; String parserName = null; @@ -498,8 +534,8 @@ public class ConfigProcessor extends AbstractProcessor { String listName = method.getSimpleName() + "List"; builder.addStatement("$T " + listName + " = new $T()", listType, arrayListType); - builder.addStatement("String [] parts = ($S).split($S)", bundle.defaultValue(), - "[\\n\\r\\s]+"); + builder.addStatement( + "String [] parts = ($S).split($S)", bundle.defaultValue(), "[\\n\\r\\s]+"); builder.beginControlFlow("for (String part : parts)"); builder.beginControlFlow("if (part.trim().length() > 0)"); if (bundle.parserClass().isPresent()) { @@ -534,9 +570,13 @@ public class ConfigProcessor extends AbstractProcessor { if (ConfigProcessorUtils.isString(bundle.erasure(), processingEnv)) { builder.addStatement("return $S", bundle.defaultValue()); } else { - if (bundle.defaultValue().trim().length() == 0) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - String.format("Default value on method %s is blank!", method.getSimpleName())); + if (bundle.defaultValue().trim().isEmpty()) { + processingEnv + .getMessager() + .printMessage( + Diagnostic.Kind.ERROR, + String.format( + "Default value on method %s is blank!", method.getSimpleName())); } builder.addStatement("return $L", bundle.defaultValue()); } @@ -551,31 +591,40 @@ public class ConfigProcessor extends AbstractProcessor { /** * Create a method to create a configuration from the object - * + * * @param tvn * @param m * @param annotationsMap * @param prefix * @return */ - private MethodSpec buildFromConfig(TypeVariableName tvn, Method m, - Map annotationsMap, String prefix) { + private MethodSpec buildFromConfig( + TypeVariableName tvn, + Method m, + Map annotationsMap, + String prefix) { - MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(m.getName()) - .addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(tvn) - .addParameter(org.apache.commons.configuration2.Configuration.class, "config"); + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder(m.getName()) + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(tvn) + .addParameter(org.apache.commons.configuration2.Configuration.class, "config"); TypeSpec.Builder typeBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(tvn); for (ExecutableElement method : annotationsMap.keySet()) { AnnotationBundle bundle = annotationsMap.get(method); - MethodSpec.Builder builder = MethodSpec.methodBuilder(method.getSimpleName().toString()) - .addModifiers(Modifier.PUBLIC).addAnnotation(Override.class) - .returns(TypeName.get(method.getReturnType())).addJavadoc(bundle.comment()); + MethodSpec.Builder builder = + MethodSpec.methodBuilder(method.getSimpleName().toString()) + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns(TypeName.get(method.getReturnType())) + .addJavadoc(bundle.comment()); builder.addStatement("String key = $N + $S", prefix, bundle.key()); builder .beginControlFlow("if (!config.containsKey(key))") - .addStatement("throw new $T($S + key)", RuntimeException.class, "No such key") + .addStatement("throw new $T($S + key)", RuntimeException.class, "No such key ") .endControlFlow(); TypeMirror parser = null; @@ -642,8 +691,11 @@ public class ConfigProcessor extends AbstractProcessor { } else if (ConfigProcessorUtils.isString(bundle.erasure(), processingEnv)) { builder.addStatement("return config.getString(key)"); } else { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Can't handle return type " + m.getReturnType().getCanonicalName()); + processingEnv + .getMessager() + .printMessage( + Diagnostic.Kind.ERROR, + "Can't handle return type " + m.getReturnType().getCanonicalName()); } } } @@ -656,14 +708,16 @@ public class ConfigProcessor extends AbstractProcessor { /** * Create a method for each member that allows it to be replaced. - * + * * @param tvn * @param annotationsMap * @param prefixMemberName * @return */ - private List buildWithMethods(TypeVariableName tvn, - Map annotationsMap, String prefixMemberName) { + private List buildWithMethods( + TypeVariableName tvn, + Map annotationsMap, + String prefixMemberName) { List withMethods = new ArrayList<>(); @@ -671,14 +725,17 @@ public class ConfigProcessor extends AbstractProcessor { for (ExecutableElement method : annotationsMap.keySet()) { String methodName = method.getSimpleName().toString(); - String camelCase = String.format("with%s%s", methodName.substring(0, 1).toUpperCase(), - methodName.substring(1)); + String camelCase = + String.format( + "with%s%s", methodName.substring(0, 1).toUpperCase(), methodName.substring(1)); TypeName propertiesConfigurationClass = TypeName.get(org.apache.commons.configuration2.PropertiesConfiguration.class); // method with object passed in as an argument - MethodSpec.Builder builder = MethodSpec.methodBuilder(camelCase).addModifiers(Modifier.PUBLIC) - .returns(propertiesConfigurationClass); + MethodSpec.Builder builder = + MethodSpec.methodBuilder(camelCase) + .addModifiers(Modifier.PUBLIC) + .returns(propertiesConfigurationClass); builder.addJavadoc("Replace the value of " + methodName); builder.addParameter(ps); builder.addParameter( @@ -688,8 +745,10 @@ public class ConfigProcessor extends AbstractProcessor { withMethods.add(builder.build()); // method with PropertiesConfiguration passed in as an argument - builder = MethodSpec.methodBuilder(camelCase).addModifiers(Modifier.PUBLIC) - .returns(propertiesConfigurationClass); + builder = + MethodSpec.methodBuilder(camelCase) + .addModifiers(Modifier.PUBLIC) + .returns(propertiesConfigurationClass); builder.addJavadoc("Replace the value of " + methodName); builder.addParameter(ParameterSpec.builder(propertiesConfigurationClass, "config").build()); builder.addParameter( @@ -742,8 +801,11 @@ public class ConfigProcessor extends AbstractProcessor { } else { if (ab.parserClass().isPresent()) { // store the serialized string as the property - builder.addStatement("config.setProperty($N + $S, $L.toString(replaceValue))", - prefixMemberName, key, parserName); + builder.addStatement( + "config.setProperty($N + $S, $L.toString(replaceValue))", + prefixMemberName, + key, + parserName); } else { builder.addStatement("config.setProperty($N + $S, replaceValue)", prefixMemberName, key); } @@ -756,5 +818,4 @@ public class ConfigProcessor extends AbstractProcessor { return withMethods; } - } diff --git a/jackfruit/src/main/java/jackfruit/processor/ConfigProcessorUtils.java b/jackfruit/src/main/java/jackfruit/processor/ConfigProcessorUtils.java index 2f91d39..bc54d32 100644 --- a/jackfruit/src/main/java/jackfruit/processor/ConfigProcessorUtils.java +++ b/jackfruit/src/main/java/jackfruit/processor/ConfigProcessorUtils.java @@ -9,9 +9,9 @@ package jackfruit.processor; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -30,7 +30,11 @@ import javax.tools.Diagnostic; public class ConfigProcessorUtils { /** - * @param processingEnv + * + * @param typeMirror the return type without any parameters (e.g. List rather than + * * List<String>) + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link List} */ public static boolean isList(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { @@ -38,9 +42,10 @@ public class ConfigProcessorUtils { } /** - * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link - * AnnotationBundle#typeArgs()} for a parameterized type - * @param processingEnv + * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element + * of {@link AnnotationBundle#typeArgs()} for a parameterized type + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link Boolean} or primitive boolean */ public static boolean isBoolean(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { @@ -49,9 +54,10 @@ public class ConfigProcessorUtils { } /** - * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link - * AnnotationBundle#typeArgs()} for a parameterized type - * @param processingEnv + * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element + * of {@link AnnotationBundle#typeArgs()} for a parameterized type + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link Byte} or primitive byte */ public static boolean isByte(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { @@ -60,9 +66,10 @@ public class ConfigProcessorUtils { } /** - * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link - * AnnotationBundle#typeArgs()} for a parameterized type - * @param processingEnv + * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element + * of {@link AnnotationBundle#typeArgs()} for a parameterized type + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link Double} or primitive double */ public static boolean isDouble(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { @@ -71,9 +78,10 @@ public class ConfigProcessorUtils { } /** - * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link - * AnnotationBundle#typeArgs()} for a parameterized type - * @param processingEnv + * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element + * of {@link AnnotationBundle#typeArgs()} for a parameterized type + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link Float} or primitive float */ public static boolean isFloat(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { @@ -82,9 +90,10 @@ public class ConfigProcessorUtils { } /** - * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link - * AnnotationBundle#typeArgs()} for a parameterized type - * @param processingEnv + * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element + * of {@link AnnotationBundle#typeArgs()} for a parameterized type + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link Integer} or primitive int */ public static boolean isInteger(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { @@ -93,9 +102,10 @@ public class ConfigProcessorUtils { } /** - * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link - * AnnotationBundle#typeArgs()} for a parameterized type - * @param processingEnv + * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element + * of {@link AnnotationBundle#typeArgs()} for a parameterized type + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link Long} or primitive long */ public static boolean isLong(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { @@ -104,9 +114,10 @@ public class ConfigProcessorUtils { } /** - * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link - * AnnotationBundle#typeArgs()} for a parameterized type - * @param processingEnv + * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element + * of {@link AnnotationBundle#typeArgs()} for a parameterized type + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link Short} or primitive float */ public static boolean isShort(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { @@ -115,9 +126,10 @@ public class ConfigProcessorUtils { } /** - * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link - * AnnotationBundle#typeArgs()} for a parameterized type - * @param processingEnv + * @param typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element + * of {@link AnnotationBundle#typeArgs()} for a parameterized type + * @param processingEnv Processing environment providing by the tool framework, from {@link + * javax.annotation.processing.AbstractProcessor} * @return true if this annotated member returns a {@link String} */ public static boolean isString(TypeMirror typeMirror, ProcessingEnvironment processingEnv) { diff --git a/pom.xml b/pom.xml index 2ebd086..4610438 100644 --- a/pom.xml +++ b/pom.xml @@ -3,16 +3,20 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - edu.jhuapl.ses.srn + + edu.jhuapl.ses jackfruit-parent 1.0-SNAPSHOT pom + jackfruit-parent + Jackfruit processes annotations on Java interfaces and abstract classes to generate code that can read and write Apache Configuration files. + https://github.com/JHUAPL/Jackfruit 2023 Johns Hopkins University Applied Physics Laboratory - http://jhuapl.edu + https://www.jhuapl.edu/ @@ -22,14 +26,31 @@ - + + + HariNairJHUAPL + Hari Nair + Hari.Nair@jhuapl.edu + JHUAPL + https://www.jhuapl.edu/ + + + + + scm:git:https://github.com/JHUAPL/Jackfruit.git + https://github.com/JHUAPL/Jackfruit.git + scm:git:https://github.com/JHUAPL/Jackfruit.git + HEAD + + + - - central - surfshop-snapshots - http://surfshop.jhuapl.edu:8081/artifactory/libs-snapshot-local - + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + UTF-8 17 @@ -45,8 +66,8 @@ 4.13.2 test - + @@ -56,7 +77,7 @@ https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> maven-clean-plugin - 3.2.0 + 3.3.1 @@ -73,7 +94,7 @@ maven-surefire-plugin - 3.1.0 + 3.1.2 maven-jar-plugin @@ -85,14 +106,28 @@ maven-deploy-plugin - 2.8.2 + 3.1.1 + + org.apache.maven.plugins + maven-javadoc-plugin + 3.5.0 + + + attach-javadocs + + jar + + + + + maven-site-plugin - 4.0.0-M8 + 4.0.0-M9 ${maven-site-plugin.skip} @@ -100,13 +135,13 @@ maven-project-info-reports-plugin - 3.4.4 + 3.4.5 org.codehaus.mojo license-maven-plugin - 2.0.1 + 2.2.0 apache_v2 @@ -139,10 +174,15 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + + org.apache.maven.plugins maven-enforcer-plugin - 3.3.0 + 3.4.0 enforce-maven @@ -160,6 +200,39 @@ + + org.apache.maven.plugins + maven-gpg-plugin + 3.1.0 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.13 + true + + ossrh + https://oss.sonatype.org/ + true + + +