mirror of
https://github.com/JHUAPL/Jackfruit.git
synced 2026-01-09 14:18:05 -05:00
Merge branch '4-allow-abstract-classes' into 'main'
Resolve "Allow abstract classes" Closes #4 See merge request nairah1/jackfruit!4
This commit is contained in:
@@ -137,6 +137,3 @@ public interface Parser<T> {
|
||||
public String toString(T t);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
42
demo/src/main/java/jackfruit/demo/DemoClass.java
Normal file
42
demo/src/main/java/jackfruit/demo/DemoClass.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package jackfruit.demo;
|
||||
|
||||
import java.util.List;
|
||||
import jackfruit.annotations.Comment;
|
||||
import jackfruit.annotations.DefaultValue;
|
||||
import jackfruit.annotations.Jackfruit;
|
||||
import jackfruit.annotations.Key;
|
||||
import jackfruit.annotations.ParserClass;
|
||||
|
||||
@Jackfruit(prefix = "prefix")
|
||||
public abstract class DemoClass {
|
||||
|
||||
@Key("key")
|
||||
@Comment("field comment")
|
||||
@DefaultValue("0")
|
||||
public abstract int intMethod();
|
||||
|
||||
@DefaultValue("0.")
|
||||
public abstract Double doubleMethod();
|
||||
|
||||
@DefaultValue("Default String")
|
||||
public abstract String StringMethod();
|
||||
|
||||
@Comment("This string is serialized into an object")
|
||||
@DefaultValue("serialized string")
|
||||
@ParserClass(SomeRandomClassParser.class)
|
||||
public abstract SomeRandomClass randomClass();
|
||||
|
||||
@Comment("List of Doubles")
|
||||
@DefaultValue("0. 5.34 17")
|
||||
public abstract List<Double> doubles();
|
||||
|
||||
@Comment("List of RandomClass")
|
||||
@DefaultValue("obj1 obj2")
|
||||
@ParserClass(SomeRandomClassParser.class)
|
||||
public abstract List<SomeRandomClass> randoms();
|
||||
|
||||
public void noAnnotationsOnThisMethod() {
|
||||
System.out.println("This method was not processed");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,12 +33,6 @@ import jackfruit.annotations.ParserClass;
|
||||
* <ul>
|
||||
* <li>Optional, name of class to create object from String using its fromString() method</li>
|
||||
* </ul>
|
||||
* <li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* How to handle blocks like List<MISEObservingMode>?
|
||||
* <p>
|
||||
* Use <a href="https://github.com/square/javapoet">JavaPoet</a> to build a factory?
|
||||
* <p>
|
||||
* Inspired by <a href="http://owner.aeonbits.org/">owner</a>.
|
||||
*
|
||||
@@ -47,7 +41,7 @@ import jackfruit.annotations.ParserClass;
|
||||
*/
|
||||
|
||||
@Jackfruit(prefix = "prefix")
|
||||
public interface DemoConfig {
|
||||
public interface DemoInterface {
|
||||
|
||||
// default key is field name
|
||||
@Key("key")
|
||||
@@ -13,13 +13,19 @@ public class JackfruitDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
// this factory is built by the annotation processor after reading the
|
||||
// DemoConfig interface
|
||||
DemoConfigFactory factory = new DemoConfigFactory();
|
||||
// this factory is built by the annotation processor after reading
|
||||
// DemoClass
|
||||
DemoClassFactory factory = new DemoClassFactory();
|
||||
|
||||
// get an example config object
|
||||
DemoConfig template = factory.getTemplate();
|
||||
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 =
|
||||
|
||||
@@ -5,8 +5,15 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The Comment annotation specifies the comment that appears in the configuration file above the
|
||||
* parameter itself.
|
||||
*
|
||||
* @author nairah1
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Comment {
|
||||
public String value() default "";
|
||||
}
|
||||
|
||||
@@ -5,8 +5,19 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The DefaultValue annotation is a String used to initialize the parameter. This is a required
|
||||
* annotation. Methods without this annotation are ignored.
|
||||
* <p>
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface DefaultValue {
|
||||
public String value() default "";
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@ import java.lang.annotation.Target;
|
||||
* an optional "prefix" argument that can be used to add a prefix to all of the configuration keys
|
||||
* created by the processor.
|
||||
* <p>
|
||||
* For example:
|
||||
*
|
||||
* For example: <br>
|
||||
* @Jackfruit(prefix = "myPrefix")
|
||||
* <p>
|
||||
* Inspired by <a href="http://owner.aeonbits.org/">owner</a>.
|
||||
*
|
||||
* @author nairah1
|
||||
*
|
||||
|
||||
@@ -5,8 +5,15 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
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
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Key {
|
||||
public String value() default "";
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package jackfruit.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Parameter {
|
||||
public String key() default "";
|
||||
|
||||
public String comment() default "";
|
||||
}
|
||||
@@ -6,13 +6,14 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* This class will convert a String to/from an Object
|
||||
* The ParserClass annotation specifies a class which implements the {@link Parser} interface to
|
||||
* convert an object to and from a String.
|
||||
*
|
||||
* @author nairah1
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface ParserClass {
|
||||
public Class<?> value();
|
||||
}
|
||||
|
||||
@@ -68,10 +68,11 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
|
||||
Messager messager = processingEnv.getMessager();
|
||||
|
||||
List<Element> annotatedInterfaces = roundEnv.getElementsAnnotatedWith(Jackfruit.class).stream()
|
||||
.filter(e -> e.getKind() == ElementKind.INTERFACE).collect(Collectors.toList());
|
||||
List<Element> annotatedElements = roundEnv.getElementsAnnotatedWith(Jackfruit.class).stream()
|
||||
.filter(e -> e.getKind() == ElementKind.INTERFACE || e.getKind() == ElementKind.CLASS)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Element element : annotatedInterfaces) {
|
||||
for (Element element : annotatedElements) {
|
||||
|
||||
try {
|
||||
if (element instanceof TypeElement) {
|
||||
@@ -95,17 +96,19 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
|
||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(factoryName)
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL).addSuperinterface(ptn);
|
||||
/*-
|
||||
/*-
|
||||
// logger for the generated class
|
||||
FieldSpec loggerField = FieldSpec.builder(org.apache.logging.log4j.Logger.class, "logger")
|
||||
.initializer("$T.getLogger()", org.apache.logging.log4j.LogManager.class)
|
||||
.addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC).build();
|
||||
classBuilder.addField(loggerField);
|
||||
*/
|
||||
// create a list of annotated methods
|
||||
*/
|
||||
|
||||
// create a list of methods annotated with DefaultValue - ignore everything else
|
||||
List<ExecutableElement> enclosedMethods = new ArrayList<>();
|
||||
for (Element e : annotatedType.getEnclosedElements()) {
|
||||
if (e.getKind() == ElementKind.METHOD && e instanceof ExecutableElement)
|
||||
if (e.getKind() == ElementKind.METHOD && e.getAnnotation(DefaultValue.class) != null
|
||||
&& e instanceof ExecutableElement)
|
||||
enclosedMethods.add((ExecutableElement) e);
|
||||
}
|
||||
|
||||
@@ -124,11 +127,11 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
|
||||
List<TypeMirror> typeArgs = new ArrayList<>();
|
||||
if (erasure.getKind() == TypeKind.DECLARED) {
|
||||
// these are the parameter types for a List
|
||||
// these are the parameter types for a generic class
|
||||
List<? extends TypeMirror> args = ((DeclaredType) returnType).getTypeArguments();
|
||||
typeArgs.addAll(args);
|
||||
} 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(),
|
||||
|
||||
Reference in New Issue
Block a user