diff --git a/table/annotation-processor/build.gradle b/table/annotation-processor/build.gradle index 38901440..54483d56 100644 --- a/table/annotation-processor/build.gradle +++ b/table/annotation-processor/build.gradle @@ -7,4 +7,5 @@ dependencies { api project(':table:core') implementation "org.apache.commons:commons-text:1.8" + implementation "org.apache.commons:commons-collections4:4.1" } diff --git a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/AnnotationElement.java b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/AnnotationElement.java new file mode 100644 index 00000000..9281b0e9 --- /dev/null +++ b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/AnnotationElement.java @@ -0,0 +1,34 @@ +package com.riiablo.table.annotation; + +import java.lang.annotation.Annotation; +import java.util.Map; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.ExecutableElement; +import org.apache.commons.lang3.builder.ToStringBuilder; + +abstract class AnnotationElement { + protected final Context context; + protected final A annotation; + protected final AnnotationMirror mirror; + + protected AnnotationElement(Context context, A annotation, AnnotationMirror mirror) { + this.context = context; + this.annotation = annotation; + this.mirror = mirror; + } + + Map + defaults() { + return context.elementUtils.getElementValuesWithDefaults(mirror); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("context", context) + .append("annotation", annotation) + .append("mirror", mirror) + .toString(); + } +} diff --git a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/Constants.java b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/Constants.java index 91037748..244aca9c 100644 --- a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/Constants.java +++ b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/Constants.java @@ -10,6 +10,7 @@ final class Constants { static final ClassName STRING = ClassName.get(String.class); static final ClassName PRIMARY_KEY = ClassName.get(PrimaryKey.class); + static final ClassName FORMAT = ClassName.get(Format.class); static final TypeName[] PRIMARY_KEY_TYPES = { TypeName.INT, STRING }; diff --git a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/Context.java b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/Context.java index df103e63..fef1ba78 100644 --- a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/Context.java +++ b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/Context.java @@ -67,7 +67,7 @@ class Context { } } - messager.printMessage(kind, builder); + messager.printMessage(kind, builder, element, annotationMirror, annotationValue); } void error(String message, Object... args) { diff --git a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/FieldElement.java b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/FieldElement.java new file mode 100644 index 00000000..3be893a1 --- /dev/null +++ b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/FieldElement.java @@ -0,0 +1,38 @@ +package com.riiablo.table.annotation; + +import java.util.Collection; +import javax.lang.model.element.VariableElement; + +final class FieldElement { + static FieldElement get(Context context, VariableElement element) { + FormatElement formatElement = FormatElement.get(context, element); + PrimaryKeyElement primaryKeyElement = PrimaryKeyElement.get(context, element); + + return new FieldElement(element, formatElement, primaryKeyElement); + } + + static FieldElement firstPrimaryKey(Collection fields) { + for (FieldElement field : fields) { + if (field.primaryKeyElement != null || Constants.isPrimaryKey(field.element)) { + return field; + } + } + + return null; + } + + final VariableElement element; + final FormatElement formatElement; + final PrimaryKeyElement primaryKeyElement; + + FieldElement(VariableElement element, FormatElement formatElement, PrimaryKeyElement primaryKeyElement) { + this.element = element; + this.formatElement = formatElement; + this.primaryKeyElement = primaryKeyElement; + } + + @Override + public String toString() { + return element.toString(); + } +} diff --git a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/FormatElement.java b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/FormatElement.java new file mode 100644 index 00000000..2b01abf0 --- /dev/null +++ b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/FormatElement.java @@ -0,0 +1,17 @@ +package com.riiablo.table.annotation; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.VariableElement; + +final class FormatElement extends AnnotationElement { + static FormatElement get(Context context, VariableElement element) { + Format annotation = element.getAnnotation(Format.class); + if (annotation == null) return null; + AnnotationMirror mirror = context.getAnnotationMirror(element, Constants.FORMAT); + return new FormatElement(context, annotation, mirror); + } + + FormatElement(Context context, Format annotation, AnnotationMirror mirror) { + super(context, annotation, mirror); + } +} diff --git a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/PrimaryKeyElement.java b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/PrimaryKeyElement.java index 0e34cc4b..4f2f8383 100644 --- a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/PrimaryKeyElement.java +++ b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/PrimaryKeyElement.java @@ -1,63 +1,17 @@ package com.riiablo.table.annotation; -import java.util.Collection; import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import org.apache.commons.lang3.builder.ToStringBuilder; -final class PrimaryKeyElement { - static PrimaryKeyElement find( - Context context, - TypeElement element, - Collection elements - ) { - VariableElement firstAcceptableElement = null, primaryKeyElement = null; - for (VariableElement e : elements) { - if (firstAcceptableElement == null && Constants.isPrimaryKey(e)) { - firstAcceptableElement = e; - } - - PrimaryKey annotation = e.getAnnotation(PrimaryKey.class); - if (annotation != null) { - if (primaryKeyElement == null) { - primaryKeyElement = e; - } else { - context.error( - e, context.getAnnotationMirror(e, Constants.PRIMARY_KEY), - "{} already declared as {}", primaryKeyElement, PrimaryKey.class); - } - } - } - - if (primaryKeyElement == null) { - if (firstAcceptableElement == null) { - context.error(element, "{element} did not declare any {}", PrimaryKey.class); - return null; - } - - context.warn(element, "{element} did not declare any {}, using {}", - PrimaryKey.class, firstAcceptableElement); - primaryKeyElement = firstAcceptableElement; - } - - AnnotationMirror primaryKeyMirror = context.getAnnotationMirror(primaryKeyElement, Constants.PRIMARY_KEY); - return new PrimaryKeyElement(primaryKeyElement, primaryKeyMirror); +final class PrimaryKeyElement extends AnnotationElement { + static PrimaryKeyElement get(Context context, VariableElement element) { + PrimaryKey annotation = element.getAnnotation(PrimaryKey.class); + if (annotation == null) return null; + AnnotationMirror mirror = context.getAnnotationMirror(element, Constants.PRIMARY_KEY); + return new PrimaryKeyElement(context, annotation, mirror); } - final VariableElement element; - final AnnotationMirror mirror; - - PrimaryKeyElement(VariableElement element, AnnotationMirror mirror) { - this.element = element; - this.mirror = mirror; - } - - @Override - public String toString() { - return new ToStringBuilder(this) - .append("element", element) - .append("mirror", mirror) - .toString(); + PrimaryKeyElement(Context context, PrimaryKey annotation, AnnotationMirror mirror) { + super(context, annotation, mirror); } } diff --git a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/SchemaElement.java b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/SchemaElement.java index 1c56c063..f0d19252 100644 --- a/table/annotation-processor/src/main/java/com/riiablo/table/annotation/SchemaElement.java +++ b/table/annotation-processor/src/main/java/com/riiablo/table/annotation/SchemaElement.java @@ -2,37 +2,63 @@ package com.riiablo.table.annotation; import com.squareup.javapoet.ClassName; import java.util.ArrayList; -import java.util.List; +import java.util.Collection; +import java.util.Iterator; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.IteratorUtils; +import org.apache.commons.collections4.Predicate; import org.apache.commons.lang3.builder.ToStringBuilder; final class SchemaElement { - static SchemaElement get(Context context, Element element) { + static SchemaElement get(final Context context, Element element) { TypeElement typeElement = (TypeElement) element; - List columns = collectColumns(context, typeElement); - PrimaryKeyElement primaryKeyElement = PrimaryKeyElement.find(context, typeElement, columns); + Collection fields = collectFieldElements(context, typeElement); - // for (VariableElement e : columns) { - // System.out.println(e); - // } + final FieldElement primaryKeyFieldElement; + Collection primaryKeys = CollectionUtils.select(fields, new Predicate() { + @Override + public boolean evaluate(FieldElement e) { + return e.primaryKeyElement != null; + } + }); + if (primaryKeys.size() >= 1) { + Iterator it = primaryKeys.iterator(); + primaryKeyFieldElement = it.next(); + for (FieldElement e : IteratorUtils.asIterable(it)) { + context.warn(e.element, e.primaryKeyElement.mirror, + "{} already declared as {}", + primaryKeyFieldElement, PrimaryKey.class); + } + } else { + primaryKeyFieldElement = FieldElement.firstPrimaryKey(fields); + if (primaryKeyFieldElement == null) { + context.error(element, "{element} did not declare any {}", PrimaryKey.class); + return null; + } + + context.warn(element, + "{element} did not declare any {}, using {}", + PrimaryKey.class, primaryKeyFieldElement); + } TableElement tableElement = TableElement.get(context, typeElement); SerializerElement serializerElement = SerializerElement.get(context, typeElement); - return new SchemaElement(typeElement, tableElement, serializerElement); + return new SchemaElement(typeElement, tableElement, serializerElement, primaryKeyFieldElement); } - static List collectColumns(Context context, TypeElement typeElement) { - List columns = new ArrayList<>(); + static Collection collectFieldElements(Context context, TypeElement typeElement) { + Collection columns = new ArrayList<>(); TypeElement superclassElement = typeElement; for (;;) { for (Element e : superclassElement.getEnclosedElements()) { switch (e.getKind()) { case FIELD: - columns.add((VariableElement) e); + columns.add(FieldElement.get(context, (VariableElement) e)); break; } } @@ -50,14 +76,17 @@ final class SchemaElement { final TypeElement element; final TableElement tableElement; final SerializerElement serializerElement; + final FieldElement primaryKeyFieldElement; SchemaElement( TypeElement element, TableElement tableElement, - SerializerElement serializerElement) { + SerializerElement serializerElement, + FieldElement primaryKeyFieldElement) { this.element = element; this.tableElement = tableElement; this.serializerElement = serializerElement; + this.primaryKeyFieldElement = primaryKeyFieldElement; } @Override @@ -66,6 +95,7 @@ final class SchemaElement { .append("element", element) .append("tableElement", tableElement) .append("serializerElement", serializerElement) + .append("primaryKeyFieldElement", primaryKeyFieldElement) .toString(); } }