From 3e26f7e0cf9a1d8af22be9ca4ea5598a5a347927 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Thu, 4 Jun 2020 17:43:28 -0400 Subject: [PATCH] Generate Persistence Find methods by fields Signed-off-by: Daniel Bluhm --- .../dev/annotations/IPersistenceHandler.java | 14 ++++- .../processors/DataElementProcessor.java | 12 +++- .../annotations/processors/DefaultFields.java | 10 +++ .../ice/dev/annotations/processors/Field.java | 49 +++++++++++++++ .../PersistenceHandlerTemplateProperty.java | 3 +- .../resources/templates/PersistenceHandler.vm | 61 +++++-------------- .../java/org/eclipse/ice/renderer/Person.java | 5 +- 7 files changed, 102 insertions(+), 52 deletions(-) diff --git a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/IPersistenceHandler.java b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/IPersistenceHandler.java index fddbb51cf..929ad923b 100644 --- a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/IPersistenceHandler.java +++ b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/IPersistenceHandler.java @@ -1,6 +1,16 @@ package org.eclipse.ice.dev.annotations; +import java.util.UUID; + public interface IPersistenceHandler { public void save(T element) throws Exception; - public T findByID(String id) throws Exception; -} + public T findByUUID(UUID uuid) throws Exception; + public Iterable findById(long id) throws Exception; + public Iterable findByName(String name) throws Exception; + public Iterable findByDescription(String description) throws Exception; + public Iterable findByComment(String comment) throws Exception; + public Iterable findByContext(String context) throws Exception; + public Iterable findByRequired(boolean required) throws Exception; + public Iterable findBySecret(boolean secret) throws Exception; + public long clear() throws Exception; +} \ No newline at end of file diff --git a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/DataElementProcessor.java b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/DataElementProcessor.java index c30b7b02b..faacb2245 100644 --- a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/DataElementProcessor.java +++ b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/DataElementProcessor.java @@ -135,7 +135,7 @@ public boolean process(final Set annotations, final Round // Check if Persistence should be generated. if (dataElement.hasAnnotation(Persisted.class)) { String collectionName = getCollectionName(dataElement); - writePersistence(dataElement, collectionName); + writePersistence(dataElement, collectionName, fields); } } catch (final IOException | UnexpectedValueError | InvalidDataElementRoot e) { messager.printMessage(Diagnostic.Kind.ERROR, stackTraceToString(e)); @@ -265,7 +265,11 @@ private void writeClass(DataElementRoot element, final List fields) throw * @param fields the fields extracted from DataField annotations on interface * @throws IOException */ - private void writePersistence(DataElementRoot element, final String collectionName) throws IOException { + private void writePersistence( + DataElementRoot element, + final String collectionName, + List fields + ) throws IOException { // Prepare context of template final VelocityContext context = new VelocityContext(); context.put( @@ -288,6 +292,10 @@ private void writePersistence(DataElementRoot element, final String collectionNa PersistenceHandlerTemplateProperty.IMPLEMENTATION.getKey(), element.getImplName() ); + context.put( + PersistenceHandlerTemplateProperty.FIELDS.getKey(), + fields + ); // Write to file final JavaFileObject generatedClassFile = processingEnv.getFiler() diff --git a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/DefaultFields.java b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/DefaultFields.java index e440fe8d6..a7aa9f32d 100644 --- a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/DefaultFields.java +++ b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/DefaultFields.java @@ -29,6 +29,7 @@ public class DefaultFields { .getter(true) .build() ) + .defaultField(true) .build(); /** @@ -39,6 +40,7 @@ public class DefaultFields { .type(long.class) .docString("A unique identifier for this element.") .defaultValue(0L) + .defaultField(true) .build(); /** @@ -49,6 +51,7 @@ public class DefaultFields { .type(String.class) .docString("A simple name for the data.") .defaultValue("name") + .defaultField(true) .build(); /** @@ -59,6 +62,7 @@ public class DefaultFields { .type(String.class) .docString("A simple description of the data") .defaultValue("description") + .defaultField(true) .build(); /** @@ -69,6 +73,7 @@ public class DefaultFields { .type(String.class) .docString("A comment that annotates the data in a meaningful way.") .defaultValue("no comment") + .defaultField(true) .build(); /** @@ -79,6 +84,7 @@ public class DefaultFields { .type(String.class) .docString("The context (a tag) in which the data should be considered.") .defaultValue("default") + .defaultField(true) .build(); /** @@ -89,6 +95,7 @@ public class DefaultFields { .type(boolean.class) .docString("This value is true if the element should be regarded by the client as required.") .defaultValue(false) + .defaultField(true) .build(); /** @@ -100,6 +107,7 @@ public class DefaultFields { .type(boolean.class) .docString("This value is true if the element should be regarded as a secret by the client, such as for passwords.") .defaultValue(false) + .defaultField(true) .build(); /** @@ -110,6 +118,8 @@ public class DefaultFields { .type(Field.raw("JavascriptValidator<$class>")) .docString("The validator used to check the correctness of the data.") .nullable(true) + .defaultField(true) + .search(false) .build(); /** diff --git a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/Field.java b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/Field.java index 31c0306ad..36a0cce85 100644 --- a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/Field.java +++ b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/Field.java @@ -4,8 +4,10 @@ import java.util.List; import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; @@ -75,6 +77,17 @@ public class Field { */ @Builder.Default boolean setter = true; + /** + * Whether this field is considered a "default" or included in all + * DataElements. + */ + boolean defaultField; + + /** + * Whether this field should be searchable with PersistenceHandler. + */ + @Builder.Default boolean search = true; + /** * A list of alternate names for this field. */ @@ -110,6 +123,15 @@ private static Class getClassOrNull(String cls) { } } + /** + * Return this Fields name ready for use in a method. + * @return capitalized name + */ + @JsonIgnore + public String getNameForMethod() { + return StringUtils.capitalize(this.name); + } + /** * Reverse the escaping performed on defaultValues when the type of the field is * a String. This is only used when serializing to JSON and will render a string @@ -118,6 +140,9 @@ private static Class getClassOrNull(String cls) { */ @JsonProperty("defaultValue") public String unescapeDefaultValue() { + if (this.type == null) { + return this.defaultValue; + } Class cls = getClassOrNull(this.type); if (this.defaultValue != null && cls != null && cls.equals(String.class)) { return this.defaultValue.substring(1, this.defaultValue.length() - 1); @@ -249,6 +274,9 @@ public FieldBuilder jsonName(String name) { */ @JsonAlias({"fieldType"}) public FieldBuilder jsonType(String type) { + if (type == null) { + return this; + } Class cls = getClassOrNull(type); if (cls == null) { cls = getClassOrNull("java.lang." + type); @@ -273,6 +301,9 @@ public FieldBuilder jsonType(String type) { * @return builder */ public FieldBuilder jsonDefaultValue(String defaultValue) { + if (defaultValue == null) { + return this; + } this.defaultValue(raw(defaultValue)); if (shouldEscapeDefaultValue()) { this.defaultValue(defaultValue); @@ -334,5 +365,23 @@ public FieldBuilder jsonGetter(boolean getter) { public FieldBuilder jsonSetter(boolean setter) { return this.setter(setter); } + + /** + * DefaultField builder for use in Deserialization. + * @param defaultField + * @return + */ + public FieldBuilder jsonDefaultField(boolean defaultField) { + return this.defaultField(defaultField); + } + + /** + * Search builder for use in Deserialization. + * @param search + * @return + */ + public FieldBuilder jsonSearch(boolean search) { + return this.search(search); + } } } diff --git a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/PersistenceHandlerTemplateProperty.java b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/PersistenceHandlerTemplateProperty.java index 53cf3d3ac..53e51835f 100644 --- a/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/PersistenceHandlerTemplateProperty.java +++ b/org.eclipse.ice.dev.annotations/src/main/java/org/eclipse/ice/dev/annotations/processors/PersistenceHandlerTemplateProperty.java @@ -13,7 +13,8 @@ enum PersistenceHandlerTemplateProperty { ELEMENT_INTERFACE("elementInterface"), CLASS("class"), COLLECTION("collection"), - IMPLEMENTATION("implementation"); + IMPLEMENTATION("implementation"), + FIELDS("fields"); @Getter private String key; } \ No newline at end of file diff --git a/org.eclipse.ice.dev.annotations/src/main/resources/templates/PersistenceHandler.vm b/org.eclipse.ice.dev.annotations/src/main/resources/templates/PersistenceHandler.vm index 1ef60aee9..8c065cf23 100644 --- a/org.eclipse.ice.dev.annotations/src/main/resources/templates/PersistenceHandler.vm +++ b/org.eclipse.ice.dev.annotations/src/main/resources/templates/PersistenceHandler.vm @@ -55,57 +55,26 @@ public class $class implements $interface { return (T) element; } - @Override - public Iterable findById(long id) throws Exception { - return this.collection.find(Filters.eq("id", id)) - .map(doc -> new ${implementation}().fromJSON(doc)); - } - - @Override - public Iterable findByName(String name) throws Exception { - return this.collection.find(Filters.eq("name", name)) - .map(doc -> new ${implementation}().fromJSON(doc)); - } - - @Override - public Iterable findByDescription(String description) throws Exception { - return this.collection.find(Filters.eq("description", description)) - .map(doc -> new ${implementation}().fromJSON(doc)); - } - - @Override - public Iterable findByComment(String comment) throws Exception { - return this.collection.find(Filters.eq("comment", comment)) - .map(doc -> new ${implementation}().fromJSON(doc)); - } - - @Override - public Iterable findByContext(String context) throws Exception { - return this.collection.find(Filters.eq("context", context)) - .map(doc -> new ${implementation}().fromJSON(doc)); - } - - @Override - public Iterable findRequired() throws Exception { - return this.collection.find(Filters.eq("required", true)) - .map(doc -> new ${implementation}().fromJSON(doc)); - } - - @Override - public Iterable findNotRequired() throws Exception { - return this.collection.find(Filters.eq("required", false)) - .map(doc -> new ${implementation}().fromJSON(doc)); - } + #foreach($field in $fields) + #if(${field.Getter} && ${field.Search}) + /** + * Find $elementInterface by ${field.Name}. + * @param ${field.Name} + * @return Iterator of results + */ + #if(${field.DefaultField}) @Override - public Iterable findSecret() throws Exception { - return this.collection.find(Filters.eq("secret", true)) + #end + public Iterable findBy${field.NameForMethod}(${field.Type} ${field.Name}) throws Exception { + return this.collection.find(Filters.eq("${field.Name}", ${field.Name})) .map(doc -> new ${implementation}().fromJSON(doc)); } + #end + #end @Override - public Iterable findNotSecret() throws Exception { - return this.collection.find(Filters.eq("secret", false)) - .map(doc -> new ${implementation}().fromJSON(doc)); + public long clear() throws Exception { + return this.collection.deleteMany(new Document()).getDeletedCount(); } } \ No newline at end of file diff --git a/org.eclipse.ice.renderer/src/main/java/org/eclipse/ice/renderer/Person.java b/org.eclipse.ice.renderer/src/main/java/org/eclipse/ice/renderer/Person.java index 1e1d1f38d..5dee09a7f 100644 --- a/org.eclipse.ice.renderer/src/main/java/org/eclipse/ice/renderer/Person.java +++ b/org.eclipse.ice.renderer/src/main/java/org/eclipse/ice/renderer/Person.java @@ -2,11 +2,14 @@ import org.eclipse.ice.dev.annotations.DataElement; import org.eclipse.ice.dev.annotations.DataField; +import org.eclipse.ice.dev.annotations.IDataElement; +import org.eclipse.ice.dev.annotations.Persisted; @DataElement @DataField(fieldName = "age", fieldType = int.class, docString = "The age of the person.") @DataField(fieldName = "firstName", fieldType = String.class, docString = "The first name of the person.") @DataField(fieldName = "lastName", fieldType = String.class, docString = "The last name of the Person.") -public interface Person { +@Persisted(collection = "people") +public interface Person extends IDataElement { //void foo(); }