From 26b01b500065634eb3133dc354a0ba71b13bff56 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 7 Aug 2013 23:53:53 +0200 Subject: wip o Start of JPA implementation. --- .../trygvis/container/compiler/EntityHandler.java | 183 +++++++++++---------- .../io/trygvis/container/compiler/MyProcessor.java | 10 +- .../trygvis/container/compiler/SqlUnitModel.java | 9 + .../container/compiler/TransactionalHandler.java | 5 +- .../java/io/trygvis/container/compiler/Utils.java | 46 +++++- .../trygvis/container/compiler/model/ClassG.java | 34 +++- .../container/compiler/model/Constructor.java | 11 +- .../container/compiler/model/MethodRef.java | 17 ++ .../trygvis/container/compiler/model/TypeRef.java | 21 ++- .../java/io/trygvis/persistence/EntityMirror.java | 75 +++++++-- .../java/io/trygvis/persistence/SqlEntitySet.java | 1 + .../generators/EntityManagerFactoryGenerator.java | 69 ++++++++ .../generators/EntityManagerGenerator.java | 129 +++++++++++++++ .../persistence/generators/SequencesGenerator.java | 41 +++++ 14 files changed, 525 insertions(+), 126 deletions(-) create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/EntityManagerFactoryGenerator.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/EntityManagerGenerator.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SequencesGenerator.java (limited to 'container-compiler-plugin/src/main/java') diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/EntityHandler.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/EntityHandler.java index 74f303f..9bce51e 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/EntityHandler.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/EntityHandler.java @@ -1,15 +1,20 @@ package io.trygvis.container.compiler; import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.Constructor; import io.trygvis.container.compiler.model.FieldRef; +import io.trygvis.container.compiler.model.MethodRef; +import io.trygvis.container.compiler.model.Parameters; import io.trygvis.container.compiler.model.TypeRef; import io.trygvis.persistence.EntityMirror; import io.trygvis.persistence.FieldMirror; import io.trygvis.persistence.GeneratorConfiguration; import io.trygvis.persistence.SequenceMirror; import io.trygvis.persistence.SqlEntity; +import io.trygvis.persistence.SqlEntitySet; import io.trygvis.persistence.TypeHandler; -import io.trygvis.persistence.sql.SqlEntityDesc; +import io.trygvis.persistence.sql.SqlDao; +import io.trygvis.persistence.sql.SqlEntityMeta; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; @@ -25,9 +30,10 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.persistence.Id; import javax.persistence.SequenceGenerator; -import javax.tools.JavaFileObject; import java.io.IOException; -import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -35,8 +41,9 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; -import static io.trygvis.container.compiler.Utils.toFieldName; -import static io.trygvis.container.compiler.Utils.toJavaString; +import static io.trygvis.container.compiler.Utils.*; +import static io.trygvis.container.compiler.model.Parameters.ParameterRef; +import static io.trygvis.container.compiler.model.TypeRef.VOID; import static io.trygvis.persistence.FieldMirror.AccessorType.FIELD; import static io.trygvis.persistence.FieldMirror.AccessorType.METHOD; import static io.trygvis.persistence.FieldMirror.FieldType.PRIMITIVE; @@ -47,15 +54,15 @@ import static java.lang.String.format; import static java.lang.reflect.Modifier.PUBLIC; import static javax.lang.model.util.ElementFilter.fieldsIn; import static javax.lang.model.util.ElementFilter.methodsIn; -import static org.apache.commons.lang.StringUtils.*; +import static org.apache.commons.lang.StringUtils.join; public class EntityHandler extends AbstractHandler { private GeneratorConfiguration generatorConfiguration = new GeneratorConfiguration(); - private SqlUnitModel sqlUnit = new SqlUnitModel(); - private PackageElement packageElement; + private SqlUnitModel sqlUnit; - public EntityHandler(ProcessingEnvironment processingEnv) { + public EntityHandler(ProcessingEnvironment processingEnv, SqlUnitModel sqlUnit) { super(processingEnv); + this.sqlUnit = sqlUnit; } public void phase1(Set sqlEntities, Set packages) throws Exception { @@ -81,11 +88,22 @@ public class EntityHandler extends AbstractHandler { if (packages.size() == 0) { throw new CompilerException("There has to be exactly one @SqlEntitySet annotated package."); } - packageElement = packages.iterator().next(); + PackageElement packageElement = packages.iterator().next(); if (packages.size() != 1) { throw new CompilerException(packageElement, "There can only be one @SqlEntitySet annotated package."); } + AnnotationMirror sqlEntitySet = getAnnotation(SqlEntitySet.class, packageElement); + String name = null; + for (Map.Entry v : sqlEntitySet.getElementValues().entrySet()) { + String field = v.getKey().getSimpleName().toString(); + String value = v.getValue().getValue().toString(); + switch (field) { + case "name": + name = value; + } + } + sqlUnit.setName(name); sqlUnit.setPackageName(packageElement.getQualifiedName().toString()); } @@ -178,6 +196,7 @@ public class EntityHandler extends AbstractHandler { if (idFields.size() != 1) { throw new CompilerException(element, "This implementation only support a single @Id annotated field."); } + entity.setIdType(idFields.get(0).type); sqlUnit.add(entity, element); } @@ -193,18 +212,19 @@ public class EntityHandler extends AbstractHandler { for (Map.Entry v : sequenceGenerator.getElementValues().entrySet()) { String field = v.getKey().getSimpleName().toString(); + String value = v.getValue().getValue().toString(); switch (field) { case "name": - name = v.getValue().getValue().toString(); + name = value; break; case "sequenceName": - sequenceName = v.getValue().getValue().toString(); + sequenceName = value; break; case "initialValue": - initialValue = Integer.valueOf(v.getValue().getValue().toString()); + initialValue = Integer.valueOf(value); break; case "allocationSize": - allocationSize = Integer.valueOf(v.getValue().getValue().toString()); + allocationSize = Integer.valueOf(value); break; default: throw new InternalErrorException("Unsupported field on @SequenceGenerator: " + field); @@ -218,30 +238,83 @@ public class EntityHandler extends AbstractHandler { } public ClassG phase3(EntityMirror entityMirror) throws IOException { - ClassG g = new ClassG(PUBLIC, entityMirror.daoType); + ClassG g = new ClassG(PUBLIC, entityMirror.daoType). + extendsType(new TypeRef(SqlDao.class).args(entityMirror.idType, entityMirror.type)); + Parameters p = new Parameters(); + ParameterRef c = p.addParameter(new TypeRef(Connection.class), "c"); + g.add(new Constructor(p, "super(" + c.name + ");")); TypeRef stringType = g.imports.add(String.class); - TypeRef sqlEntityDescType = g.imports.add(SqlEntityDesc.class); + TypeRef sqlEntityDescType = g.imports.add(SqlEntityMeta.class); + TypeRef sqlException = g.imports.add(SQLException.class); - g.addPublicStaticFinalField(stringType, "createTableSql"). + FieldRef createTableSql = g.addPublicStaticFinalField(stringType, "createTableSql"). value(toJavaString(entityMirror.createTableSql(sqlUnit))); - g.addPublicStaticFinalField(stringType, "dropTableSql"). + g.add(new MethodRef(PUBLIC, stringType, "createTableSql", "return createTableSql;")); + FieldRef dropTableSql = g.addPublicStaticFinalField(stringType, "dropTableSql"). value(toJavaString(entityMirror.dropTableSql())); + g.add(new MethodRef(PUBLIC, stringType, "dropTableSql", "return dropTableSql;")); g.addPublicStaticFinalField(stringType, "insertIntoSql"). value(toJavaString(entityMirror.insertIntoSql(sqlUnit))); g.addPublicStaticFinalField(stringType, "deleteFromSql"). value(toJavaString(entityMirror.deleteFromSql())); String desc = "new " + sqlEntityDescType + "(" + toJavaString(entityMirror.tableName) + ", " + - toJavaString(entityMirror.defaultFields()) + + toJavaString(entityMirror.defaultFields()) + ", " + + toJavaString(createTableSql.name) + ", " + + toJavaString(dropTableSql.name) + ")"; g.addPublicStaticFinalField(sqlEntityDescType, "desc").value(desc); ClassG.InnerClassG typedQuery = g.addInnerClass(entityMirror.queryType(g.imports)); - typedQuery.inner.addMethod(entityMirror.fromResultSet(g.imports)); - g.addMethod(entityMirror.insertInto(sqlUnit, g.imports)); - g.addMethod(entityMirror.delete(g.imports)); - g.addMethod(entityMirror.deleteById(g.imports)); - g.addMethod(entityMirror.query(g.imports)); + g.addInnerClass(entityMirror.utils(sqlUnit)); + + { + p = new Parameters(); + ParameterRef rs = p.addParameter(new TypeRef(ResultSet.class), "rs"); + g.add(new MethodRef(PUBLIC, entityMirror.type, "fromResultSet", p, + "return Utils.fromResultSet" + entityMirror.type.className + "(" + rs.name + ");"). + exception(sqlException)); + } + + { + p = new Parameters(); + ParameterRef entity = p.addParameter(entityMirror.type, "entity"); + g.add(new MethodRef(PUBLIC, VOID, "insert", p, + "Utils.insert" + entityMirror.type.className + "(super.c, " + entity.name + ");"). + exception(sqlException)); + } + + { + p = new Parameters(); + ParameterRef id = p.addParameter(entityMirror.idType, "id"); + g.add(new MethodRef(PUBLIC, entityMirror.type, "selectById", p, + "return Utils.select" + entityMirror.type.className + "ById(super.c, " + id.name + ");"). + exception(sqlException)); + } + + { + p = new Parameters(); + ParameterRef entity = p.addParameter(entityMirror.type, "entity"); + g.add(new MethodRef(PUBLIC, VOID, "delete", p, + "Utils.delete" + entityMirror.type.className + "(super.c, " + entity.name + ");"). + exception(sqlException)); + } + + { + p = new Parameters(); + ParameterRef id = p.addParameter(entityMirror.idType, "id"); + g.add(new MethodRef(PUBLIC, VOID, "deleteById", p, + "Utils.delete" + entityMirror.type.className + "ById(super.c, " + id.name + ");"). + exception(sqlException)); + } + + { + p = new Parameters(); + ParameterRef entity = p.addParameter(entityMirror.type, "entity"); + g.add(new MethodRef(PUBLIC, VOID, "update", p, + "Utils.update" + entityMirror.type.className + "(super.c, " + entity.name + ");"). + exception(sqlException)); + } return g; } @@ -328,10 +401,8 @@ public class EntityHandler extends AbstractHandler { public void phase3(boolean errorRaised) throws Exception { try { for (EntityMirror entity : sqlUnit.getEntities().values()) { - writeFile(phase3(entity), sqlUnit.element(entity)); + writeFile(processingEnv, phase3(entity), sqlUnit.element(entity)); } - writeFile(generateSequences(sqlUnit), null); - writeFile(generateSession(), null); } catch (CompilerException | InternalErrorException e) { // Ignore any exceptions if we had an error from before if (errorRaised) { @@ -341,62 +412,6 @@ public class EntityHandler extends AbstractHandler { } } - private ClassG generateSequences(SqlUnitModel unit) { - TypeRef sequences = new TypeRef(unit.getPackageName() + ".Sequences"); - ClassG g = new ClassG(PUBLIC, sequences); - List creates = new ArrayList<>(); - List drops = new ArrayList<>(); - for (SequenceMirror sequence : unit.getSequences().values()) { - TypeRef stringType = g.imports.add(String.class); - String value = "CREATE SEQUENCE " + sequence.sequenceName + ";"; - FieldRef f = g.addPublicStaticFinalField(stringType, "create" + capitalize(sequence.name)). - value(toJavaString(value)); - creates.add(f.name); - - f = g.addPublicStaticFinalField(stringType, "drop" + capitalize(sequence.name)). - value(toJavaString("DROP SEQUENCE " + sequence.sequenceName) + ";"); - drops.add(f.name); - - } - g.addPublicStaticFinalField(new TypeRef(String[].class), "createSequences"). - value("new String[]{" + join(creates, ", ") + "}"); - g.addPublicStaticFinalField(new TypeRef(String[].class), "dropSequences"). - value("new String[]{" + join(drops, ", ") + "}"); - return g; - } - - private void writeFile(ClassG g, Element element) throws IOException { - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(g.type.fqName, element); - try (PrintWriter w = new PrintWriter(sourceFile.openWriter())) { - for (String s : g.generate()) { - w.println(stripEnd(s, " ")); - } - } - } - - private ClassG generateSession() throws IOException { - String p = packageElement.getQualifiedName().toString(); - - // TODO: Support a name prefix from @SqlEntitySet - TypeRef type = new TypeRef(p + ".Session"); - -/* - TypeRef conType = g.add(Connection.class); - Parameters parameters = new Parameters(); - ParameterRef c = parameters.addParameter(conType, "c"); - - List body = new ArrayList<>(); - for (EntityMirror entity : entities) { - FieldRef fieldRef = g.addField(entity.javaName.asElement().asType(), toFieldName(entity.daoName)); - body.add("this." + fieldRef.name + " = new " + entity.daoName + "(" + c.name + ");"); - } - - g.addConstructor(parameters, body); -*/ - - return new ClassG(PUBLIC, type); - } - public static String sqlName(String javaName) { StringBuilder builder = new StringBuilder(); for (char c : javaName.toCharArray()) { @@ -420,7 +435,7 @@ public class EntityHandler extends AbstractHandler { return null; } - public AnnotationMirror getAnnotation(Class c, TypeElement type) { + public AnnotationMirror getAnnotation(Class c, Element type) { AnnotationMirror annotation = findAnnotation(c, type); if (annotation != null) { diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/MyProcessor.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/MyProcessor.java index fbbc56d..64ac678 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/MyProcessor.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/MyProcessor.java @@ -25,6 +25,10 @@ import javax.tools.Diagnostic; import java.util.HashSet; import java.util.Set; +import static io.trygvis.container.compiler.Utils.writeFile; +import static io.trygvis.persistence.generators.EntityManagerGenerator.generateEntityManager; +import static io.trygvis.persistence.generators.EntityManagerFactoryGenerator.generateEntityManagerFactory; +import static io.trygvis.persistence.generators.SequencesGenerator.generateSequences; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; @@ -104,7 +108,8 @@ public class MyProcessor implements Processor { TypeElement log = elements.getTypeElement(Log.class.getCanonicalName()); TypeElement entity = elements.getTypeElement(Entity.class.getCanonicalName()); - EntityHandler entityHandler = new EntityHandler(processingEnv); + SqlUnitModel unit = new SqlUnitModel(); + EntityHandler entityHandler = new EntityHandler(processingEnv, unit); Set sqlEntities = typesIn(roundEnv.getElementsAnnotatedWith(SqlEntity.class)); Set packages = ElementFilter.packagesIn(roundEnv.getElementsAnnotatedWith(SqlEntitySet.class)); @@ -136,6 +141,9 @@ public class MyProcessor implements Processor { } entityHandler.phase3(hadErrors); + writeFile(processingEnv, generateSequences(unit), null); + writeFile(processingEnv, generateEntityManagerFactory(unit), null); + writeFile(processingEnv, generateEntityManager(unit), null); return true; } diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/SqlUnitModel.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/SqlUnitModel.java index 1bd2535..e41fbb8 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/SqlUnitModel.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/SqlUnitModel.java @@ -14,6 +14,7 @@ public class SqlUnitModel { private Map sequences = new TreeMap<>(); private Map sequenceElements = new TreeMap<>(); private String packageName; + private String name; public String getPackageName() { if (packageName == null) { @@ -27,6 +28,14 @@ public class SqlUnitModel { this.packageName = packageName; } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + // ----------------------------------------------------------------------- // Entity Mirrors // ----------------------------------------------------------------------- diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java index b5db075..bfa1ec8 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java @@ -1,6 +1,7 @@ package io.trygvis.container.compiler; import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.Constructor; import io.trygvis.container.compiler.model.FieldRef; import io.trygvis.container.compiler.model.MethodRef; import io.trygvis.container.compiler.model.Parameters; @@ -109,7 +110,7 @@ public class TransactionalHandler extends AbstractHandler { body.add(" });"); MethodRef m = new MethodRef(PUBLIC, returnType, ee.getSimpleName().toString(), parameters, body); - g.addMethod(m); + g.add(m); } JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile((p.length() == 0 ? "" : p + ".") + className, element); @@ -137,6 +138,6 @@ public class TransactionalHandler extends AbstractHandler { List body = new ArrayList<>(); body.add("super(" + collectionToDelimitedString(goesToSuper, ", ") + ");"); body.add("this." + platformTransactionManager.name + " = " + transactionManager.name + ";"); - g.addConstructor(parameters, body); + g.add(new Constructor(parameters, body)); } } diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/Utils.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/Utils.java index 8bb1b33..5d69fc0 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/Utils.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/Utils.java @@ -1,13 +1,29 @@ package io.trygvis.container.compiler; +import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.Imports; +import io.trygvis.container.compiler.model.TypeRef; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.persistence.PersistenceException; +import javax.tools.JavaFileObject; import java.io.BufferedReader; import java.io.IOException; +import java.io.PrintWriter; import java.io.StringReader; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import static io.trygvis.container.compiler.model.ClassG.addAll; import static java.lang.Character.toLowerCase; import static java.lang.Character.toUpperCase; +import static org.apache.commons.lang.StringUtils.stripEnd; public class Utils { + public static final String EOL = System.getProperty("line.separator"); + public static String toFieldName(String s) { if (s.length() < 1) { return s.toLowerCase(); @@ -40,6 +56,11 @@ public class Utils { return new String(chars, 0, j); } + public static String toClassName(String s) { + s = toFieldName(s); + return toUpperCase(s.charAt(0)) + s.substring(1, s.length()); + } + public static String toSetterName(String s) { s = toFieldName(s); return "set" + toUpperCase(s.charAt(0)) + s.substring(1, s.length()); @@ -60,8 +81,8 @@ public class Utils { buffer.append(line.replace("\"", "\\\"")); buffer.append('"'); line = reader.readLine(); - if(line != null) { - buffer.append(" +\n"); + if (line != null) { + buffer.append(" +").append(EOL); } } @@ -70,4 +91,25 @@ public class Utils { throw new RuntimeException(e); } } + + public static void writeFile(ProcessingEnvironment processingEnv, ClassG g, Element element) throws IOException { + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(g.type.fqName, element); + try (PrintWriter w = new PrintWriter(sourceFile.openWriter())) { + for (String s : g.generate()) { + w.println(stripEnd(s, " ")); + } + } + } + + public static List tryCatchSqlException(Imports imports, List body) { + TypeRef sqlException = imports.add(SQLException.class); + TypeRef persistenceException = imports.add(PersistenceException.class); + List newBody = new ArrayList<>(); + newBody.add("try {"); + addAll(1, newBody, body); + newBody.add("} catch (" + sqlException.plainName + " e) {"); + newBody.add(" throw new " + persistenceException.plainName + "(e);"); // TODO: Add context info. + newBody.add("}"); + return newBody; + } } diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/ClassG.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/ClassG.java index c99feae..402498c 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/ClassG.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/ClassG.java @@ -45,7 +45,12 @@ public class ClassG { } public ClassG extendsType(TypeRef extendsType) { - this.extendsType = extendsType; + this.extendsType = imports.add(extendsType); + return this; + } + + public ClassG extendsType(Class extendsType) { + this.extendsType = imports.add(extendsType); return this; } @@ -54,6 +59,13 @@ public class ClassG { return this; } + public ClassG implementsType(Class... implementsTypes) { + for (Class type : implementsTypes) { + this.implementsTypes.add(imports.add(type)); + } + return this; + } + public FieldRef addField(TypeMirror klass, String name) { TypeRef type = imports.add(klass); FieldRef ref = new FieldRef(PRIVATE | FINAL, type, name); @@ -80,18 +92,17 @@ public class ClassG { return addField(PUBLIC | STATIC | FINAL, type, name); } - public Constructor addConstructor(Parameters parameters, List body) { - Constructor constructor = new Constructor(this, parameters, body); + public ClassG add(Constructor constructor) { constructors.add(constructor); - return constructor; + return this; } - public ClassG addMethod(MethodRef methodRef) { + public ClassG add(MethodRef methodRef) { this.methods.add(methodRef); return this; } -// public MethodRef addMethod(List body, TypeRef returnType, String name, Parameters parameters) { +// public MethodRef add(List body, TypeRef returnType, String name, Parameters parameters) { // MethodRef ref = new MethodRef(PUBLIC, returnType, name, parameters, body); // methods.add(ref); // return ref; @@ -145,7 +156,7 @@ public class ClassG { for (Constructor constructor : constructors) { body.add(""); - addAll(1, body, constructor.write()); + addAll(1, body, constructor.write(this)); } for (MethodRef method : methods) { @@ -165,7 +176,11 @@ public class ClassG { } private List write(MethodRef method) { - List body = new ArrayList<>(); + String typeArgs = ""; + if (!method.typeArgs.isEmpty()) { + typeArgs = "<" + join(method.typeArgs, ", ") + "> "; + } + String returnString; if (method.returnType == TypeRef.VOID) { returnString = "void"; @@ -178,9 +193,10 @@ public class ClassG { parameters.add("final " + p.klass + " " + p.name); } - String m = Modifier.toString(method.modifiers) + " " + + String m = Modifier.toString(method.modifiers) + " " + typeArgs + returnString + " " + method.name + "(" + collectionToDelimitedString(parameters, ", ") + ")"; + List body = new ArrayList<>(); if (method.exceptions.isEmpty()) { body.add(m + " {"); } else { diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Constructor.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Constructor.java index 0f3ceeb..f701476 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Constructor.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Constructor.java @@ -4,21 +4,24 @@ import java.util.ArrayList; import java.util.List; import static io.trygvis.container.compiler.model.ClassG.addAll; +import static java.util.Arrays.asList; import static org.apache.commons.lang.StringUtils.join; public class Constructor { - private final ClassG g; private final Parameters parameters; private final List body; - public Constructor(ClassG g, Parameters parameters, List body) { - this.g = g; + public Constructor(Parameters parameters, String... body) { + this(parameters, asList(body)); + } + + public Constructor(Parameters parameters, List body) { this.parameters = parameters; this.body = body; } - public List write() { + public List write(ClassG g) { List ps = new ArrayList<>(); for (Parameters.ParameterRef p : parameters) { ps.add(p.klass + " " + p.name); diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/MethodRef.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/MethodRef.java index 902d25a..952a1e5 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/MethodRef.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/MethodRef.java @@ -1,11 +1,14 @@ package io.trygvis.container.compiler.model; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; +import static java.util.Arrays.asList; import static java.util.Collections.addAll; +import static java.util.Collections.singletonList; public class MethodRef { public final TypeRef returnType; @@ -13,8 +16,17 @@ public class MethodRef { public final int modifiers; public final Parameters parameters; public final Set exceptions = new TreeSet<>(); + public final List typeArgs = new ArrayList<>(); public final List body; + public MethodRef(int modifiers, TypeRef returnType, String name, String body) { + this(modifiers, returnType, name, new Parameters(), singletonList(body)); + } + + public MethodRef(int modifiers, TypeRef returnType, String name, Parameters p, String... body) { + this(modifiers, returnType, name, p, asList(body)); + } + public MethodRef(int modifiers, TypeRef returnType, String name, Parameters parameters, List body) { this.modifiers = modifiers; this.returnType = returnType; @@ -31,4 +43,9 @@ public class MethodRef { addAll(this.exceptions, exceptions); return this; } + + public MethodRef typeArgs(String... args) { + addAll(typeArgs, args); + return this; + } } diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/TypeRef.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/TypeRef.java index 2e679a5..c329ab3 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/TypeRef.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/TypeRef.java @@ -2,6 +2,7 @@ package io.trygvis.container.compiler.model; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -39,9 +40,9 @@ public class TypeRef implements Comparable { public final boolean array; - public final List args; + public final List args; - private TypeRef(String fqName, String name, boolean primitive, boolean array, List args) { + private TypeRef(String fqName, String name, boolean primitive, boolean array, List args) { this.fqName = fqName; this.plainName = name; this.primitive = primitive; @@ -61,7 +62,7 @@ public class TypeRef implements Comparable { } public TypeRef(Class klass) { - this(fqName(klass), fqName(klass), false, klass.isArray(), Collections.emptyList()); + this(fqName(klass), fqName(klass), false, klass.isArray(), Collections.emptyList()); } private static String fqName(Class klass) { @@ -74,14 +75,14 @@ public class TypeRef implements Comparable { } public TypeRef(String fqName) { - this(fqName, fqName, false, false, Collections.emptyList()); + this(fqName, fqName, false, false, Collections.emptyList()); } - public TypeRef(String fqName, String name, boolean array, List args) { + public TypeRef(String fqName, String name, boolean array, List args) { this(fqName, name, false, array, args); } - public TypeRef args(List args) { + public TypeRef args(List args) { return new TypeRef(fqName, plainName, primitive, array, args); } @@ -108,6 +109,14 @@ public class TypeRef implements Comparable { } public TypeRef args(TypeRef... args) { + List list = new ArrayList<>(); + for (TypeRef arg : args) { + list.add(arg.plainName); + } + return args(list); + } + + public TypeRef args(String... args) { return args(asList(args)); } diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/EntityMirror.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/EntityMirror.java index 5d6defb..140a910 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/persistence/EntityMirror.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/EntityMirror.java @@ -3,6 +3,7 @@ package io.trygvis.persistence; import io.trygvis.container.compiler.NotImplementedException; import io.trygvis.container.compiler.SqlUnitModel; import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.Constructor; import io.trygvis.container.compiler.model.Imports; import io.trygvis.container.compiler.model.MethodRef; import io.trygvis.container.compiler.model.Parameters; @@ -38,6 +39,8 @@ public class EntityMirror implements Comparable { public final TypeRef type; public final String tableName; public final TypeRef daoType; + public final TypeRef utilsType; + public TypeRef idType; public EntityMirror(GeneratorConfiguration generatorConfiguration, TypeRef type, String tableName) { this.generatorConfiguration = generatorConfiguration; @@ -45,6 +48,7 @@ public class EntityMirror implements Comparable { this.tableName = tableName; this.daoType = new TypeRef(type.plainName + "Dao").args(type.args); + this.utilsType = new TypeRef(type.plainName + ".Utils").args(type.args); } public void add(FieldMirror... fields) { @@ -57,6 +61,10 @@ public class EntityMirror implements Comparable { } } + public void setIdType(TypeRef idType) { + this.idType = idType; + } + public FieldMirror getIdField() { return idFields.get(0); } @@ -180,7 +188,7 @@ public class EntityMirror implements Comparable { body.add(setter); } else { body.add(" " + field.type + " " + field.javaName + " = " + accessor + ";"); - body.add(" if(" + field.javaName + " == null) {"); + body.add(" if (" + field.javaName + " == null) {"); body.add(" stmt.setNull(" + i + ", " + typesType + "." + typeHandler.typeName() + ");"); body.add(" } else {"); body.add(" " + setter); @@ -189,7 +197,23 @@ public class EntityMirror implements Comparable { } body.add(" stmt.executeUpdate();"); body.add("}"); - return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "insertInto", p, body).exception(sqlExceptionType); + return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "insert" + type.className, p, body).exception(sqlExceptionType); + } + + public MethodRef selectById(Imports imports) { + Parameters p = new Parameters(); + p.addParameter(imports.add(Connection.class), "c"); + p.addParameter(idType, "id"); + return new MethodRef(PUBLIC | STATIC, type, "select" + type.className + "ById", p, + "throw new UnsupportedOperationException(\"Not implemented\");"); + } + + public MethodRef update(Imports imports) { + Parameters p = new Parameters(); + p.addParameter(imports.add(Connection.class), "c"); + p.addParameter(type, "entity"); + return new MethodRef(PUBLIC | STATIC, type, "update" + type.className, p, + "throw new UnsupportedOperationException(\"Not implemented\");"); } public MethodRef delete(Imports imports) { @@ -208,11 +232,9 @@ public class EntityMirror implements Comparable { arguments.add(o.name + "." + toGetterName(field.javaName) + "()"); } } - List body = new ArrayList<>(); - body.add("deleteById(" + join(arguments, ", ") + ");"); - return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "delete", p, body). - exception(imports.add(SQLException.class)); + return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "delete" + type.className, p, + "delete" + type.className + "ById(" + join(arguments, ", ") + ");").exception(imports.add(SQLException.class)); } public MethodRef deleteById(Imports imports) { @@ -233,22 +255,29 @@ public class EntityMirror implements Comparable { body.add(" stmt.executeUpdate();"); body.add("}"); - return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "deleteById", p, body). + return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "delete" + type.className + "ById", p, body). exception(imports.add(SQLException.class)); } public ClassG queryType(Imports imports) { - TypeRef abstractQueryType = imports.add(AbstractTypedQuery.class).args(type); + TypeRef sqlQueryType = imports.add(AbstractTypedQuery.class).args(type); TypeRef conType = imports.add(Connection.class); TypeRef entityTypedQuery = new TypeRef(type.className + "TypedQuery"); + TypeRef sqlExceptionType = new TypeRef(SQLException.class); Parameters p = new Parameters(); ParameterRef c = p.addParameter(conType, "c"); - - ClassG typedQuery = new ClassG(PUBLIC | STATIC, entityTypedQuery). - extendsType(abstractQueryType); - typedQuery.addConstructor(p, singletonList("super(" + c.name + ", " + daoType.className + ".desc);")); - return typedQuery; + Constructor constructor = new Constructor(p, singletonList("super(" + c.name + ", " + daoType.className + ".desc);")); + ClassG g = new ClassG(PUBLIC | STATIC, entityTypedQuery). + extendsType(sqlQueryType). + add(constructor); + p = new Parameters(); + ParameterRef rs = p.addParameter(new TypeRef(ResultSet.class), "rs"); + MethodRef fromResultSet = new MethodRef(PUBLIC, type, "fromResultSet", p, + "return " + utilsType.className + ".fromResultSet" + type.className + "(" + rs.name + ");"). + exception(sqlExceptionType); + g.add(fromResultSet); + return g; } public MethodRef query(Imports imports) { @@ -258,10 +287,8 @@ public class EntityMirror implements Comparable { Parameters p = new Parameters(); ParameterRef c = p.addParameter(conType, "c"); - - List body = new ArrayList<>(); - body.add("return new " + entityTypedQuery + "(" + c.name + ");"); - return new MethodRef(PUBLIC | STATIC, typedQueryType, "query", p, body); + return new MethodRef(PUBLIC | STATIC, typedQueryType, "query" + type.className, p, + "return new " + entityTypedQuery + "(" + c.name + ");"); } public MethodRef fromResultSet(Imports g) { @@ -313,7 +340,7 @@ public class EntityMirror implements Comparable { body.add("return returnValue;"); - return new MethodRef(PUBLIC, type, "fromResultSet", p, body). + return new MethodRef(PUBLIC | STATIC, type, "fromResultSet" + type.className, p, body). exception(g.add(SQLException.class)); } @@ -336,4 +363,16 @@ public class EntityMirror implements Comparable { public int compareTo(@SuppressWarnings("NullableProblems") EntityMirror o) { return type.compareTo(o.type); } + + public ClassG utils(SqlUnitModel unit) { + ClassG g = new ClassG(PUBLIC | STATIC, utilsType); + g.add(insertInto(unit, g.imports)); + g.add(selectById(g.imports)); + g.add(update(g.imports)); + g.add(delete(g.imports)); + g.add(deleteById(g.imports)); + g.add(query(g.imports)); + g.add(fromResultSet(g.imports)); + return g; + } } diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/SqlEntitySet.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/SqlEntitySet.java index 69176f8..455e3cd 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/persistence/SqlEntitySet.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/SqlEntitySet.java @@ -1,4 +1,5 @@ package io.trygvis.persistence; public @interface SqlEntitySet { + String name(); } diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/EntityManagerFactoryGenerator.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/EntityManagerFactoryGenerator.java new file mode 100644 index 0000000..82e69e3 --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/EntityManagerFactoryGenerator.java @@ -0,0 +1,69 @@ +package io.trygvis.persistence.generators; + +import io.trygvis.container.compiler.SqlUnitModel; +import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.Constructor; +import io.trygvis.container.compiler.model.FieldRef; +import io.trygvis.container.compiler.model.Imports; +import io.trygvis.container.compiler.model.MethodRef; +import io.trygvis.container.compiler.model.Parameters; +import io.trygvis.container.compiler.model.TypeRef; +import io.trygvis.persistence.EntityMirror; +import io.trygvis.persistence.sql.SqlEntityManagerFactory; +import io.trygvis.persistence.sql.SqlEntityMeta; +import io.trygvis.persistence.sql.SqlUnit; + +import javax.persistence.EntityManager; +import javax.sql.DataSource; +import java.io.IOException; +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; + +import static io.trygvis.container.compiler.Utils.toClassName; +import static java.lang.reflect.Modifier.*; +import static org.apache.commons.lang.StringUtils.join; + +public class EntityManagerFactoryGenerator { + public static ClassG generateEntityManagerFactory(SqlUnitModel unit) throws IOException { + String prefix = unit.getPackageName() + "." + toClassName(unit.getName()); + TypeRef emfType = new TypeRef(prefix + "EntityManagerFactory"); + + ClassG g = new ClassG(PUBLIC, emfType). + extendsType(SqlEntityManagerFactory.class); + + List s = new ArrayList<>(); + for (EntityMirror entity : unit.getEntities().values()) { + s.add(entity.daoType.plainName + ".desc"); + } + TypeRef sqlEntityMetaArrayType = new TypeRef(SqlEntityMeta[].class); + FieldRef entities = g.addField(PUBLIC | STATIC, sqlEntityMetaArrayType, "entities"). + value("new " + sqlEntityMetaArrayType + "{" + join(s, ", ") + "}"); + + g.add(constructor(entities, g.imports)); + g.add(createEntityManager(unit, g.imports)); + return g; + } + + private static Constructor constructor(FieldRef entities, Imports imports) { + TypeRef dataSourceType = imports.add(DataSource.class); + TypeRef sqlUnitType = imports.add(SqlUnit.class); + Parameters p = new Parameters(); + Parameters.ParameterRef ds = p.addParameter(dataSourceType, "ds"); + ArrayList body = new ArrayList<>(); + body.add("super(new " + sqlUnitType.plainName + "(" + entities.name + "), " + ds.name + ");"); + return new Constructor(p, body); + } + + private static MethodRef createEntityManager(SqlUnitModel unit, Imports imports) { + String prefix = unit.getPackageName() + "." + toClassName(unit.getName()); + TypeRef entityManagerType = imports.add(EntityManager.class); + TypeRef connectionType = imports.add(Connection.class); + TypeRef emType = imports.add(new TypeRef(prefix + "EntityManager")); + + Parameters p = new Parameters(); + Parameters.ParameterRef c = p.addParameter(connectionType, "c"); + return new MethodRef(PROTECTED, entityManagerType, "createEntityManager", p, + "return new " + emType + "(this, " + c.name + ");"); + } +} diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/EntityManagerGenerator.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/EntityManagerGenerator.java new file mode 100644 index 0000000..f524b1a --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/EntityManagerGenerator.java @@ -0,0 +1,129 @@ +package io.trygvis.persistence.generators; + +import io.trygvis.container.compiler.SqlUnitModel; +import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.Constructor; +import io.trygvis.container.compiler.model.FieldRef; +import io.trygvis.container.compiler.model.Imports; +import io.trygvis.container.compiler.model.MethodRef; +import io.trygvis.container.compiler.model.Parameters; +import io.trygvis.container.compiler.model.TypeRef; +import io.trygvis.persistence.EntityMirror; +import io.trygvis.persistence.sql.SqlDao; +import io.trygvis.persistence.sql.SqlEntityManager; +import io.trygvis.persistence.sql.SqlEntityManagerFactory; + +import java.io.IOException; +import java.sql.Connection; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static io.trygvis.container.compiler.Utils.toClassName; +import static io.trygvis.container.compiler.Utils.toFieldName; +import static io.trygvis.container.compiler.model.Parameters.ParameterRef; +import static java.lang.reflect.Modifier.PUBLIC; + +public class EntityManagerGenerator { + public static ClassG generateEntityManager(SqlUnitModel unit) throws IOException { + String prefix = unit.getPackageName() + "." + toClassName(unit.getName()); + TypeRef emType = new TypeRef(prefix + "EntityManager"); + + ClassG g = new ClassG(PUBLIC, emType). + extendsType(SqlEntityManager.class); + + Map daoFields = new HashMap<>(); + for (EntityMirror entity : unit.getEntities().values()) { + daoFields.put(entity, g.addField(entity.daoType, toFieldName(entity.type.className))); + } + + g.add(constructor(unit, g.imports, daoFields)); + g.add(getSqlDao(unit, g.imports, daoFields)); + + return g; + } + + private static Constructor constructor(SqlUnitModel unit, Imports imports, Map daoFields) { + Parameters p = new Parameters(); + ParameterRef semf = p.addParameter(imports.add(SqlEntityManagerFactory.class), "emf"); + ParameterRef c = p.addParameter(imports.add(Connection.class), "c"); + List body = new ArrayList<>(); + body.add("super(" + semf.name + ", " + c.name + ");"); + + for (EntityMirror entity : unit.getEntities().values()) { + FieldRef f = daoFields.get(entity); + body.add("this." + f.name + " = new " + entity.daoType.plainName + "(" + c.name + ");"); + } + return new Constructor(p, body); + } + + public static MethodRef getSqlDao(SqlUnitModel unit, Imports imports, Map daoFields) { + TypeRef sqlDatoType = imports.add(new TypeRef(SqlDao.class)).args("Id", "T"); + Parameters p = new Parameters(); + TypeRef klassType = new TypeRef(Class.class).args("T"); + ParameterRef klass = p.addParameter(klassType, "klass"); + List body = new ArrayList<>(); + for (EntityMirror entity : unit.getEntities().values()) { + body.add("if (klass == " + entity.type.plainName + ".class) {"); + body.add(" @SuppressWarnings(\"unchecked\")"); + body.add(" SqlDao dao = (SqlDao) " + daoFields.get(entity).name + ";"); + body.add(" return (SqlDao) dao;"); + body.add("}"); + } + body.add("throw new RuntimeException(\"Type is not a part of this persistence unit: \" + klass);"); + return new MethodRef(PUBLIC, sqlDatoType, "getDao", p, body).typeArgs("Id", "T"); + } + + /* + public static ClassG sem(EntityMirror entity) { + ClassG g = new ClassG(PUBLIC, new TypeRef(entity.type.className + "SEM")); + g.implementsType(g.imports.add(new TypeRef(SqlDao.class)).args(entity.idType, entity.type)); + return g. + add(semFind(entity, g.imports)). + add(semPersist(entity, g.imports)). + add(semMerge(entity, g.imports)). + add(semRemove(entity, g.imports)); + } + + public static MethodRef semFind(EntityMirror entity, Imports imports) { + TypeRef type = imports.add(entity.type); + TypeRef sqlException = imports.add(SQLException.class); + Parameters p = new Parameters(); + ParameterRef primaryKey = p.addParameter(new TypeRef(Object.class), "primaryKey"); + List body = new ArrayList<>(); + body.add("throw new " + sqlException.plainName + "(\"Not implemented\");"); + return new MethodRef(PUBLIC, type, "find", p, tryCatchSqlException(imports, body)); + } + + public static MethodRef semPersist(EntityMirror entity, Imports imports) { + TypeRef type = imports.add(entity.type); + TypeRef dao = imports.add(entity.daoType); + Parameters p = new Parameters(); + ParameterRef e = p.addParameter(type, "entity"); + List body = new ArrayList<>(); + body.add(dao.plainName + ".insertInto(currentConnection(), " + e.name + ");"); + return new MethodRef(PUBLIC, VOID, "persist", p, tryCatchSqlException(imports, body)); + } + + public static MethodRef semMerge(EntityMirror entity, Imports imports) { + TypeRef type = imports.add(entity.type); + TypeRef sqlException = imports.add(SQLException.class); + Parameters p = new Parameters(); + ParameterRef e = p.addParameter(type, "entity"); + List body = new ArrayList<>(); + body.add("throw new " + sqlException.plainName + "(\"Not implemented\");"); + return new MethodRef(PUBLIC, type, "merge", p, tryCatchSqlException(imports, body)); + } + + public static MethodRef semRemove(EntityMirror entity, Imports imports) { + TypeRef type = imports.add(entity.type); + TypeRef sqlException = imports.add(SQLException.class); + Parameters p = new Parameters(); + ParameterRef e = p.addParameter(type, "entity"); + List body = new ArrayList<>(); + body.add("throw new " + sqlException.plainName + "(\"Not implemented\");"); + return new MethodRef(PUBLIC, VOID, "remove", p, tryCatchSqlException(imports, body)); + } + */ +} diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SequencesGenerator.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SequencesGenerator.java new file mode 100644 index 0000000..07823af --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SequencesGenerator.java @@ -0,0 +1,41 @@ +package io.trygvis.persistence.generators; + +import io.trygvis.container.compiler.SqlUnitModel; +import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.FieldRef; +import io.trygvis.container.compiler.model.TypeRef; +import io.trygvis.persistence.SequenceMirror; + +import java.util.ArrayList; +import java.util.List; + +import static io.trygvis.container.compiler.Utils.toJavaString; +import static java.lang.reflect.Modifier.PUBLIC; +import static org.apache.commons.lang.StringUtils.capitalize; +import static org.apache.commons.lang.StringUtils.join; + +public class SequencesGenerator { + public static ClassG generateSequences(SqlUnitModel unit) { + TypeRef sequences = new TypeRef(unit.getPackageName() + ".Sequences"); + ClassG g = new ClassG(PUBLIC, sequences); + List creates = new ArrayList<>(); + List drops = new ArrayList<>(); + for (SequenceMirror sequence : unit.getSequences().values()) { + TypeRef stringType = g.imports.add(String.class); + String value = "CREATE SEQUENCE " + sequence.sequenceName + ";"; + FieldRef f = g.addPublicStaticFinalField(stringType, "create" + capitalize(sequence.name)). + value(toJavaString(value)); + creates.add(f.name); + + f = g.addPublicStaticFinalField(stringType, "drop" + capitalize(sequence.name)). + value(toJavaString("DROP SEQUENCE " + sequence.sequenceName) + ";"); + drops.add(f.name); + + } + g.addPublicStaticFinalField(new TypeRef(String[].class), "createSequences"). + value("new String[]{" + join(creates, ", ") + "}"); + g.addPublicStaticFinalField(new TypeRef(String[].class), "dropSequences"). + value("new String[]{" + join(drops, ", ") + "}"); + return g; + } +} -- cgit v1.2.3