mirror of
https://github.com/JHUAPL/Jackfruit.git
synced 2026-01-08 21:58:09 -05:00
Merge branch '6-string-stuff' into 'main'
Resolve "String stuff" Closes #6 See merge request nairah1/jackfruit!6
This commit is contained in:
67
README.md
67
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
## Quick start
|
||||
|
||||
Jackfruit processes annotations on Java interfaces to generate code that can read and write Apache Configuration files. The `demo` module includes sample code. In the top level directory, run `mvn clean package`, which will build the annotation library, run the annotation processor on the file `demo/src/main/java/jackfruit/demo/DemoConfig.java`, and generate the class `demo/target/generated-sources/annotations/jackfruit/demo/DemoConfigFactory.java`. The file `demo/src/main/java/jackfruit/demo/JackfruitDemo.java` shows some simple examples of use.
|
||||
Jackfruit processes annotations on Java interfaces to generate code that can read and write Apache Configuration files. The `demo` module includes sample code. In the top level directory, run `mvn clean package`, which will build the annotation library, run the annotation processor on the file `demo/src/main/java/jackfruit/demo/DemoInterface.java`, and generate the class `demo/target/generated-sources/annotations/jackfruit/demo/DemoInterfaceFactory.java`. The file `demo/src/main/java/jackfruit/demo/JackfruitDemo.java` shows some simple examples of use.
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -19,46 +19,66 @@ Include Jackfruit in your project with the following POM:
|
||||
|
||||
Find the latest version at [Surfshop](http://surfshop:8082/ui/repos/tree/General/libs-snapshot-local/edu/jhuapl/ses/srn/jackfruit/).
|
||||
|
||||
An example of an annotated interface is
|
||||
The annotation processor runs on any interface or abstract class annotated with `@Jackfruit`
|
||||
```
|
||||
@Jackfruit(prefix = "prefix")
|
||||
public interface DemoConfig {
|
||||
public interface DemoInterface {
|
||||
|
||||
// default key is field name
|
||||
@Key("key")
|
||||
@Comment("field comment")
|
||||
@DefaultValue("0")
|
||||
public int intMethod();
|
||||
@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 but that's really up to you.")
|
||||
@DefaultValue("0.")
|
||||
public Double doubleMethod();
|
||||
Double doubleMethod();
|
||||
|
||||
@Comment("""
|
||||
This is a multiline
|
||||
java text block.
|
||||
|
||||
This is a new paragraph.
|
||||
""")
|
||||
@DefaultValue("Default String")
|
||||
public String StringMethod();
|
||||
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 SomeRandomClass randomClass();
|
||||
SomeRandomClass randomClass();
|
||||
|
||||
@Comment("List of Doubles")
|
||||
@DefaultValue("0. 5.34 17")
|
||||
List<Double> doubles();
|
||||
|
||||
|
||||
@Comment("List of RandomClass")
|
||||
@DefaultValue("obj1 obj2")
|
||||
@DefaultValue("""
|
||||
obj1
|
||||
obj2
|
||||
|
||||
obj3 obj4
|
||||
""")
|
||||
@ParserClass(SomeRandomClassParser.class)
|
||||
List<SomeRandomClass> randoms();
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This corresponds to this Apache Configuration file:
|
||||
```
|
||||
# field comment
|
||||
prefix.key = 0
|
||||
# One line comment
|
||||
prefix.key = 1
|
||||
# This is a very long comment line that really should be wrapped into more than one line but that's really up to you.
|
||||
prefix.doubleMethod = 0.0
|
||||
# This is a multiline
|
||||
# java text block.
|
||||
|
||||
# This is a new paragraph.
|
||||
|
||||
prefix.StringMethod = Default String
|
||||
# This string is serialized into an object
|
||||
# This comment contains a newline character, and this line starts with a tab.
|
||||
prefix.randomClass = serialized string
|
||||
# List of Doubles
|
||||
prefix.doubles = 0.0
|
||||
@@ -67,15 +87,17 @@ prefix.doubles = 17.0
|
||||
# List of RandomClass
|
||||
prefix.randoms = obj1
|
||||
prefix.randoms = obj2
|
||||
prefix.randoms = obj3
|
||||
prefix.randoms = obj4
|
||||
```
|
||||
|
||||
The annotation processor generates a class called DemoConfigFactory. An example of use is
|
||||
The annotation processor generates a class called DemoInterfaceFactory. An example of use is
|
||||
```
|
||||
// this factory is built by the annotation processor after reading the DemoConfig interface
|
||||
DemoConfigFactory factory = new DemoConfigFactory();
|
||||
DemoInterfaceFactory factory = new DemoInterfaceFactory();
|
||||
|
||||
// get an example config object
|
||||
DemoConfig template = factory.getTemplate();
|
||||
DemoInterface template = factory.getTemplate();
|
||||
|
||||
// generate an Apache PropertiesConfiguration object. This can be written out to a file
|
||||
PropertiesConfiguration config = factory.toConfig(template);
|
||||
@@ -104,19 +126,22 @@ The annotation processor generates a class called DemoConfigFactory. An example
|
||||
template = factory.fromConfig(config);
|
||||
|
||||
// get one of the config object's properties
|
||||
System.out.printf("config.StringMethod() = %s\n", template.StringMethod());
|
||||
System.out.println("\n*** Retrieving a configuration value");
|
||||
List<SomeRandomClass> randoms = template.randoms();
|
||||
for (SomeRandomClass random : randoms)
|
||||
System.out.println("random.toUpperCase() = " + random.toUpperCase());
|
||||
```
|
||||
|
||||
## Supported Annotations
|
||||
|
||||
The `@Jackfruit` annotation goes on the interface. The remaining annotations are for use on the interface methods.
|
||||
The `@Jackfruit` annotation goes on the abstract type. The remaining annotations are for use on methods.
|
||||
|
||||
### Jackfruit
|
||||
This annotation goes on the interface 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 created by the processor.
|
||||
This annotation goes on the abstract type 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 created by the processor.
|
||||
|
||||
### Comment
|
||||
|
||||
The `@Comment` annotation specifies the comment that appears in the configuration file above the parameter itself.
|
||||
The `@Comment` annotation specifies the comment that appears in the configuration file above the parameter itself. This can be a multiline text block and include newlines and tabs.
|
||||
|
||||
### DefaultValue
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ public abstract class DemoClass {
|
||||
@DefaultValue("1")
|
||||
public abstract int intMethod();
|
||||
|
||||
@Comment("This is a very long comment line that really should be wrapped into more than one line")
|
||||
@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();
|
||||
|
||||
@@ -38,12 +38,17 @@ public abstract class DemoClass {
|
||||
public abstract List<Double> doubles();
|
||||
|
||||
@Comment("List of RandomClass")
|
||||
@DefaultValue("obj1 obj2")
|
||||
@DefaultValue("""
|
||||
obj1
|
||||
obj2
|
||||
|
||||
obj3 obj4
|
||||
""")
|
||||
@ParserClass(SomeRandomClassParser.class)
|
||||
public abstract List<SomeRandomClass> randoms();
|
||||
|
||||
public void noAnnotationsOnThisMethod() {
|
||||
System.out.println("This method was not processed");
|
||||
System.out.println("This method was not processed since it has no DefaultValue annotation");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ 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")
|
||||
@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();
|
||||
|
||||
@@ -72,7 +72,12 @@ public interface DemoInterface {
|
||||
List<Double> doubles();
|
||||
|
||||
@Comment("List of RandomClass")
|
||||
@DefaultValue("obj1 obj2")
|
||||
@DefaultValue("""
|
||||
obj1
|
||||
obj2
|
||||
|
||||
obj3 obj4
|
||||
""")
|
||||
@ParserClass(SomeRandomClassParser.class)
|
||||
List<SomeRandomClass> randoms();
|
||||
|
||||
|
||||
@@ -13,19 +13,19 @@ public class JackfruitDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
/*-
|
||||
// this factory is built by the annotation processor after reading
|
||||
// DemoClass
|
||||
DemoClassFactory factory = new DemoClassFactory();
|
||||
|
||||
|
||||
// get an example config object
|
||||
DemoClass template = factory.getTemplate();
|
||||
|
||||
/*-
|
||||
*/
|
||||
|
||||
// or if you prefer, use an interface
|
||||
DemoInterfaceFactory factory = new DemoInterfaceFactory();
|
||||
DemoInterface template = factory.getTemplate();
|
||||
*/
|
||||
|
||||
|
||||
// generate an Apache PropertiesConfiguration object. This can be written out to
|
||||
// a file
|
||||
PropertiesConfiguration config =
|
||||
|
||||
@@ -55,11 +55,6 @@
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.18.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
|
||||
@@ -31,7 +31,6 @@ 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;
|
||||
@@ -69,8 +68,10 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
|
||||
Messager messager = processingEnv.getMessager();
|
||||
|
||||
// find interfaces or abstract classes with the Jackfruit annotation
|
||||
List<Element> annotatedElements = roundEnv.getElementsAnnotatedWith(Jackfruit.class).stream()
|
||||
.filter(e -> e.getKind() == ElementKind.INTERFACE || e.getKind() == ElementKind.CLASS)
|
||||
.filter(e -> e.getKind() == ElementKind.INTERFACE
|
||||
|| (e.getKind() == ElementKind.CLASS && e.getModifiers().contains(Modifier.ABSTRACT)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Element element : annotatedElements) {
|
||||
@@ -338,8 +339,7 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
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.addStatement("$N.setComment($S, $L)", layout, key, commentName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,7 +382,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(), "\\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()) {
|
||||
|
||||
Reference in New Issue
Block a user