summaryrefslogtreecommitdiff
path: root/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2013-08-10 15:44:58 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2013-08-10 15:44:58 +0200
commit5a1256a8ed931f7a5ba05c4328353411bae31f2b (patch)
tree2d25ea2076d2dd229bfe7bac61b27977f11889eb /container-compiler-plugin/src/main/java/io/trygvis/persistence/generators
parent86c174ddf24b3e5ac8c8d45fa4d7dc6c5d5d3a3a (diff)
downloadcontainer-playground-5a1256a8ed931f7a5ba05c4328353411bae31f2b.tar.gz
container-playground-5a1256a8ed931f7a5ba05c4328353411bae31f2b.tar.bz2
container-playground-5a1256a8ed931f7a5ba05c4328353411bae31f2b.tar.xz
container-playground-5a1256a8ed931f7a5ba05c4328353411bae31f2b.zip
o Moving code out to separate generators.
o Creating SqlSession and SqlSessionFactory.
Diffstat (limited to 'container-compiler-plugin/src/main/java/io/trygvis/persistence/generators')
-rw-r--r--container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/DaoGenerator.java214
-rw-r--r--container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/DaoUtilsGenerator.java265
-rw-r--r--container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/GeneratorUtils.java46
-rw-r--r--container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SqlSessionFactoryGenerator.java67
-rw-r--r--container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SqlSessionGenerator.java129
5 files changed, 721 insertions, 0 deletions
diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/DaoGenerator.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/DaoGenerator.java
new file mode 100644
index 0000000..d9ac482
--- /dev/null
+++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/DaoGenerator.java
@@ -0,0 +1,214 @@
+package io.trygvis.persistence.generators;
+
+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.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.TypeHandler;
+import io.trygvis.persistence.sql.SqlDao;
+import io.trygvis.persistence.sql.SqlEntityMeta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static io.trygvis.container.compiler.Utils.toJavaString;
+import static io.trygvis.container.compiler.model.TypeRef.VOID;
+import static io.trygvis.persistence.FieldMirror.FieldType.PRIMITIVE;
+import static io.trygvis.persistence.FieldMirror.FieldType.REFERENCE;
+import static java.lang.String.format;
+import static java.lang.reflect.Modifier.PUBLIC;
+import static org.apache.commons.lang.StringUtils.join;
+
+public class DaoGenerator {
+
+ private final GeneratorConfiguration generatorConfiguration;
+ private final SqlUnitModel unit;
+ private final EntityMirror entity;
+
+ public DaoGenerator(GeneratorConfiguration generatorConfiguration, SqlUnitModel unit, EntityMirror entity) {
+ this.generatorConfiguration = generatorConfiguration;
+ this.unit = unit;
+ this.entity = entity;
+ }
+
+ public ClassG generate() throws IOException {
+ ClassG g = new ClassG(PUBLIC, entity.daoType).
+ extendsType(new TypeRef(SqlDao.class).args(entity.idType, entity.type));
+ Parameters p = new Parameters();
+ 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(SqlEntityMeta.class);
+ TypeRef sqlException = g.imports.add(SQLException.class);
+ TypeRef listOfEntityType = new TypeRef(List.class).args(entity.type);
+
+ FieldRef createTableSql = g.addPublicStaticFinalField(stringType, "createTableSql").
+ value(toJavaString(createTableSql()));
+ g.add(new MethodRef(PUBLIC, stringType, "createTableSql", "return createTableSql;"));
+ FieldRef dropTableSql = g.addPublicStaticFinalField(stringType, "dropTableSql").
+ value(toJavaString(dropTableSql()));
+ g.add(new MethodRef(PUBLIC, stringType, "dropTableSql", "return dropTableSql;"));
+ g.addPublicStaticFinalField(stringType, "insertIntoSql").
+ value(toJavaString(insertIntoSql()));
+ g.addPublicStaticFinalField(stringType, "deleteFromSql").
+ value(toJavaString(deleteFromSql()));
+ String desc = "new " + sqlEntityDescType + "(" +
+ toJavaString(entity.tableName) + ", " +
+ toJavaString(defaultFields()) + ", " +
+ createTableSql.name + ", " +
+ dropTableSql.name +
+ ")";
+ g.addPublicStaticFinalField(sqlEntityDescType, "desc").value(desc);
+ DaoUtilsGenerator daoUtil = new DaoUtilsGenerator(unit, generatorConfiguration, entity);
+ g.addInnerClass(daoUtil.queryType(g.imports));
+ g.addInnerClass(daoUtil.utils());
+
+ {
+ p = new Parameters();
+ Parameters.ParameterRef rs = p.addParameter(new TypeRef(ResultSet.class), "rs");
+ g.add(new MethodRef(PUBLIC, entity.type, "fromResultSet", p,
+ "return Utils.fromResultSet" + entity.type.className + "(" + rs.name + ");").
+ exception(sqlException));
+ }
+
+ {
+ p = new Parameters();
+ Parameters.ParameterRef entity = p.addParameter(this.entity.type, "entity");
+ g.add(new MethodRef(PUBLIC, VOID, "insert", p,
+ "Utils.insert" + this.entity.type.className + "(super.c, " + entity.name + ");").
+ exception(sqlException));
+ }
+
+ {
+ p = new Parameters();
+ Parameters.ParameterRef id = p.addParameter(entity.idType, "id");
+ g.add(new MethodRef(PUBLIC, entity.type, "selectById", p,
+ "return Utils.select" + entity.type.className + "ById(super.c, " + id.name + ");").
+ exception(sqlException));
+ }
+
+ {
+ p = new Parameters();
+ Parameters.ParameterRef where = p.addParameter(stringType, "where");
+ g.add(new MethodRef(PUBLIC, listOfEntityType, "selectWhere", p,
+ "return Utils.select" + entity.type.className + "Where(super.c, " + where.name + ");").
+ exception(sqlException));
+ }
+
+ {
+ p = new Parameters();
+ Parameters.ParameterRef entity = p.addParameter(this.entity.type, "entity");
+ g.add(new MethodRef(PUBLIC, VOID, "delete", p,
+ "Utils.delete" + this.entity.type.className + "(super.c, " + entity.name + ");").
+ exception(sqlException));
+ }
+
+ {
+ p = new Parameters();
+ Parameters.ParameterRef id = p.addParameter(entity.idType, "id");
+ g.add(new MethodRef(PUBLIC, VOID, "deleteById", p,
+ "Utils.delete" + entity.type.className + "ById(super.c, " + id.name + ");").
+ exception(sqlException));
+ }
+
+ {
+ p = new Parameters();
+ Parameters.ParameterRef entity = p.addParameter(this.entity.type, "entity");
+ g.add(new MethodRef(PUBLIC, VOID, "update", p,
+ "Utils.update" + this.entity.type.className + "(super.c, " + entity.name + ");").
+ exception(sqlException));
+ }
+
+ return g;
+ }
+
+ public String createTableSql() {
+ List<String> columns = new ArrayList<>();
+ for (FieldMirror field : entity.fields) {
+ String s;
+ if (field.fieldType == PRIMITIVE) {
+ TypeHandler typeHandler = generatorConfiguration.typeHandler(field.type);
+ s = " " + field.sqlName + " " + typeHandler.sqlType(field);
+ if (field.id) {
+ s += " PRIMARY KEY";
+ } else if (field.notNull) {
+ s += " NOT NULL";
+ } else if (field.unique) {
+ s += " UNIQUE";
+ }
+ } else if (field.fieldType == REFERENCE) {
+ EntityMirror referenced = unit.get(field.type);
+ if (referenced.idFields.size() == 1) {
+ FieldMirror idField = referenced.idFields.get(0);
+ TypeHandler typeHandler = generatorConfiguration.typeHandler(idField.type);
+ s = " " + field.sqlName + " " + typeHandler.sqlType(field);
+ s += " REFERENCES " + referenced.tableName + "(" + idField.sqlName + ")";
+ if (field.notNull) {
+ s += " NOT NULL";
+ } else if (field.unique) {
+ s += " UNIQUE";
+ }
+ } else {
+ throw new NotImplementedException();
+ }
+ } else {
+ throw new RuntimeException("Unknown field type: " + field.getClass());
+ }
+ columns.add(s);
+ }
+
+ return format("CREATE TABLE " + entity.tableName + "(%n" +
+ join(columns, ",%n") +
+ "%n);");
+ }
+
+ public String dropTableSql() {
+ return "DROP TABLE " + entity.tableName + ";";
+ }
+
+ public String insertIntoSql() {
+ List<String> columns = new ArrayList<>();
+ List<String> values = new ArrayList<>();
+ for (FieldMirror field : entity.fields) {
+ columns.add(field.sqlName);
+ if (field.id) {
+ values.add("nextval('" + unit.getDefaultSequence().sequenceName + "')");
+ } else {
+ values.add("?");
+ }
+ }
+
+ return "INSERT INTO " + entity.tableName + "(" + join(columns, ", ") + ") " +
+ "VALUES(" + join(values, ", ") + ");";
+ }
+
+ public String deleteFromSql() {
+ List<String> ss = new ArrayList<>();
+ for (FieldMirror field : entity.idFields) {
+ ss.add(field.sqlName + "=?");
+ }
+
+ return "DELETE FROM " + entity.tableName + " WHERE " + join(ss, " AND ") + ";";
+ }
+
+ public String defaultFields() {
+ List<String> names = new ArrayList<>();
+ for (FieldMirror field : entity.fields) {
+ names.add(field.sqlName);
+ }
+
+ return join(names, ", ");
+ }
+}
diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/DaoUtilsGenerator.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/DaoUtilsGenerator.java
new file mode 100644
index 0000000..115223a
--- /dev/null
+++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/DaoUtilsGenerator.java
@@ -0,0 +1,265 @@
+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.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.FieldMirror;
+import io.trygvis.persistence.GeneratorConfiguration;
+import io.trygvis.persistence.TypeHandler;
+import io.trygvis.persistence.sql.AbstractTypedQuery;
+import io.trygvis.persistence.sql.FromResultSet;
+
+import javax.persistence.TypedQuery;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.List;
+
+import static io.trygvis.container.compiler.Utils.toGetterName;
+import static io.trygvis.container.compiler.Utils.toSetterName;
+import static io.trygvis.persistence.FieldMirror.AccessorType.FIELD;
+import static io.trygvis.persistence.FieldMirror.AccessorType.METHOD;
+import static io.trygvis.persistence.FieldMirror.FieldType.PRIMITIVE;
+import static io.trygvis.persistence.FieldMirror.FieldType.REFERENCE;
+import static io.trygvis.persistence.generators.GeneratorUtils.staticVersion;
+import static java.lang.reflect.Modifier.PUBLIC;
+import static java.lang.reflect.Modifier.STATIC;
+import static java.util.Collections.singletonList;
+import static org.apache.commons.lang.StringUtils.join;
+
+public class DaoUtilsGenerator {
+
+ private final SqlUnitModel unit;
+ private final GeneratorConfiguration generatorConfiguration;
+ private final EntityMirror entity;
+
+ public DaoUtilsGenerator(SqlUnitModel unit, GeneratorConfiguration generatorConfiguration, EntityMirror entity) {
+ this.unit = unit;
+ this.generatorConfiguration = generatorConfiguration;
+ this.entity = entity;
+ }
+
+ public ClassG utils() {
+ ClassG g = new ClassG(PUBLIC | STATIC, entity.utilsType);
+ g.add(insertInto(g.imports));
+ g.add(selectById(g.imports));
+ g.add(selectWhere(g.imports));
+ g.add(update(g.imports));
+ g.add(delete(g.imports));
+ g.add(deleteById(g.imports));
+ g.add(query(g.imports));
+ MethodRef fromResultSet = fromResultSet(g.imports);
+ g.add(fromResultSet);
+ g.add(staticVersion(new TypeRef(FromResultSet.class).args(entity.type), "fromResultSet", fromResultSet, g.type));
+ return g;
+ }
+
+ public MethodRef insertInto(Imports imports) {
+ TypeRef sqlExceptionType = imports.add(SQLException.class);
+ TypeRef typesType = imports.add(Types.class);
+ TypeRef conType = imports.add(Connection.class);
+ TypeRef psType = imports.add(PreparedStatement.class);
+ Parameters p = new Parameters();
+ Parameters.ParameterRef con = p.addParameter(conType, "con");
+ Parameters.ParameterRef o = p.addParameter(entity.type, "o");
+
+ List<String> body = new ArrayList<>();
+
+ body.add("try(" + psType + " stmt = " + con.name + ".prepareStatement(insertIntoSql)) {");
+ int i = 0;
+ for (FieldMirror field : entity.fields) {
+ // Assume all ID fields are generated for now.
+ if (field.id) {
+ continue;
+ }
+
+ i++;
+
+ TypeHandler typeHandler;
+ String accessor;
+ String setter;
+ if (field.fieldType == PRIMITIVE) {
+ typeHandler = generatorConfiguration.typeHandler(field.type);
+ accessor = field.fieldAccessor(o);
+ setter = " stmt." + typeHandler.setter(i, accessor) + ";";
+ } else {
+ EntityMirror referenced = unit.get(field.type);
+ FieldMirror idField = referenced.getIdField();
+ typeHandler = generatorConfiguration.typeHandler(idField.type);
+ accessor = field.referenceAccessor(o, idField);
+ setter = " stmt." + typeHandler.setter(i, accessor) + ";";
+ accessor = "null";
+ }
+
+ if (field.notNull) {
+ body.add(setter);
+ } else {
+ body.add(" " + field.type + " " + field.javaName + " = " + accessor + ";");
+ body.add(" if (" + field.javaName + " == null) {");
+ body.add(" stmt.setNull(" + i + ", " + typesType + "." + typeHandler.typeName() + ");");
+ body.add(" } else {");
+ body.add(" " + setter);
+ body.add(" }");
+ }
+ }
+ body.add(" stmt.executeUpdate();");
+ body.add("}");
+ return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "insert" + entity.type.className, p, body).exception(sqlExceptionType);
+ }
+
+ public MethodRef selectById(Imports imports) {
+ Parameters p = new Parameters();
+ p.addParameter(imports.add(Connection.class), "c");
+ p.addParameter(entity.idType, "id");
+ return new MethodRef(PUBLIC | STATIC, entity.type, "select" + entity.type.className + "ById", p,
+ "throw new UnsupportedOperationException(\"Not implemented\");");
+ }
+
+ public MethodRef selectWhere(Imports imports) {
+ TypeRef sqlExceptionType = imports.add(SQLException.class);
+ Parameters p = new Parameters();
+ Parameters.ParameterRef c = p.addParameter(imports.add(Connection.class), "c");
+ Parameters.ParameterRef where = p.addParameter(imports.add(String.class), "where");
+ List<String> body = new ArrayList<>();
+ body.add("String sql = \"SELECT \" + desc.defaultFields + \" FROM " + entity.tableName + " WHERE \" + " + where.name + " + \";\";");
+ body.add("return runQuery(" + c.name + ", sql, " + entity.utilsType + ".fromResultSet" + entity.type.className + ");");
+
+ TypeRef listOfEntityType = new TypeRef(List.class).args(entity.type);
+ return new MethodRef(PUBLIC | STATIC, listOfEntityType, "select" + entity.type.className + "Where", p, body).
+ exception(sqlExceptionType);
+ }
+
+ public MethodRef update(Imports imports) {
+ Parameters p = new Parameters();
+ p.addParameter(imports.add(Connection.class), "c");
+ p.addParameter(entity.type, "entity");
+ return new MethodRef(PUBLIC | STATIC, entity.type, "update" + entity.type.className, p,
+ "throw new UnsupportedOperationException(\"Not implemented\");");
+ }
+
+ public MethodRef delete(Imports imports) {
+ TypeRef conType = imports.add(Connection.class);
+ TypeRef objectType = imports.add(entity.type);
+ Parameters p = new Parameters();
+ Parameters.ParameterRef con = p.addParameter(conType, "con");
+ Parameters.ParameterRef o = p.addParameter(objectType, "o");
+
+ List<String> arguments = new ArrayList<>();
+ arguments.add(con.name);
+ for (FieldMirror field : entity.idFields) {
+ if (field.accessorType == FIELD) {
+ arguments.add(o.name + "." + field.javaName);
+ } else {
+ arguments.add(o.name + "." + toGetterName(field.javaName) + "()");
+ }
+ }
+
+ return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "delete" + entity.type.className, p,
+ "delete" + entity.type.className + "ById(" + join(arguments, ", ") + ");").exception(imports.add(SQLException.class));
+ }
+
+ public MethodRef deleteById(Imports imports) {
+ TypeRef conType = imports.add(Connection.class);
+ TypeRef psType = imports.add(PreparedStatement.class);
+ Parameters p = new Parameters();
+ Parameters.ParameterRef con = p.addParameter(conType, "con");
+
+ List<String> body = new ArrayList<>();
+
+ body.add("try(" + psType + " stmt = " + con.name + ".prepareStatement(deleteFromSql)) {");
+ for (int i = 0; i < entity.idFields.size(); i++) {
+ FieldMirror field = entity.idFields.get(i);
+ p.addParameter(field.type, field.javaName);
+ TypeHandler typeHandler = generatorConfiguration.typeHandler(field.type);
+ body.add(" stmt." + typeHandler.setter(i + 1, field.javaName) + ";");
+ }
+ body.add(" stmt.executeUpdate();");
+ body.add("}");
+
+ return new MethodRef(PUBLIC | STATIC, TypeRef.VOID, "delete" + entity.type.className + "ById", p, body).
+ exception(imports.add(SQLException.class));
+ }
+
+ public ClassG queryType(Imports imports) {
+ TypeRef sqlQueryType = imports.add(AbstractTypedQuery.class).args(entity.type);
+ TypeRef conType = imports.add(Connection.class);
+ TypeRef entityTypedQuery = new TypeRef(entity.type.className + "TypedQuery");
+ TypeRef sqlExceptionType = new TypeRef(SQLException.class);
+
+ Parameters p = new Parameters();
+ Parameters.ParameterRef c = p.addParameter(conType, "c");
+ Constructor constructor = new Constructor(p, singletonList("super(" + c.name + ", " + entity.daoType.className + ".desc);"));
+ ClassG g = new ClassG(PUBLIC | STATIC, entityTypedQuery).
+ extendsType(sqlQueryType).
+ add(constructor);
+ p = new Parameters();
+ Parameters.ParameterRef rs = p.addParameter(new TypeRef(ResultSet.class), "rs");
+ MethodRef fromResultSet = new MethodRef(PUBLIC, entity.type, "fromResultSet", p,
+ "return " + entity.utilsType.className + ".fromResultSet" + entity.type.className + "(" + rs.name + ");").
+ exception(sqlExceptionType);
+ g.add(fromResultSet);
+ return g;
+ }
+
+ public MethodRef query(Imports imports) {
+ TypeRef conType = imports.add(Connection.class);
+ TypeRef typedQueryType = imports.add(TypedQuery.class).args(entity.type);
+ TypeRef entityTypedQuery = new TypeRef(entity.type.className + "TypedQuery");
+
+ Parameters p = new Parameters();
+ Parameters.ParameterRef c = p.addParameter(conType, "c");
+ return new MethodRef(PUBLIC | STATIC, typedQueryType, "query" + entity.type.className, p,
+ "return new " + entityTypedQuery + "(" + c.name + ");");
+ }
+
+ public MethodRef fromResultSet(Imports g) {
+ TypeRef rsType = g.add(ResultSet.class);
+ Parameters p = new Parameters();
+ Parameters.ParameterRef rs = p.addParameter(rsType, "rs");
+
+ List<String> body = new ArrayList<>();
+ List<String> names = new ArrayList<>();
+ for (int i = 0; i < entity.fields.size(); i++) {
+ FieldMirror field = entity.fields.get(i);
+ if (field.accessorType != FIELD) {
+ continue;
+ }
+ if (field.fieldType == PRIMITIVE) {
+ TypeHandler typeHandler = generatorConfiguration.typeHandler(field.type);
+ body.add(field.type + " " + field.javaName + " = " + typeHandler.getter(rs.name, i + 1) + ";");
+ } else if (field.fieldType == REFERENCE) {
+ body.add(field.type + " " + field.javaName + " = null;");
+ }
+ names.add(field.javaName);
+ }
+
+ body.add(entity.type + " returnValue = new " + entity.type + "(" + join(names, ", ") + ");");
+
+ for (int i = 0; i < entity.fields.size(); i++) {
+ FieldMirror field = entity.fields.get(i);
+ if (field.accessorType != METHOD) {
+ continue;
+ }
+ if (field.fieldType == PRIMITIVE) {
+ TypeHandler typeHandler = generatorConfiguration.typeHandler(field.type);
+ body.add("returnValue." + toSetterName(field.javaName) + "(" + typeHandler.getter(rs.name, i + 1) + ");");
+ } else if (field.fieldType == REFERENCE) {
+ body.add("returnValue." + toSetterName(field.javaName) + "(" + null + ");");
+ }
+ names.add(field.javaName);
+ }
+
+ body.add("return returnValue;");
+
+ return new MethodRef(PUBLIC | STATIC, entity.type, "fromResultSet" + entity.type.className, p, body).
+ exception(g.add(SQLException.class));
+ }
+}
diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/GeneratorUtils.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/GeneratorUtils.java
new file mode 100644
index 0000000..7dc083e
--- /dev/null
+++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/GeneratorUtils.java
@@ -0,0 +1,46 @@
+package io.trygvis.persistence.generators;
+
+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 java.io.CharArrayWriter;
+import java.io.PrintWriter;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.lang.reflect.Modifier.*;
+import static org.apache.commons.lang.StringUtils.join;
+
+public class GeneratorUtils {
+ public static FieldRef staticVersion(TypeRef interfaceType, String interfaceMethod, MethodRef methodRef, TypeRef klass) {
+ if (!Modifier.isStatic(methodRef.modifiers)) {
+ throw new RuntimeException("This only works on static methods.");
+ }
+
+ List<String> params = new ArrayList<>();
+ List<String> args = new ArrayList<>();
+ for (Parameters.ParameterRef parameter : methodRef.parameters) {
+ params.add(parameter.klass.plainName + " " + parameter.name);
+ args.add(parameter.name);
+ }
+
+ List<String> exceptions = new ArrayList<>();
+ for (TypeRef exception : methodRef.exceptions) {
+ exceptions.add(exception.plainName);
+ }
+
+ String e = exceptions.isEmpty() ? "" : "throws " + join(exceptions, ", ") + " ";
+
+ CharArrayWriter buffer = new CharArrayWriter();
+ PrintWriter w = new PrintWriter(buffer);
+ w.println("new " + interfaceType.plainName + "() {");
+ w.println(" public " + methodRef.returnType.plainName + " " + interfaceMethod + "(" + join(params, ", ") + ") " + e + "{");
+ w.println(" return " + klass.plainName + "." + methodRef.name + "(" + join(args, ", ") + ");");
+ w.println(" }");
+ w.println("}");
+ return new FieldRef(PUBLIC | STATIC | FINAL, interfaceType, methodRef.name).value(buffer.toString());
+ }
+}
diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SqlSessionFactoryGenerator.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SqlSessionFactoryGenerator.java
new file mode 100644
index 0000000..3f0da2b
--- /dev/null
+++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SqlSessionFactoryGenerator.java
@@ -0,0 +1,67 @@
+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.SqlEntityMeta;
+import io.trygvis.persistence.sql.SqlSessionFactory;
+import io.trygvis.persistence.sql.SqlUnit;
+
+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 SqlSessionFactoryGenerator {
+ public static ClassG generateSqlSessionFactory(SqlUnitModel unit) throws IOException {
+ String prefix = unit.getPackageName() + "." + toClassName(unit.getName());
+ TypeRef ssfType = new TypeRef(prefix + "SqlSessionFactory");
+ TypeRef ssType = new TypeRef(prefix + "SqlSession");
+
+ ClassG g = new ClassG(PUBLIC, ssfType).
+ extendsType(new TypeRef(SqlSessionFactory.class).args(ssType));
+
+ List<String> 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(newSession(unit, ssType, 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<String> body = new ArrayList<>();
+ body.add("super(new " + sqlUnitType.plainName + "(" + entities.name + "), " + ds.name + ");");
+ return new Constructor(p, body);
+ }
+
+ private static MethodRef newSession(SqlUnitModel unit, TypeRef sessionType, Imports imports) {
+ String prefix = unit.getPackageName() + "." + toClassName(unit.getName());
+ TypeRef connectionType = imports.add(Connection.class);
+
+ Parameters p = new Parameters();
+ Parameters.ParameterRef c = p.addParameter(connectionType, "c");
+ return new MethodRef(PROTECTED, sessionType, "newSession", p,
+ "return new " + sessionType + "(" + c.name + ");");
+ }
+}
diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SqlSessionGenerator.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SqlSessionGenerator.java
new file mode 100644
index 0000000..7a46018
--- /dev/null
+++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/generators/SqlSessionGenerator.java
@@ -0,0 +1,129 @@
+package io.trygvis.persistence.generators;
+
+import io.trygvis.container.compiler.SqlUnitModel;
+import io.trygvis.container.compiler.model.AnnotationG;
+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.SqlSession;
+
+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 SqlSessionGenerator {
+ public static ClassG generateSqlSession(SqlUnitModel unit) throws IOException {
+ String prefix = unit.getPackageName() + "." + toClassName(unit.getName());
+ TypeRef emType = new TypeRef(prefix + "SqlSession");
+ TypeRef sqlSession = new TypeRef(SqlSession.class);
+
+ ClassG g = new ClassG(PUBLIC, emType).
+ extendsType(sqlSession);
+
+ Map<EntityMirror, FieldRef> daoFields = new HashMap<>();
+ for (EntityMirror entity : unit.getEntities().values()) {
+ FieldRef f = g.addPublicFinalField(entity.daoType, toFieldName(entity.type.className));
+ daoFields.put(entity, f);
+ }
+
+ 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<EntityMirror, FieldRef> daoFields) {
+ Parameters p = new Parameters();
+ ParameterRef c = p.addParameter(imports.add(Connection.class), "c");
+ List<String> body = new ArrayList<>();
+ body.add("super(" + 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<EntityMirror, FieldRef> 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<String> body = new ArrayList<>();
+ for (EntityMirror entity : unit.getEntities().values()) {
+ body.add("if (klass == " + entity.type.plainName + ".class) {");
+ body.add(" return (SqlDao<Id, T>) " + daoFields.get(entity).name + ";");
+ 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").
+ annotation(new AnnotationG(new TypeRef(SuppressWarnings.class), "\"unchecked\""));
+ }
+
+ /*
+ 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<String> 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<String> 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<String> 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<String> body = new ArrayList<>();
+ body.add("throw new " + sqlException.plainName + "(\"Not implemented\");");
+ return new MethodRef(PUBLIC, VOID, "remove", p, tryCatchSqlException(imports, body));
+ }
+ */
+}