From 34137b599dbea13c94224dff2955376b1394dbc9 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sat, 3 Aug 2013 12:33:39 +0200 Subject: wip --- container-compiler-plugin/pom.xml | 5 ++ .../trygvis/container/compiler/EntityHandler.java | 89 ++++++++++++++++------ .../io/trygvis/container/compiler/MyProcessor.java | 53 ++++++------- .../container/compiler/entity/EntityMirror.java | 38 --------- .../trygvis/container/compiler/model/ClassG.java | 27 +++++-- .../container/compiler/model/MethodRef.java | 13 +++- .../java/io/trygvis/persistence/EntityMirror.java | 65 ++++++++++++++++ .../java/io/trygvis/persistence/FieldMirror.java | 63 +++++++++++++++ .../io/trygvis/persistence/GeneratorSupport.java | 41 ++++++++++ .../java/io/trygvis/persistence/SqlEntity.java | 17 +++++ .../java/io/trygvis/persistence/TypeHandler.java | 26 +++++++ .../container/compiler/EntityHandlerTest.java | 1 + .../container/compiler/JavaSourceFromString.java | 32 ++++++++ .../trygvis/container/compiler/ProcessorTest.java | 35 +-------- .../persistence/test/PersonTypeHandler.java | 11 +++ .../src/test/resources/Person.java | 23 +++--- persistence-compile-time/pom.xml | 19 +++++ pom.xml | 1 + 18 files changed, 420 insertions(+), 139 deletions(-) delete mode 100644 container-compiler-plugin/src/main/java/io/trygvis/container/compiler/entity/EntityMirror.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/persistence/EntityMirror.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/persistence/FieldMirror.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/persistence/GeneratorSupport.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/persistence/SqlEntity.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/persistence/TypeHandler.java create mode 100644 container-compiler-plugin/src/test/java/io/trygvis/container/compiler/JavaSourceFromString.java create mode 100644 container-compiler-plugin/src/test/java/io/trygvis/persistence/test/PersonTypeHandler.java create mode 100644 persistence-compile-time/pom.xml diff --git a/container-compiler-plugin/pom.xml b/container-compiler-plugin/pom.xml index f48d8fc..2e9fff9 100644 --- a/container-compiler-plugin/pom.xml +++ b/container-compiler-plugin/pom.xml @@ -15,6 +15,11 @@ container-core ${project.version} + + io.trygvis.container + persistence-compile-time + ${project.version} + org.easytesting fest-assert 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 df7a673..f9247e0 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,43 +1,90 @@ package io.trygvis.container.compiler; -import io.trygvis.container.compiler.entity.EntityMirror; import io.trygvis.container.compiler.model.ClassG; import io.trygvis.container.compiler.model.Parameters; +import io.trygvis.persistence.EntityMirror; +import io.trygvis.persistence.FieldMirror; +import io.trygvis.persistence.GeneratorSupport; +import io.trygvis.persistence.SqlEntity; +import io.trygvis.persistence.TypeHandler; import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; import javax.tools.JavaFileObject; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Set; -import static io.trygvis.container.compiler.entity.EntityMirror.FieldMirror; +import static io.trygvis.persistence.FieldMirror.PrimitiveFieldMirror; import static java.lang.Character.isUpperCase; import static javax.lang.model.util.ElementFilter.fieldsIn; -import static org.springframework.util.StringUtils.collectionToDelimitedString; public class EntityHandler extends AbstractHandler { + GeneratorSupport generatorSupport = new GeneratorSupport(); + public EntityHandler(ProcessingEnvironment processingEnv) { super(processingEnv); } + public void phase1(Set sqlEntities) throws Exception { + System.out.println("io.trygvis.container.compiler.EntityHandler.phase1"); + for (Element entity : sqlEntities) { +// SqlEntity sqlEntity = entity.getAnnotation(SqlEntity.class); +// Class typeHandlerClass = sqlEntity.value(); + + AnnotationMirror sqlEntity = findAnnotation(SqlEntity.class, entity.getAnnotationMirrors()); + for (Map.Entry v : sqlEntity.getElementValues().entrySet()) { + switch (v.getKey().getSimpleName().toString()) { + case "value": + Class typeHandlerClass = getClass().getClassLoader().loadClass(v.getValue().getValue().toString()); + + TypeHandler typeHandler = (TypeHandler) typeHandlerClass.newInstance(); + String type = entity.asType().toString(); + generatorSupport.addTypeHandler(type, typeHandler); + System.out.println("Loaded TypeHandler for " + type + " through " + typeHandlerClass.getCanonicalName()); + break; + } + } + System.out.println("sqlEntity.getElementValues() = " + sqlEntity.getElementValues()); + } + } + + private AnnotationMirror findAnnotation(Class c, List annotations) { + TypeElement t = elements.getTypeElement(c.getCanonicalName()); + for (AnnotationMirror a : annotations) { + if (types.isSameType(a.getAnnotationType(), t.asType())) { + return a; + } + } + + throw new RuntimeException("Could not find annotation " + c.getSimpleName()); + } + public void processEntity(TypeElement element) throws Exception { - EntityMirror entityMirror = new EntityMirror(sqlName(element.getSimpleName().toString())); + EntityMirror entityMirror = new EntityMirror(generatorSupport, element.asType(), sqlName(element.getSimpleName().toString())); for (VariableElement f : fieldsIn(elements.getAllMembers(element))) { - entityMirror.add(fromElement(f)); + entityMirror.add(fromElement(generatorSupport, f)); } String p = elements.getPackageOf(element).getQualifiedName().toString(); String className = element.getSimpleName() + "_Sql"; ClassG g = new ClassG(p, className, null); - g.addPublicFinalField(String.class, "insertInto"); - String insertInto = insertInto(entityMirror); + g.addPublicFinalField(String.class, "insertIntoSql"); + String insertInto = entityMirror.insertIntoSql(); List body = new ArrayList<>(); - body.add("this.insertInto = \"" + insertInto + "\";"); + body.add("this.insertIntoSql = \"" + insertInto + "\";"); g.addConstructor(new Parameters(), body); + entityMirror.insertInto(g); String fileName = (p.length() == 0 ? "" : p + ".") + className; JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(fileName, element); @@ -46,25 +93,21 @@ public class EntityHandler extends AbstractHandler { } } - public static String insertInto(EntityMirror entityMirror) { - List names = new ArrayList<>(); - List placeholders = new ArrayList<>(); - for (FieldMirror field : entityMirror.fields) { - names.add(field.sqlName); - placeholders.add("?"); - } - return "INSERT INTO " + entityMirror.tableName + "(" + collectionToDelimitedString(names, ", ") + ") " + - "VALUES(" + collectionToDelimitedString(placeholders, ", ") + ");"; - } - - public FieldMirror fromElement(VariableElement var) { - System.out.println("io.trygvis.container.compiler.entity.EntityMirror.FieldMirror.fromElement"); + public FieldMirror fromElement(GeneratorSupport generatorSupport, VariableElement var) { System.out.print("element = "); + TypeMirror type = var.asType(); elements.printElements(new PrintWriter(System.out), var); String javaName = var.getSimpleName().toString(); String sqlName = sqlName(javaName); boolean notNull = false; - FieldMirror field = new FieldMirror(javaName, sqlName, notNull); + FieldMirror field; + if (generatorSupport.isPrimitive(type)) { + field = new PrimitiveFieldMirror(var, javaName, sqlName, notNull); + } else if (generatorSupport.hasTypeHandler(type)) { + field = new FieldMirror.ReferenceFieldMirror(var, javaName, sqlName, notNull); + } else { + throw new RuntimeException("Missing type handler for type: " + type); + } System.out.println("field = " + field); return field; } @@ -73,7 +116,7 @@ public class EntityHandler extends AbstractHandler { StringBuilder builder = new StringBuilder(); for (char c : javaName.toCharArray()) { char lower = Character.toLowerCase(c); - if(isUpperCase(c) && builder.length() > 0) { + if (isUpperCase(c) && builder.length() > 0) { builder.append("_"); } builder.append(lower); 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 6843659..735d688 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 @@ -1,6 +1,7 @@ package io.trygvis.container.compiler; import io.trygvis.container.log.Log; +import io.trygvis.persistence.SqlEntity; import org.springframework.transaction.annotation.Transactional; import javax.annotation.processing.Completion; @@ -31,19 +32,16 @@ public class MyProcessor implements Processor { @Override public Set getSupportedOptions() { - System.out.println("io.trygvis.container.compiler.MyProcessor.getSupportedOptions"); return emptySet(); } @Override public SourceVersion getSupportedSourceVersion() { - System.out.println("io.trygvis.container.compiler.MyProcessor.getSupportedSourceVersion"); return SourceVersion.RELEASE_7; } @Override public void init(ProcessingEnvironment processingEnv) { - System.out.println("io.trygvis.container.compiler.MyProcessor.init"); this.processingEnv = processingEnv; elements = processingEnv.getElementUtils(); types = processingEnv.getTypeUtils(); @@ -51,13 +49,11 @@ public class MyProcessor implements Processor { @Override public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { - System.out.println("io.trygvis.container.compiler.MyProcessor.getCompletions"); return emptyList(); } @Override public Set getSupportedAnnotationTypes() { - System.out.println("io.trygvis.container.compiler.MyProcessor.getSupportedAnnotationTypes"); return new HashSet<>(asList( Transactional.class.getName(), Log.class.getName(), @@ -66,34 +62,39 @@ public class MyProcessor implements Processor { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - System.out.println("io.trygvis.container.compiler.MyProcessor.process"); - System.out.println("annotations = " + annotations); -// Set transactional = roundEnv.getElementsAnnotatedWith(Transactional.class); + try { + return work(annotations, roundEnv); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + public boolean work(Set annotations, RoundEnvironment roundEnv) throws Exception { TypeElement tx = elements.getTypeElement(Transactional.class.getCanonicalName()); TypeElement log = elements.getTypeElement(Log.class.getCanonicalName()); TypeElement entity = elements.getTypeElement(Entity.class.getCanonicalName()); + EntityHandler entityHandler = new EntityHandler(processingEnv); + + Set sqlEntities = roundEnv.getElementsAnnotatedWith(SqlEntity.class); + entityHandler.phase1(sqlEntities); + for (Element element : roundEnv.getRootElements()) { - try { - System.out.println("Processing: " + element); - for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { - DeclaredType annotationType = annotationMirror.getAnnotationType(); - - if (types.isSameType(tx.asType(), annotationType)) { - new TransactionalHandler(processingEnv).processTransactional((TypeElement) element); - } - if (types.isSameType(log.asType(), annotationType)) { - new LogHandler(processingEnv).processLog((TypeElement) element); - } - if (types.isSameType(entity.asType(), annotationType)) { - new EntityHandler(processingEnv).processEntity((TypeElement) element); - } + System.out.println("Processing: " + element); + for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + + if (types.isSameType(tx.asType(), annotationType)) { + new TransactionalHandler(processingEnv).processTransactional((TypeElement) element); + } + if (types.isSameType(log.asType(), annotationType)) { + new LogHandler(processingEnv).processLog((TypeElement) element); + } + if (types.isSameType(entity.asType(), annotationType)) { + entityHandler.processEntity((TypeElement) element); } - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); } } return true; diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/entity/EntityMirror.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/entity/EntityMirror.java deleted file mode 100644 index ae7077c..0000000 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/entity/EntityMirror.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.trygvis.container.compiler.entity; - -import java.util.ArrayList; -import java.util.List; - -public class EntityMirror { - public final List fields = new ArrayList<>(); - public final String tableName; - - public EntityMirror(String tableName) { - this.tableName = tableName; - } - - public void add(FieldMirror field) { - fields.add(field); - } - - public static class FieldMirror { - private final String javaName; - public final String sqlName; - private final boolean notNull; - - public FieldMirror(String javaName, String sqlName, boolean notNull) { - this.javaName = javaName; - this.sqlName = sqlName; - this.notNull = notNull; - } - - @Override - public String toString() { - return "FieldMirror{" + - "javaName='" + javaName + '\'' + - ", sqlName='" + sqlName + '\'' + - ", notNull=" + notNull + - '}'; - } - } -} 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 cf68cba..8ff91a0 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 @@ -31,7 +31,6 @@ public class ClassG { } String canonicalName = type.toString(); - System.out.println("canonicalName = " + canonicalName); for (TypeRef i : imports) { if (i.canonicalName().equals(canonicalName)) { @@ -45,10 +44,6 @@ public class ClassG { } public TypeRef addImport(Class klass) { -// if (klass.isPrimitive()) { -// return TypeRef.PRIMITIVE; -// } - String canonicalName = klass.getCanonicalName(); String simpleName = klass.getSimpleName(); String name = simpleName; @@ -104,6 +99,9 @@ public class ClassG { if (i.isPrimitive()) { continue; } + if(i.canonicalName().indexOf('.') == -1) { + continue; + } writer.println("import " + i.canonicalName() + ";"); } writer.println(); @@ -144,7 +142,24 @@ public class ClassG { parameters.add("final " + p.klass.name + " " + p.name); } - writer.println(" public " + returnString + " " + method.name + "(" + collectionToDelimitedString(parameters, ", ") + ") {"); + writer.print(" public " + returnString + " " + method.name + "(" + collectionToDelimitedString(parameters, ", ") + ")"); + if(method.exceptions.isEmpty()) { + writer.println(" {"); + } + else { + writer.println(" throws"); + ArrayList typeRefs = new ArrayList<>(method.exceptions); + for (int i = 0; i < typeRefs.size(); i++) { + TypeRef e = typeRefs.get(i); + writer.print(" " + e.name); + if(i < typeRefs.size() - 1) { + writer.println(","); + } + else { + writer.println(" {"); + } + } + } for (String s : method.body) { writer.print(" "); writer.println(s); 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 36f61e8..a59e9a6 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,18 +1,27 @@ package io.trygvis.container.compiler.model; import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import static java.util.Collections.addAll; public class MethodRef { public final TypeRef returnType; public final String name; public final ParameterRef[] parameters; + public final Set exceptions = new TreeSet<>(); public final List body; - public - MethodRef(TypeRef returnType, String name, ParameterRef[] parameters, List body) { + public MethodRef(TypeRef returnType, String name, ParameterRef[] parameters, List body) { this.returnType = returnType; this.name = name; this.parameters = parameters; this.body = body; } + + public MethodRef exception(TypeRef... exceptions) { + addAll(this.exceptions, exceptions); + return this; + } } 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 new file mode 100644 index 0000000..fe50e17 --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/EntityMirror.java @@ -0,0 +1,65 @@ +package io.trygvis.persistence; + +import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.ParameterRef; +import io.trygvis.container.compiler.model.TypeRef; + +import javax.lang.model.type.TypeMirror; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import static org.apache.commons.lang.StringUtils.join; + +public class EntityMirror { + public final GeneratorSupport generatorSupport; + public final List fields = new ArrayList<>(); + public final TypeMirror javaName; + public final String tableName; + + public EntityMirror(GeneratorSupport generatorSupport, TypeMirror javaName, String tableName) { + this.generatorSupport = generatorSupport; + this.javaName = javaName; + this.tableName = tableName; + } + + public void add(FieldMirror field) { + fields.add(field); + } + + public String insertIntoSql() { + List names = new ArrayList<>(); + List placeholders = new ArrayList<>(); + for (FieldMirror field : fields) { + names.add(field.sqlName); + placeholders.add("?"); + } + + return "INSERT INTO " + tableName + "(" + join(names, ", ") + ") " + + "VALUES(" + join(placeholders, ", ") + ");"; + } + + public void insertInto(ClassG g) { + TypeRef conType = g.addImport(Connection.class); + TypeRef psType = g.addImport(PreparedStatement.class); + TypeRef objectType = g.addImport(javaName); + ParameterRef con = new ParameterRef(conType, "con"); + ParameterRef object = new ParameterRef(objectType, "o"); + + List body = new ArrayList<>(); + + body.add("try(" + psType.name + " stmt = " + con.name + ".prepareStatement(insertIntoSql)) {"); + for (int i = 0; i < fields.size(); i++) { + FieldMirror field = fields.get(i); + TypeHandler typeHandler = generatorSupport.typeHandler(field.element); + body.add(" stmt." + typeHandler.resultSetSetter(i + 1, "o", field) + ";"); + } + body.add(" stmt.executeUpdate();"); + body.add("}"); + + g.addMethod(body, TypeRef.VOID, "insertInto", con, object). + exception(g.addImport(SQLException.class)); + } +} diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/FieldMirror.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/FieldMirror.java new file mode 100644 index 0000000..e14fb9f --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/FieldMirror.java @@ -0,0 +1,63 @@ +package io.trygvis.persistence; + +import javax.lang.model.element.VariableElement; + +import static io.trygvis.persistence.FieldMirror.FieldType.PRIMITIVE; +import static io.trygvis.persistence.FieldMirror.FieldType.REFERENCE; + +/** + * TODO: a single field might have to be mapped to multiple sql columns. + */ +public abstract class FieldMirror { + public final FieldType fieldType; + public final VariableElement element; + public final String javaName; + public final String sqlName; + public final boolean notNull; + + public enum FieldType { + PRIMITIVE, + REFERENCE, + } + + protected FieldMirror(FieldType fieldType, VariableElement element, String javaName, String sqlName, boolean notNull) { + this.fieldType = fieldType; + this.element = element; + this.javaName = javaName; + this.sqlName = sqlName; + this.notNull = notNull; + } + + public static class PrimitiveFieldMirror extends FieldMirror { + public PrimitiveFieldMirror(VariableElement element, String javaName, String sqlName, boolean notNull) { + super(PRIMITIVE, element, javaName, sqlName, notNull); + } + + @Override + public String toString() { + return "PrimitiveFieldMirror{" + + "javaName='" + javaName + '\'' + + ", sqlName='" + sqlName + '\'' + + ", notNull=" + notNull + + '}'; + } + } + + public static class ReferenceFieldMirror extends FieldMirror { + public ReferenceFieldMirror(VariableElement element, String javaName, String sqlName, boolean notNull) { + super(REFERENCE, element, javaName, sqlName, notNull); + } + + @Override + public String toString() { + return "ReferenceFieldMirror{" + + "javaName='" + javaName + '\'' + + ", sqlName='" + sqlName + '\'' + + ", notNull=" + notNull + + '}'; + } + } + + @Override + public abstract String toString(); +} diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/GeneratorSupport.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/GeneratorSupport.java new file mode 100644 index 0000000..7ac30d9 --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/GeneratorSupport.java @@ -0,0 +1,41 @@ +package io.trygvis.persistence; + +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.util.HashMap; +import java.util.Map; + +public class GeneratorSupport { + + private final Map primitiveTypeHandlers = new HashMap<>(); + private final Map typeHandlers = new HashMap<>(); + + { + typeHandlers.put("java.lang.Integer", new TypeHandler.IntTypeHandler()); + typeHandlers.put("java.lang.Long", new TypeHandler.LongTypeHandler()); + typeHandlers.put("java.util.Date", new TypeHandler.DateTypeHandler()); + + primitiveTypeHandlers.putAll(typeHandlers); + } + + public void addTypeHandler(String type, TypeHandler typeHandler) { + typeHandlers.put(type, typeHandler); + } + + public TypeHandler typeHandler(Element element) { + String type = element.asType().toString(); + TypeHandler typeHandler = typeHandlers.get(type); + if (typeHandler == null) + throw new RuntimeException("Unsupported field type: " + type); + return typeHandler; + } + + public boolean isPrimitive(TypeMirror type) { + return primitiveTypeHandlers.containsKey(type.toString()); + } + + public boolean hasTypeHandler(TypeMirror type) { + return typeHandlers.containsKey(type.toString()); + } +} diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/SqlEntity.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/SqlEntity.java new file mode 100644 index 0000000..e298eee --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/SqlEntity.java @@ -0,0 +1,17 @@ +package io.trygvis.persistence; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface SqlEntity { + /** + * The name of a class that implements {@link io.trygvis.persistence.TypeHandler}. + * + * The class needs to be available at compile time, but not runtime. + */ + String value(); +} diff --git a/container-compiler-plugin/src/main/java/io/trygvis/persistence/TypeHandler.java b/container-compiler-plugin/src/main/java/io/trygvis/persistence/TypeHandler.java new file mode 100644 index 0000000..252f4b4 --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/persistence/TypeHandler.java @@ -0,0 +1,26 @@ +package io.trygvis.persistence; + +public interface TypeHandler { + String resultSetSetter(int i, String o, FieldMirror field); + + public static class IntTypeHandler implements TypeHandler { + @Override + public String resultSetSetter(int i, String o, FieldMirror field) { + return "setInt(" + i + ", " + o + "." + field.javaName + ")"; + } + } + + public static class LongTypeHandler implements TypeHandler { + @Override + public String resultSetSetter(int i, String o, FieldMirror field) { + return "setLong(" + i + ", " + o + "." + field.javaName + ")"; + } + } + + public static class DateTypeHandler implements TypeHandler { + @Override + public String resultSetSetter(int i, String o, FieldMirror field) { + return "setTimestamp(" + i + ", new java.sql.Timestamp(" + o + "." + field.javaName + ".getTime()))"; + } + } +} diff --git a/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/EntityHandlerTest.java b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/EntityHandlerTest.java index 98fcaea..e24a362 100644 --- a/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/EntityHandlerTest.java +++ b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/EntityHandlerTest.java @@ -15,6 +15,7 @@ public class EntityHandlerTest { new Object[]{"MyClass", "my_class"}, new Object[]{"myField", "my_field"}, new Object[]{"name", "name"}, + new Object[]{"_first_name", "_first_name"}, new Object[]{"first_name", "first_name"}, new Object[]{"first_name_", "first_name_"}, }; diff --git a/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/JavaSourceFromString.java b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/JavaSourceFromString.java new file mode 100644 index 0000000..e07a11f --- /dev/null +++ b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/JavaSourceFromString.java @@ -0,0 +1,32 @@ +package io.trygvis.container.compiler; + +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import java.net.URI; + +/** + * A file object used to represent source coming from a string. + */ +public class JavaSourceFromString extends SimpleJavaFileObject { + /** + * The source code of this "file". + */ + final String code; + + /** + * Constructs a new JavaSourceFromString. + * + * @param name the name of the compilation unit represented by this file object + * @param code the source code for the compilation unit represented by this file object + */ + JavaSourceFromString(String name, String code) { + super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), + Kind.SOURCE); + this.code = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return code; + } +} diff --git a/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/ProcessorTest.java b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/ProcessorTest.java index e070f3c..2205d52 100644 --- a/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/ProcessorTest.java +++ b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/ProcessorTest.java @@ -7,10 +7,8 @@ import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; -import java.net.URI; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Locale; @@ -21,33 +19,6 @@ import static org.fest.assertions.Assertions.assertThat; public class ProcessorTest { Charset UTF_8 = Charset.forName("utf-8"); - /** - * A file object used to represent source coming from a string. - */ - public class JavaSourceFromString extends SimpleJavaFileObject { - /** - * The source code of this "file". - */ - final String code; - - /** - * Constructs a new JavaSourceFromString. - * - * @param name the name of the compilation unit represented by this file object - * @param code the source code for the compilation unit represented by this file object - */ - JavaSourceFromString(String name, String code) { - super(URI.create("string:///" + name.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension), - JavaFileObject.Kind.SOURCE); - this.code = code; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return code; - } - } - @Test public void testBasic() throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); @@ -66,6 +37,9 @@ public class ProcessorTest { Boolean result = task.call(); + assertThat(fileManager.codes.keySet()).containsOnly("Person_Sql"); + System.out.println(fileManager.codes.get("Person_Sql")); + for (Diagnostic diagnostic : collector.getDiagnostics()) { // System.out.println("diagnostic = " + diagnostic); System.out.println("diagnostic.source = ->" + diagnostic.getSource().getName() + "<-"); @@ -76,8 +50,5 @@ public class ProcessorTest { assertThat(result).isTrue(); fileManager.close(); - - assertThat(fileManager.codes.keySet()).containsOnly("Person_Sql"); - System.out.println(fileManager.codes.get("Person_Sql")); } } diff --git a/container-compiler-plugin/src/test/java/io/trygvis/persistence/test/PersonTypeHandler.java b/container-compiler-plugin/src/test/java/io/trygvis/persistence/test/PersonTypeHandler.java new file mode 100644 index 0000000..68e17c3 --- /dev/null +++ b/container-compiler-plugin/src/test/java/io/trygvis/persistence/test/PersonTypeHandler.java @@ -0,0 +1,11 @@ +package io.trygvis.persistence.test; + +import io.trygvis.persistence.FieldMirror; +import io.trygvis.persistence.TypeHandler; + +public class PersonTypeHandler implements TypeHandler { + @Override + public String resultSetSetter(int i, String o, FieldMirror field) { + return "setLong(" + i + ", o." + field.javaName + ".id)"; + } +} diff --git a/container-compiler-plugin/src/test/resources/Person.java b/container-compiler-plugin/src/test/resources/Person.java index 740b42d..4bdb882 100644 --- a/container-compiler-plugin/src/test/resources/Person.java +++ b/container-compiler-plugin/src/test/resources/Person.java @@ -1,26 +1,25 @@ +import io.trygvis.persistence.SqlEntity; + import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; -import java.util.ArrayList; import java.util.Date; -import java.util.List; @Entity +@SqlEntity("io.trygvis.persistence.test.PersonTypeHandler") public class Person { @Id - private Long id; + public Long id; - private Date birthDate; + public Date birthDate; @ManyToOne - private Person mother; + public Person mother; - @ManyToOne - private Person father; +// @ManyToOne +// public Person father; - @OneToMany(mappedBy = "id") - @OrderBy("birthDate asc") - private List children = new ArrayList<>(); +// @OneToMany(mappedBy = "id") +// @OrderBy("birthDate asc") +// private List children = new ArrayList<>(); } diff --git a/persistence-compile-time/pom.xml b/persistence-compile-time/pom.xml new file mode 100644 index 0000000..90f5b8a --- /dev/null +++ b/persistence-compile-time/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + container-playground + io.trygvis.container + 1.0-SNAPSHOT + + persistence-compile-time + + + commons-lang + commons-lang + 2.6 + + + diff --git a/pom.xml b/pom.xml index 9997562..b8e3ab6 100644 --- a/pom.xml +++ b/pom.xml @@ -27,5 +27,6 @@ container-compiler-plugin myapp container-core + persistence-compile-time -- cgit v1.2.3