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.TypeRef; import io.trygvis.container.log.Log; import io.trygvis.container.tx.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; import javax.annotation.processing.Completion; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; 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.Modifier; import javax.lang.model.element.Name; 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.CharArrayWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.List; 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.constructorsIn; import static org.springframework.util.StringUtils.collectionToDelimitedString; public class MyProcessor implements Processor { private ProcessingEnvironment processingEnv; private Elements elements; private Types types; @Override public Set getSupportedOptions() { return emptySet(); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.RELEASE_5; } @Override public void init(ProcessingEnvironment processingEnv) { this.processingEnv = processingEnv; elements = processingEnv.getElementUtils(); types = processingEnv.getTypeUtils(); } @Override public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { return emptyList(); } @Override public Set getSupportedAnnotationTypes() { return new HashSet<>(asList(Transactional.class.getName(), Log.class.getName())); } @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { Set transactional = roundEnv.getElementsAnnotatedWith(Transactional.class); TypeElement tx = elements.getTypeElement(Transactional.class.getCanonicalName()); TypeElement log = elements.getTypeElement(Transactional.class.getCanonicalName()); for (Element element : transactional) { try { System.out.println("Processing: " + element); for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { System.out.println("annotationMirror.getAnnotationType().asElement().getSimpleName() = " + annotationMirror.getAnnotationType().asElement().getSimpleName()); if (types.isSameType(tx.asType(), annotationMirror.getAnnotationType())) { processTransactional((TypeElement) element); } // if (types.isSameType(log.asType(), annotationMirror.getAnnotationType())) { // processLog((TypeElement) element); // } } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } return true; } private void processTransactional(TypeElement element) throws IOException { Name targetClassName = element.getSimpleName(); System.out.println("Processing @Transactional " + targetClassName); 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()); // writer.println("package " + p + ";"); // writer.println(); // writer.println("import io.trygvis.container.tx.PlatformTransactionManager;"); // writer.println(); // writer.println("public class " + className + " extends " + targetClassName + " {"); // writer.println(" private final PlatformTransactionManager transactionManager;"); // writer.println(); TypeRef platformTransactionManager = g.addImport(PlatformTransactionManager.class); FieldRef transactionManager = g.addField(PlatformTransactionManager.class, "transactionManager"); for (ExecutableElement constructor : constructorsIn(elements.getAllMembers(element))) { if (!constructor.getModifiers().contains(Modifier.PUBLIC)) { continue; } constructor(g, constructor); } // System.out.println("elements.getTypeElement(\"Object\") = " + elements.getTypeElement("java.lang.Object")); Name javaLangObjectName = elements.getTypeElement("java.lang.Object").getQualifiedName(); for (Element e : elements.getAllMembers(element)) { if (!(e instanceof ExecutableElement)) { continue; } ExecutableElement ee = (ExecutableElement) e; TypeElement enclosingElement = (TypeElement) ee.getEnclosingElement(); if (enclosingElement.getQualifiedName().equals(javaLangObjectName)) { continue; } if (ee.getSimpleName().toString().equals("")) { continue; } // System.out.println("ee.getSimpleName() = " + ee.getSimpleName()); // System.out.println("ee.getEnclosingElement() = " + enclosingElement); // System.out.println("ee.getEnclosingElement().getQualifiedName() = " + enclosingElement.getQualifiedName()); // System.out.println("ee.getEnclosingElement().asType().getKind().getDeclaringClass() = " + enclosingElement.asType().getKind().getDeclaringClass()); TypeMirror returnTypeMirror = ee.getReturnType(); TypeKind kind = returnTypeMirror.getKind(); boolean isVoid = kind == TypeKind.VOID; TypeRef returnType = isVoid ? TypeRef.VOID : g.addImport(returnTypeMirror); // String returnString; // if (isVoid) { // returnString = "void"; // } else { // returnString = returnTypeMirror.toString(); // } 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()); } CharArrayWriter buffer = new CharArrayWriter(); PrintWriter m = new PrintWriter(buffer); g.addMethod(buffer.toString(), returnType, ee.getSimpleName().toString(), parameters.toArray(new ParameterRef[arguments.size()])); // writer.println(); // writer.println(" public " + returnString + " " + ee.getSimpleName() + "(" + collectionToDelimitedString(parameters, ", ") + ") {"); /* writer.println(" " + (isVoid ? "" : "return ") + "transactionManager.doInTransaction("); writer.println(" PlatformTransactionManager.TransactionIsolation.ISOLATION_" + transactional.isolation() + ","); writer.println(" PlatformTransactionManager.TransactionPropagation.PROPAGATION_" + transactional.propagation() + ","); writer.println(" new PlatformTransactionManager.TransactionTemplate<" + (isVoid ? "Object" : returnTypeMirror) + ">() {"); writer.println(" @Override"); writer.println(" public " + (isVoid ? "Object" : returnTypeMirror) + " doInTransaction() {"); String targetInvocation = className + ".super." + ee.getSimpleName() + "(" + collectionToDelimitedString(arguments, ", ") + ");"; if (isVoid) { writer.println(" " + targetInvocation); writer.println(" return null;"); } else { writer.print(" return "); writer.println(targetInvocation); } writer.println(" }"); writer.println(" });"); writer.println(" }"); */ elements.printElements(new PrintWriter(System.out), ee); } // writer.println("}"); g.write(w); } } private void constructor(ClassG g, ExecutableElement constructor) { List parameters = new ArrayList<>(); List goesToSuper = new ArrayList<>(); TypeRef k = g.addImport(PlatformTransactionManager.class); parameters.add(new ParameterRef(k, "_transactionManager_")); for (VariableElement p : constructor.getParameters()) { // parameters.add(p.asType().toString() + " " + p.getSimpleName().toString()); // arguments.add(p.getSimpleName().toString()); k = g.addImport(p.asType()); String name = p.getSimpleName().toString(); parameters.add(new ParameterRef(k, name)); goesToSuper.add(name); } // String params = parameters.size() == 0 ? "" : ", " + collectionToDelimitedString(parameters, ", "); g.simpleConstructor(parameters, goesToSuper); // writer.println(" public " + className + "(PlatformTransactionManager _transactionManager_" + params + ") {"); // writer.println(" super(" + collectionToDelimitedString(arguments, ", ") + ");"); // writer.println(" this.transactionManager = _transactionManager_;"); // writer.println(" }"); } }