From 4e794b5ed03e5020770becb068d11e6838feec64 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 2 Aug 2013 21:57:54 +0200 Subject: wip --- container-compiler-plugin/pom.xml | 25 ++++ .../container/compiler/AbstractHandler.java | 17 +++ .../trygvis/container/compiler/EntityHandler.java | 83 ++++++++++++++ .../io/trygvis/container/compiler/MyProcessor.java | 31 +++-- .../container/compiler/TransactionalHandler.java | 126 ++++++++++----------- .../container/compiler/entity/EntityMirror.java | 38 +++++++ .../trygvis/container/compiler/model/ClassG.java | 27 +++-- .../trygvis/container/compiler/model/FieldRef.java | 10 +- .../container/compiler/EntityHandlerTest.java | 27 +++++ .../compiler/InMemoryJavaFileManager.java | 74 ++++++++++++ .../trygvis/container/compiler/ProcessorTest.java | 83 ++++++++++++++ .../src/test/resources/Car.java | 6 + .../src/test/resources/Person.java | 26 +++++ container-core/pom.xml | 5 + .../java/io/trygvis/container/myapp/MyEntity.java | 10 ++ 15 files changed, 504 insertions(+), 84 deletions(-) create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/container/compiler/AbstractHandler.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/container/compiler/EntityHandler.java create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/container/compiler/entity/EntityMirror.java create mode 100644 container-compiler-plugin/src/test/java/io/trygvis/container/compiler/EntityHandlerTest.java create mode 100644 container-compiler-plugin/src/test/java/io/trygvis/container/compiler/InMemoryJavaFileManager.java create mode 100644 container-compiler-plugin/src/test/java/io/trygvis/container/compiler/ProcessorTest.java create mode 100644 container-compiler-plugin/src/test/resources/Car.java create mode 100644 container-compiler-plugin/src/test/resources/Person.java create mode 100644 myapp/src/main/java/io/trygvis/container/myapp/MyEntity.java diff --git a/container-compiler-plugin/pom.xml b/container-compiler-plugin/pom.xml index beb4b55..f48d8fc 100644 --- a/container-compiler-plugin/pom.xml +++ b/container-compiler-plugin/pom.xml @@ -15,5 +15,30 @@ container-core ${project.version} + + org.easytesting + fest-assert + 1.4 + + + org.testng + testng + 6.8.5 + test + + + + commons-io + commons-io + 2.4 + test + diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/AbstractHandler.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/AbstractHandler.java new file mode 100644 index 0000000..0a558ea --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/AbstractHandler.java @@ -0,0 +1,17 @@ +package io.trygvis.container.compiler; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +public abstract class AbstractHandler { + protected final ProcessingEnvironment processingEnv; + protected final Elements elements; + protected final Types types; + + public AbstractHandler(ProcessingEnvironment processingEnv) { + this.processingEnv = processingEnv; + this.elements = processingEnv.getElementUtils(); + this.types = processingEnv.getTypeUtils(); + } +} 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 new file mode 100644 index 0000000..df7a673 --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/EntityHandler.java @@ -0,0 +1,83 @@ +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 javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.tools.JavaFileObject; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import static io.trygvis.container.compiler.entity.EntityMirror.FieldMirror; +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 { + public EntityHandler(ProcessingEnvironment processingEnv) { + super(processingEnv); + } + + public void processEntity(TypeElement element) throws Exception { + EntityMirror entityMirror = new EntityMirror(sqlName(element.getSimpleName().toString())); + + for (VariableElement f : fieldsIn(elements.getAllMembers(element))) { + entityMirror.add(fromElement(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); + List body = new ArrayList<>(); + body.add("this.insertInto = \"" + insertInto + "\";"); + g.addConstructor(new Parameters(), body); + + String fileName = (p.length() == 0 ? "" : p + ".") + className; + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(fileName, element); + try (PrintWriter w = new PrintWriter(sourceFile.openWriter())) { + g.write(w); + } + } + + 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"); + 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 = new FieldMirror(javaName, sqlName, notNull); + System.out.println("field = " + field); + return field; + } + + public static String sqlName(String javaName) { + StringBuilder builder = new StringBuilder(); + for (char c : javaName.toCharArray()) { + char lower = Character.toLowerCase(c); + if(isUpperCase(c) && builder.length() > 0) { + builder.append("_"); + } + builder.append(lower); + } + return builder.toString(); + } +} 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 729a0ee..6843659 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 @@ -12,8 +12,10 @@ import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; +import javax.persistence.Entity; import java.util.HashSet; import java.util.Set; @@ -29,16 +31,19 @@ public class MyProcessor implements Processor { @Override public Set getSupportedOptions() { + System.out.println("io.trygvis.container.compiler.MyProcessor.getSupportedOptions"); return emptySet(); } @Override public SourceVersion getSupportedSourceVersion() { - return SourceVersion.RELEASE_5; + 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(); @@ -46,32 +51,44 @@ 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() { - return new HashSet<>(asList(Transactional.class.getName(), Log.class.getName())); + System.out.println("io.trygvis.container.compiler.MyProcessor.getSupportedAnnotationTypes"); + return new HashSet<>(asList( + Transactional.class.getName(), + Log.class.getName(), + Entity.class.getName())); } @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - Set transactional = roundEnv.getElementsAnnotatedWith(Transactional.class); + System.out.println("io.trygvis.container.compiler.MyProcessor.process"); + System.out.println("annotations = " + annotations); +// Set transactional = roundEnv.getElementsAnnotatedWith(Transactional.class); TypeElement tx = elements.getTypeElement(Transactional.class.getCanonicalName()); - TypeElement log = elements.getTypeElement(Transactional.class.getCanonicalName()); + TypeElement log = elements.getTypeElement(Log.class.getCanonicalName()); + TypeElement entity = elements.getTypeElement(Entity.class.getCanonicalName()); - for (Element element : transactional) { + 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(), annotationMirror.getAnnotationType())) { + if (types.isSameType(tx.asType(), annotationType)) { new TransactionalHandler(processingEnv).processTransactional((TypeElement) element); } - if (types.isSameType(log.asType(), annotationMirror.getAnnotationType())) { + if (types.isSameType(log.asType(), annotationType)) { new LogHandler(processingEnv).processLog((TypeElement) element); } + if (types.isSameType(entity.asType(), annotationType)) { + new EntityHandler(processingEnv).processEntity((TypeElement) element); + } } } catch (RuntimeException e) { throw e; 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 2877e15..d24a697 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 @@ -17,8 +17,6 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; import javax.tools.JavaFileObject; import java.io.IOException; import java.io.PrintWriter; @@ -28,16 +26,10 @@ import java.util.List; import static javax.lang.model.util.ElementFilter.constructorsIn; import static org.springframework.util.StringUtils.collectionToDelimitedString; -public class TransactionalHandler { - - private final ProcessingEnvironment processingEnv; - private final Elements elements; - private final Types types; +public class TransactionalHandler extends AbstractHandler { public TransactionalHandler(ProcessingEnvironment processingEnv) { - this.processingEnv = processingEnv; - this.elements = processingEnv.getElementUtils(); - this.types = processingEnv.getTypeUtils(); + super(processingEnv); } public void processTransactional(TypeElement element) throws IOException { @@ -46,80 +38,80 @@ public class TransactionalHandler { Transactional transactional = element.getAnnotation(Transactional.class); - String p = elements.getPackageOf(element).getQualifiedName().toString(); - String className = targetClassName + "_Transactional"; - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(p + "." + className, element); - - try (PrintWriter w = new PrintWriter(sourceFile.openWriter())) { - ClassG g = new ClassG(p, className, targetClassName.toString()); - FieldRef transactionManager = g.addField(PlatformTransactionManager.class, "transactionManager"); + String p = elements.getPackageOf(element).getQualifiedName().toString(); - for (ExecutableElement constructor : constructorsIn(elements.getAllMembers(element))) { - if (!constructor.getModifiers().contains(Modifier.PUBLIC)) { - continue; - } + ClassG g = new ClassG(p, className, targetClassName.toString()); + FieldRef transactionManager = g.addField(PlatformTransactionManager.class, "transactionManager"); - constructor(g, constructor, transactionManager); + for (ExecutableElement constructor : constructorsIn(elements.getAllMembers(element))) { + if (!constructor.getModifiers().contains(Modifier.PUBLIC)) { + continue; } - Name javaLangObjectName = elements.getTypeElement("java.lang.Object").getQualifiedName(); + constructor(g, constructor, transactionManager); + } + + Name javaLangObjectName = elements.getTypeElement("java.lang.Object").getQualifiedName(); - for (Element e : elements.getAllMembers(element)) { - if (!(e instanceof ExecutableElement)) { - continue; - } + for (Element e : elements.getAllMembers(element)) { + if (!(e instanceof ExecutableElement)) { + continue; + } - ExecutableElement ee = (ExecutableElement) e; + ExecutableElement ee = (ExecutableElement) e; - TypeElement enclosingElement = (TypeElement) ee.getEnclosingElement(); + TypeElement enclosingElement = (TypeElement) ee.getEnclosingElement(); - if (enclosingElement.getQualifiedName().equals(javaLangObjectName)) { - continue; - } + if (enclosingElement.getQualifiedName().equals(javaLangObjectName)) { + continue; + } - if (ee.getSimpleName().toString().equals("")) { - continue; - } + if (ee.getSimpleName().toString().equals("")) { + continue; + } - TypeMirror returnTypeMirror = ee.getReturnType(); + TypeMirror returnTypeMirror = ee.getReturnType(); - TypeKind kind = returnTypeMirror.getKind(); + TypeKind kind = returnTypeMirror.getKind(); - boolean isVoid = kind == TypeKind.VOID; - TypeRef returnType = isVoid ? TypeRef.VOID : g.addImport(returnTypeMirror); + boolean isVoid = kind == TypeKind.VOID; + TypeRef returnType = isVoid ? TypeRef.VOID : g.addImport(returnTypeMirror); - List parameters = new ArrayList<>(); - List arguments = new ArrayList<>(); - for (VariableElement ve : ee.getParameters()) { + List parameters = new ArrayList<>(); + List arguments = new ArrayList<>(); + for (VariableElement ve : ee.getParameters()) { // parameters.add("final " + ve.asType().toString() + " " + ve.getSimpleName().toString()); - TypeRef k = g.addImport(ve.asType()); - parameters.add(new ParameterRef(k, ve.getSimpleName().toString())); - arguments.add(ve.getSimpleName().toString()); - } - - List body = new ArrayList<>(); - body.add((isVoid ? "" : "return ") + "transactionManager.doInTransaction("); - body.add(" PlatformTransactionManager.TransactionIsolation.ISOLATION_" + transactional.isolation() + ","); - body.add(" PlatformTransactionManager.TransactionPropagation.PROPAGATION_" + transactional.propagation() + ","); - body.add(" new PlatformTransactionManager.TransactionTemplate<" + (isVoid ? "Object" : returnTypeMirror) + ">() {"); - body.add(" @Override"); - body.add(" public " + (isVoid ? "Object" : returnTypeMirror) + " doInTransaction() {"); - String targetInvocation = className + ".super." + ee.getSimpleName() + "(" + collectionToDelimitedString(arguments, ", ") + ");"; - - if (isVoid) { - body.add(" " + targetInvocation); - body.add(" return null;"); - } else { - body.add(" return " + targetInvocation); - } - - body.add(" }"); - body.add(" });"); - - g.addMethod(body, returnType, ee.getSimpleName().toString(), parameters.toArray(new ParameterRef[arguments.size()])); + TypeRef k = g.addImport(ve.asType()); + parameters.add(new ParameterRef(k, ve.getSimpleName().toString())); + arguments.add(ve.getSimpleName().toString()); } + + List body = new ArrayList<>(); + body.add((isVoid ? "" : "return ") + "transactionManager.doInTransaction("); + body.add(" PlatformTransactionManager.TransactionIsolation.ISOLATION_" + transactional.isolation() + ","); + body.add(" PlatformTransactionManager.TransactionPropagation.PROPAGATION_" + transactional.propagation() + ","); + body.add(" new PlatformTransactionManager.TransactionTemplate<" + (isVoid ? "Object" : returnTypeMirror) + ">() {"); + body.add(" @Override"); + body.add(" public " + (isVoid ? "Object" : returnTypeMirror) + " doInTransaction() {"); + String targetInvocation = className + ".super." + ee.getSimpleName() + "(" + collectionToDelimitedString(arguments, ", ") + ");"; + + if (isVoid) { + body.add(" " + targetInvocation); + body.add(" return null;"); + } else { + body.add(" return " + targetInvocation); + } + + body.add(" }"); + body.add(" });"); + + g.addMethod(body, returnType, ee.getSimpleName().toString(), parameters.toArray(new ParameterRef[arguments.size()])); + } + + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile((p.length() == 0 ? "" : p + ".") + className, element); + try (PrintWriter w = new PrintWriter(sourceFile.openWriter())) { g.write(w); } } 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 new file mode 100644 index 0000000..ae7077c --- /dev/null +++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/entity/EntityMirror.java @@ -0,0 +1,38 @@ +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 13e1b03..cf68cba 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 @@ -2,6 +2,7 @@ package io.trygvis.container.compiler.model; import javax.lang.model.type.TypeMirror; import java.io.PrintWriter; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -18,10 +19,6 @@ public class ClassG { private final List methods = new ArrayList<>(); private final List 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; @@ -74,7 +71,14 @@ public class ClassG { public FieldRef addField(Class klass, String name) { TypeRef type = addImport(klass); - FieldRef ref = new FieldRef(type, name); + FieldRef ref = new FieldRef(Modifier.PRIVATE | Modifier.FINAL, type, name); + fields.add(ref); + return ref; + } + + public FieldRef addPublicFinalField(Class klass, String name) { + TypeRef type = addImport(klass); + FieldRef ref = new FieldRef(Modifier.PUBLIC | Modifier.FINAL, type, name); fields.add(ref); return ref; } @@ -92,8 +96,10 @@ public class ClassG { } public void write(PrintWriter writer) { - writer.println("package " + packageName + ";"); - writer.println(); + if(packageName.length() > 0) { + writer.println("package " + packageName + ";"); + writer.println(); + } for (TypeRef i : imports) { if (i.isPrimitive()) { continue; @@ -101,10 +107,13 @@ public class ClassG { writer.println("import " + i.canonicalName() + ";"); } writer.println(); - writer.println("public class " + className + " extends " + extendsClass + " {"); + + String extendsString = extendsClass == null ? "" : " extends " + extendsClass; + + writer.println("public class " + className + extendsString + " {"); for (FieldRef field : fields) { writer.println(); - writer.println(" private final " + field.klass.name + " " + field.name + ";"); + writer.println(" " + field.toJava() + ";"); } for (Constructor constructor : constructors) { 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 29a2c51..c6b81a0 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 @@ -1,14 +1,22 @@ package io.trygvis.container.compiler.model; +import java.lang.reflect.Modifier; + public class FieldRef implements Comparable { + public final int modifiers; public final TypeRef klass; public final String name; - public FieldRef(TypeRef klass, String name) { + public FieldRef(int modifiers, TypeRef klass, String name) { + this.modifiers = modifiers; this.klass = klass; this.name = name; } + public String toJava() { + return Modifier.toString(modifiers) + " " + klass.name + " " + name; + } + @Override public boolean equals(Object o) { if (this == o) return true; 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 new file mode 100644 index 0000000..98fcaea --- /dev/null +++ b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/EntityHandlerTest.java @@ -0,0 +1,27 @@ +package io.trygvis.container.compiler; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static io.trygvis.container.compiler.EntityHandler.sqlName; +import static org.fest.assertions.Assertions.assertThat; + +@Test(singleThreaded = false) +public class EntityHandlerTest { + + @DataProvider(name = "sqlName", parallel = true) + public static Object[][] SqlNameDataProvider() { + return new Object[][] { + 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_"}, + }; + } + + @Test(dataProvider = "sqlName") + public void testSqlName(String input, String output) throws Exception { + assertThat(sqlName(input)).isEqualTo(output); + } +} diff --git a/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/InMemoryJavaFileManager.java b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/InMemoryJavaFileManager.java new file mode 100644 index 0000000..e476d3e --- /dev/null +++ b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/InMemoryJavaFileManager.java @@ -0,0 +1,74 @@ +package io.trygvis.container.compiler; + +import org.apache.commons.io.output.ByteArrayOutputStream; + +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import java.io.CharArrayWriter; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +public class InMemoryJavaFileManager extends ForwardingJavaFileManager { + public final Map codes = new HashMap<>(); + + public InMemoryJavaFileManager(StandardJavaFileManager standardFileManager) { + super(standardFileManager); + } + + @Override + public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + System.out.println("io.trygvis.container.compiler.InMemoryJavaFileManager.getFileForOutput"); + throw new RuntimeException(""); + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, final String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { + System.out.println("io.trygvis.container.compiler.InMemoryJavaFileManager.getJavaFileForOutput"); + return new SimpleJavaFileObject(URI.create("wat://woot/" + className.replace('.', '/') + ".java"), kind) { + String code; + + @Override + public Writer openWriter() throws IOException { + return new CharArrayWriter() { + @Override + public void close() { + super.close(); + System.out.println("Closing writer to: className = " + className); + code = super.toString(); + codes.put(className, code); + } + }; + } + + @Override + public OutputStream openOutputStream() throws IOException { + return new ByteArrayOutputStream() { + @Override + public void close() throws IOException { + super.close(); + // ignored for now +// System.out.println("Closing output stream to: className = " + className); +// System.out.println(new String(super.toByteArray())); + } + }; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + if(code == null) { + throw new FileNotFoundException(className); + } + + 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 new file mode 100644 index 0000000..e070f3c --- /dev/null +++ b/container-compiler-plugin/src/test/java/io/trygvis/container/compiler/ProcessorTest.java @@ -0,0 +1,83 @@ +package io.trygvis.container.compiler; + +import org.apache.commons.io.IOUtils; +import org.testng.annotations.Test; + +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; + +import static java.util.Collections.singletonList; +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(); + + DiagnosticCollector collector = new DiagnosticCollector<>(); + StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(collector, Locale.ENGLISH, UTF_8); + + InMemoryJavaFileManager fileManager = new InMemoryJavaFileManager(standardFileManager); + + JavaSourceFromString myEntity = new JavaSourceFromString("Person", IOUtils.toString(getClass().getResource("/Person.java"), UTF_8)); + + JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, collector, null, + null, singletonList(myEntity)); + + task.setProcessors(Arrays.asList(new MyProcessor())); + + Boolean result = task.call(); + + for (Diagnostic diagnostic : collector.getDiagnostics()) { +// System.out.println("diagnostic = " + diagnostic); + System.out.println("diagnostic.source = ->" + diagnostic.getSource().getName() + "<-"); + System.out.println("diagnostic.message = " + diagnostic.getMessage(Locale.ENGLISH)); + } + + assertThat(collector.getDiagnostics()).isEmpty(); + 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/resources/Car.java b/container-compiler-plugin/src/test/resources/Car.java new file mode 100644 index 0000000..5661bc2 --- /dev/null +++ b/container-compiler-plugin/src/test/resources/Car.java @@ -0,0 +1,6 @@ +import javax.persistence.Entity; + +@Entity +public class Car { + private int year; +} diff --git a/container-compiler-plugin/src/test/resources/Person.java b/container-compiler-plugin/src/test/resources/Person.java new file mode 100644 index 0000000..740b42d --- /dev/null +++ b/container-compiler-plugin/src/test/resources/Person.java @@ -0,0 +1,26 @@ +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 +public class Person { + @Id + private Long id; + + private Date birthDate; + + @ManyToOne + private Person mother; + + @ManyToOne + private Person father; + + @OneToMany(mappedBy = "id") + @OrderBy("birthDate asc") + private List children = new ArrayList<>(); +} diff --git a/container-core/pom.xml b/container-core/pom.xml index e16c761..d17a86a 100644 --- a/container-core/pom.xml +++ b/container-core/pom.xml @@ -18,6 +18,11 @@ spring-beans ${version.spring} + + org.hibernate.javax.persistence + hibernate-jpa-2.0-api + 1.0.1.Final + org.springframework spring-jdbc diff --git a/myapp/src/main/java/io/trygvis/container/myapp/MyEntity.java b/myapp/src/main/java/io/trygvis/container/myapp/MyEntity.java new file mode 100644 index 0000000..5eeface --- /dev/null +++ b/myapp/src/main/java/io/trygvis/container/myapp/MyEntity.java @@ -0,0 +1,10 @@ +package io.trygvis.container.myapp; + +import javax.persistence.Entity; + +@Entity +public class MyEntity { + public Long id; + + public String name; +} -- cgit v1.2.3