diff options
Diffstat (limited to 'container-compiler-plugin/src/main/java/io/trygvis/container')
7 files changed, 199 insertions, 43 deletions
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 f9247e0..fc7ca4f 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,7 +1,10 @@ package io.trygvis.container.compiler; import io.trygvis.container.compiler.model.ClassG; +import io.trygvis.container.compiler.model.FieldRef; +import io.trygvis.container.compiler.model.ParameterRef; 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.GeneratorSupport; @@ -11,35 +14,37 @@ 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.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; +import javax.persistence.Id; import javax.tools.JavaFileObject; import java.io.PrintWriter; +import java.sql.Connection; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import static io.trygvis.container.compiler.Utils.toFieldName; import static io.trygvis.persistence.FieldMirror.PrimitiveFieldMirror; import static java.lang.Character.isUpperCase; import static javax.lang.model.util.ElementFilter.fieldsIn; public class EntityHandler extends AbstractHandler { - GeneratorSupport generatorSupport = new GeneratorSupport(); + private GeneratorSupport generatorSupport = new GeneratorSupport(); + private List<EntityMirror> entities = new ArrayList<>(); + private PackageElement packageElement; public EntityHandler(ProcessingEnvironment processingEnv) { super(processingEnv); } - public void phase1(Set<? extends Element> sqlEntities) throws Exception { - System.out.println("io.trygvis.container.compiler.EntityHandler.phase1"); - for (Element entity : sqlEntities) { -// SqlEntity sqlEntity = entity.getAnnotation(SqlEntity.class); -// Class<? extends TypeHandler> typeHandlerClass = sqlEntity.value(); - + public void phase1(Set<TypeElement> sqlEntities, Set<PackageElement> packages) throws Exception { + for (TypeElement entity : sqlEntities) { AnnotationMirror sqlEntity = findAnnotation(SqlEntity.class, entity.getAnnotationMirrors()); for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> v : sqlEntity.getElementValues().entrySet()) { switch (v.getKey().getSimpleName().toString()) { @@ -53,8 +58,18 @@ public class EntityHandler extends AbstractHandler { break; } } - System.out.println("sqlEntity.getElementValues() = " + sqlEntity.getElementValues()); +// System.out.println("sqlEntity.getElementValues() = " + sqlEntity.getElementValues()); + } + + System.out.println("packages = " + packages); + if (packages.size() == 0) { + throw new RuntimeException("There has to be exactly one @SqlEntitySet annotated package."); + } + if (packages.size() != 1) { + throw new RuntimeException("There can only be one @SqlEntitySet annotated package."); } + + packageElement = packages.iterator().next(); } private AnnotationMirror findAnnotation(Class<?> c, List<? extends AnnotationMirror> annotations) { @@ -69,49 +84,103 @@ public class EntityHandler extends AbstractHandler { } public void processEntity(TypeElement element) throws Exception { - EntityMirror entityMirror = new EntityMirror(generatorSupport, element.asType(), sqlName(element.getSimpleName().toString())); + DeclaredType declaredType = types.getDeclaredType(element); + EntityMirror entityMirror = new EntityMirror(generatorSupport, declaredType, sqlName(element.getSimpleName().toString())); for (VariableElement f : fieldsIn(elements.getAllMembers(element))) { entityMirror.add(fromElement(generatorSupport, f)); } + List<FieldMirror> idFields = new ArrayList<>(); + for (FieldMirror field : entityMirror.fields) { + if (field.id) { + idFields.add(field); + } + } + + if (idFields.size() == 0) { + throw new RuntimeException("An @Entity is required to have at least one @Id field."); + } + if (idFields.size() != 1) { + throw new RuntimeException("This implementation only support a single @Id annotated field."); + } + String p = elements.getPackageOf(element).getQualifiedName().toString(); - String className = element.getSimpleName() + "_Sql"; - ClassG g = new ClassG(p, className, null); - g.addPublicFinalField(String.class, "insertIntoSql"); + ClassG g = new ClassG(p, entityMirror.daoName); String insertInto = entityMirror.insertIntoSql(); - List<String> body = new ArrayList<>(); - body.add("this.insertIntoSql = \"" + insertInto + "\";"); - g.addConstructor(new Parameters(), body); + g.addPublicStaticFinalField(String.class, "insertIntoSql").value("\"" + insertInto + "\""); +// List<String> body = new ArrayList<>(); +// body.add("this.insertIntoSql = \"" + insertInto + "\";"); +// g.addConstructor(new Parameters(), body); entityMirror.insertInto(g); - String fileName = (p.length() == 0 ? "" : p + ".") + className; + String fileName = (p.length() == 0 ? "" : p + ".") + entityMirror.daoName; JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(fileName, element); try (PrintWriter w = new PrintWriter(sourceFile.openWriter())) { g.write(w); } + + entities.add(entityMirror); } public FieldMirror fromElement(GeneratorSupport generatorSupport, VariableElement var) { - System.out.print("element = "); TypeMirror type = var.asType(); - elements.printElements(new PrintWriter(System.out), var); +// System.out.print("element = "); +// elements.printElements(new PrintWriter(System.out), var); String javaName = var.getSimpleName().toString(); String sqlName = sqlName(javaName); boolean notNull = false; FieldMirror field; + boolean id = isId(var); if (generatorSupport.isPrimitive(type)) { - field = new PrimitiveFieldMirror(var, javaName, sqlName, notNull); + field = new PrimitiveFieldMirror(var, javaName, sqlName, id, notNull); } else if (generatorSupport.hasTypeHandler(type)) { + if (id) { + throw new RuntimeException("A @Id field has to be a primitive or embedded."); + } + field = new FieldMirror.ReferenceFieldMirror(var, javaName, sqlName, notNull); } else { throw new RuntimeException("Missing type handler for type: " + type); } - System.out.println("field = " + field); +// System.out.println("field = " + field); return field; } + public static boolean isId(VariableElement var) { + return var.getAnnotation(Id.class) != null; + } + + public void phase3() throws Exception { + String p = packageElement.getQualifiedName().toString(); + + // TODO: Support a name prefix from @SqlEntitySet + String className = "Daos"; + + String fileName = (p.length() == 0 ? "" : p + ".") + className; + ClassG g = new ClassG(p, className); + +/* + TypeRef conType = g.addImport(Connection.class); + Parameters parameters = new Parameters(); + ParameterRef c = parameters.addParameter(conType, "c"); + + List<String> 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); +*/ + + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(fileName, packageElement); + try (PrintWriter w = new PrintWriter(sourceFile.openWriter())) { + g.write(w); + } + } + public static String sqlName(String javaName) { StringBuilder builder = new StringBuilder(); for (char c : javaName.toCharArray()) { 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 735d688..43ba49e 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 @@ -2,6 +2,7 @@ package io.trygvis.container.compiler; import io.trygvis.container.log.Log; import io.trygvis.persistence.SqlEntity; +import io.trygvis.persistence.SqlEntitySet; import org.springframework.transaction.annotation.Transactional; import javax.annotation.processing.Completion; @@ -12,8 +13,10 @@ import javax.lang.model.SourceVersion; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.persistence.Entity; @@ -23,6 +26,7 @@ import java.util.Set; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; +import static javax.lang.model.util.ElementFilter.typesIn; public class MyProcessor implements Processor { @@ -57,13 +61,14 @@ public class MyProcessor implements Processor { return new HashSet<>(asList( Transactional.class.getName(), Log.class.getName(), - Entity.class.getName())); + Entity.class.getName(), + SqlEntitySet.class.getName())); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { try { - return work(annotations, roundEnv); + return work(roundEnv); } catch (RuntimeException e) { throw e; } catch (Exception e) { @@ -71,18 +76,25 @@ public class MyProcessor implements Processor { } } - public boolean work(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) throws Exception { + boolean first = true; + public boolean work(RoundEnvironment roundEnv) throws Exception { + if (!first) { + return false; + } + first = false; + 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<? extends Element> sqlEntities = roundEnv.getElementsAnnotatedWith(SqlEntity.class); - entityHandler.phase1(sqlEntities); + Set<TypeElement> sqlEntities = typesIn(roundEnv.getElementsAnnotatedWith(SqlEntity.class)); + Set<PackageElement> packages = ElementFilter.packagesIn(roundEnv.getElementsAnnotatedWith(SqlEntitySet.class)); + entityHandler.phase1(sqlEntities, packages); for (Element element : roundEnv.getRootElements()) { - System.out.println("Processing: " + element); + System.out.println("Processing: " + element.asType()); for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { DeclaredType annotationType = annotationMirror.getAnnotationType(); @@ -97,6 +109,9 @@ public class MyProcessor implements Processor { } } } + + entityHandler.phase3(); + return true; } } 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 new file mode 100644 index 0000000..8bd0de3 --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/Utils.java @@ -0,0 +1,31 @@ +package io.trygvis.container.compiler; + +import static java.lang.Character.toLowerCase; +import static java.lang.Character.toUpperCase; + +public class Utils { + public static String toFieldName(String s) { + if (s.length() < 1) { + return s.toLowerCase(); + } + char[] chars = s.toCharArray(); + + boolean toUpper = false; + + int j = 0; + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (c == '_') { + toUpper = true; + } else { + if (j == 0) { + chars[j++] = toLowerCase(c); + } else { + chars[j++] = toUpper ? toUpperCase(c) : c; + } + toUpper = false; + } + } + return new String(chars, 0, j); + } +} 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 8ff91a0..6bfd0be 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 @@ -8,6 +8,7 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; +import static java.lang.reflect.Modifier.*; import static org.springframework.util.StringUtils.collectionToDelimitedString; public class ClassG { @@ -19,6 +20,10 @@ public class ClassG { private final List<MethodRef> methods = new ArrayList<>(); private final List<Constructor> constructors = new ArrayList<>(); + public ClassG(String packageName, String className) { + this(packageName, className, null); + } + public ClassG(String packageName, String className, String extendsClass) { this.packageName = packageName; this.className = className; @@ -64,20 +69,32 @@ public class ClassG { return ref; } - public FieldRef addField(Class<?> klass, String name) { + public FieldRef addField(TypeMirror klass, String name) { TypeRef type = addImport(klass); - FieldRef ref = new FieldRef(Modifier.PRIVATE | Modifier.FINAL, type, name); + FieldRef ref = new FieldRef(PRIVATE | FINAL, type, name); fields.add(ref); return ref; } - public FieldRef addPublicFinalField(Class<?> klass, String name) { + public FieldRef addField(int modifiers, Class<?> klass, String name) { TypeRef type = addImport(klass); - FieldRef ref = new FieldRef(Modifier.PUBLIC | Modifier.FINAL, type, name); + FieldRef ref = new FieldRef(modifiers, type, name); fields.add(ref); return ref; } + public FieldRef addField(Class<?> klass, String name) { + return addField(PRIVATE | FINAL, klass, name); + } + + public FieldRef addPublicFinalField(Class<?> klass, String name) { + return addField(PUBLIC | FINAL, klass, name); + } + + public FieldRef addPublicStaticFinalField(Class<?> klass, String name) { + return addField(PUBLIC | STATIC | FINAL, klass, name); + } + public Constructor addConstructor(Parameters parameters, List<String> body) { Constructor constructor = new Constructor(this, parameters, body); constructors.add(constructor); @@ -85,13 +102,19 @@ public class ClassG { } public MethodRef addMethod(List<String> body, TypeRef returnType, String name, ParameterRef... parameters) { - MethodRef ref = new MethodRef(returnType, name, parameters, body); + MethodRef ref = new MethodRef(PUBLIC, returnType, name, parameters, body); + methods.add(ref); + return ref; + } + + public MethodRef addStaticMethod(List<String> body, TypeRef returnType, String name, ParameterRef... parameters) { + MethodRef ref = new MethodRef(PUBLIC | STATIC, returnType, name, parameters, body); methods.add(ref); return ref; } public void write(PrintWriter writer) { - if(packageName.length() > 0) { + if (packageName.length() > 0) { writer.println("package " + packageName + ";"); writer.println(); } @@ -99,12 +122,14 @@ public class ClassG { if (i.isPrimitive()) { continue; } - if(i.canonicalName().indexOf('.') == -1) { + if (i.canonicalName().indexOf('.') == -1) { continue; } writer.println("import " + i.canonicalName() + ";"); } - writer.println(); + if (!imports.isEmpty()) { + writer.println(); + } String extendsString = extendsClass == null ? "" : " extends " + extendsClass; @@ -143,19 +168,17 @@ public class ClassG { } writer.print(" public " + returnString + " " + method.name + "(" + collectionToDelimitedString(parameters, ", ") + ")"); - if(method.exceptions.isEmpty()) { + if (method.exceptions.isEmpty()) { writer.println(" {"); - } - else { + } else { writer.println(" throws"); ArrayList<TypeRef> 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) { + if (i < typeRefs.size() - 1) { writer.println(","); - } - else { + } else { writer.println(" {"); } } diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/FieldRef.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/FieldRef.java index c6b81a0..64bf032 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/FieldRef.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/FieldRef.java @@ -6,6 +6,7 @@ public class FieldRef implements Comparable<FieldRef> { public final int modifiers; public final TypeRef klass; public final String name; + public String value; public FieldRef(int modifiers, TypeRef klass, String name) { this.modifiers = modifiers; @@ -14,7 +15,11 @@ public class FieldRef implements Comparable<FieldRef> { } public String toJava() { - return Modifier.toString(modifiers) + " " + klass.name + " " + name; + String s = Modifier.toString(modifiers) + " " + klass.name + " " + name; + if (value != null) { + s += " = " + value; + } + return s; } @Override @@ -36,4 +41,8 @@ public class FieldRef implements Comparable<FieldRef> { public int compareTo(FieldRef o) { return name.compareTo(o.name); } + + public void value(String value) { + this.value = value; + } } 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 a59e9a6..ee83fa9 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,5 +1,6 @@ package io.trygvis.container.compiler.model; +import java.lang.reflect.Modifier; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -9,15 +10,21 @@ import static java.util.Collections.addAll; public class MethodRef { public final TypeRef returnType; public final String name; + public final int modifiers; public final ParameterRef[] parameters; public final Set<TypeRef> exceptions = new TreeSet<>(); public final List<String> body; - public MethodRef(TypeRef returnType, String name, ParameterRef[] parameters, List<String> body) { + public MethodRef(int modifiers, TypeRef returnType, String name, ParameterRef[] parameters, List<String> body) { + this.modifiers = modifiers; this.returnType = returnType; this.name = name; this.parameters = parameters; this.body = body; + + if ((Modifier.methodModifiers() & modifiers) != modifiers) { + throw new RuntimeException("Invalid modifiers for method: " + Modifier.toString(modifiers)); + } } public MethodRef exception(TypeRef... exceptions) { diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Parameters.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Parameters.java index 7c1ab5b..cfd29f9 100644 --- a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Parameters.java +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Parameters.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.ListIterator; public class Parameters implements Iterable<ParameterRef> { + public static final Parameters noParameters = new Parameters(); + private final List<ParameterRef> parameters = new ArrayList<>(); public ParameterRef addParameter(TypeRef klass, String name) { |