From 35330309221b7c39adf71f508190628459ad7138 Mon Sep 17 00:00:00 2001
From: Trygve Laugstøl <trygvis@inamo.no>
Date: Fri, 2 Aug 2013 02:48:11 +0200
Subject: wip

---
 .../io/trygvis/container/compiler/MyProcessor.java | 162 +-----------------
 .../container/compiler/TransactionalHandler.java   | 182 +++++++++++++++++++++
 .../trygvis/container/compiler/model/ClassG.java   |  56 +++----
 .../container/compiler/model/Constructor.java      |  38 +++++
 .../container/compiler/model/MethodRef.java        |   6 +-
 .../container/compiler/model/Parameters.java       |  33 +++-
 6 files changed, 279 insertions(+), 198 deletions(-)
 create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java
 create mode 100644 container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Constructor.java

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 0ec7001..4873e9b 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,11 +1,6 @@
 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;
@@ -16,28 +11,15 @@ 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 {
 
@@ -87,7 +69,7 @@ public class MyProcessor implements Processor {
                     System.out.println("annotationMirror.getAnnotationType().asElement().getSimpleName() = " + annotationMirror.getAnnotationType().asElement().getSimpleName());
 
                     if (types.isSameType(tx.asType(), annotationMirror.getAnnotationType())) {
-                        processTransactional((TypeElement) element);
+                        new TransactionalHandler(processingEnv).processTransactional((TypeElement) element);
                     }
 //                    if (types.isSameType(log.asType(), annotationMirror.getAnnotationType())) {
 //                        processLog((TypeElement) element);
@@ -101,146 +83,4 @@ public class MyProcessor implements Processor {
         }
         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("<init>")) {
-                    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<ParameterRef> parameters = new ArrayList<>();
-                List<String> 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<ParameterRef> parameters = new ArrayList<>();
-        List<String> 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("    }");
-    }
 }
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
new file mode 100644
index 0000000..f1f3bc5
--- /dev/null
+++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java
@@ -0,0 +1,182 @@
+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.container.tx.PlatformTransactionManager;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.processing.ProcessingEnvironment;
+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.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+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 TransactionalHandler(ProcessingEnvironment processingEnv) {
+        this.processingEnv = processingEnv;
+        this.elements = processingEnv.getElementUtils();
+        this.types = processingEnv.getTypeUtils();
+    }
+
+    public 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, transactionManager);
+            }
+
+//            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("<init>")) {
+                    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<ParameterRef> parameters = new ArrayList<>();
+                List<String> 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<String> body = new ArrayList<>();
+
+//                writer.println();
+//                writer.println("    public " + returnString + " " + ee.getSimpleName() + "(" + collectionToDelimitedString(parameters, ", ") + ") {");
+
+                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()]));
+//                elements.printElements(new PrintWriter(System.out), ee);
+            }
+//            writer.println("}");
+            g.write(w);
+        }
+    }
+
+    private void constructor(ClassG g, ExecutableElement constructor, FieldRef platformTransactionManager) {
+        Parameters parameters = new Parameters();
+        List<String> goesToSuper = new ArrayList<>();
+
+        TypeRef k = g.addImport(PlatformTransactionManager.class);
+        ParameterRef transactionManager = parameters.addParameter(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.addParameter(k, name);
+            goesToSuper.add(name);
+        }
+
+//        String params = parameters.size() == 0 ? "" : ", " + collectionToDelimitedString(parameters, ", ");
+
+        List<String> body = new ArrayList<>();
+        body.add("super(" + collectionToDelimitedString(goesToSuper, ", ") + ");");
+        body.add("this." + platformTransactionManager.name + " = " + transactionManager.name + ";");
+        g.addConstructor(parameters, body);
+
+//        writer.println("    public " + className + "(PlatformTransactionManager _transactionManager_" + params + ") {");
+//        writer.println("        super(" + collectionToDelimitedString(arguments, ", ") + ");");
+//        writer.println("        this.transactionManager = _transactionManager_;");
+//        writer.println("    }");
+    }
+}
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 6c0e246..13e1b03 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
@@ -1,7 +1,6 @@
 package io.trygvis.container.compiler.model;
 
 import javax.lang.model.type.TypeMirror;
-import java.io.CharArrayWriter;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -12,11 +11,12 @@ import static org.springframework.util.StringUtils.collectionToDelimitedString;
 
 public class ClassG {
     private final String packageName;
-    private final String className;
+    public final String className;
     private final String extendsClass;
     private final Set<TypeRef> imports = new TreeSet<>();
     private final Set<FieldRef> fields = new TreeSet<>();
     private final List<MethodRef> methods = new ArrayList<>();
+    private final List<Constructor> constructors = new ArrayList<>();
 
 //    public ClassG(String packageName, String className) {
 //        this(packageName, className, null);
@@ -79,7 +79,13 @@ public class ClassG {
         return ref;
     }
 
-    public MethodRef addMethod(String body, TypeRef returnType, String name, ParameterRef... parameters) {
+    public Constructor addConstructor(Parameters parameters, List<String> body) {
+        Constructor constructor = new Constructor(this, parameters, body);
+        constructors.add(constructor);
+        return constructor;
+    }
+
+    public MethodRef addMethod(List<String> body, TypeRef returnType, String name, ParameterRef... parameters) {
         MethodRef ref = new MethodRef(returnType, name, parameters, body);
         methods.add(ref);
         return ref;
@@ -97,10 +103,19 @@ public class ClassG {
         writer.println();
         writer.println("public class " + className + " extends " + extendsClass + " {");
         for (FieldRef field : fields) {
+            writer.println();
             writer.println("    private final " + field.klass.name + " " + field.name + ";");
         }
 
+        for (Constructor constructor : constructors) {
+            writer.println();
+            for (String s : constructor.write()) {
+                writer.println(s);
+            }
+        }
+
         for (MethodRef method : methods) {
+            writer.println();
             write(writer, method);
         }
 
@@ -117,40 +132,13 @@ public class ClassG {
 
         List<String> parameters = new ArrayList<>();
         for (ParameterRef p : method.parameters) {
-            parameters.add(p.klass.name + " " + p.name);
+            parameters.add("final " + p.klass.name + " " + p.name);
         }
 
         writer.println("    public " + returnString + " " + method.name + "(" + collectionToDelimitedString(parameters, ", ") + ") {");
-        writer.println(method.body);
-        writer.println("    }");
-    }
-
-    public void simpleConstructor(List<ParameterRef> parameters, List<String> goesToSuper) {
-        List<String> ps = new ArrayList<>();
-        for (ParameterRef p : parameters) {
-            ps.add(p.klass.name + " " + p.name);
-        }
-        List<String> ss = new ArrayList<>();
-        List<String> local = new ArrayList<>();
-        for (String s : goesToSuper) {
-            for (ParameterRef parameter : parameters) {
-                if (parameter.name.equals(s)) {
-                    ss.add(parameter.name);
-                    continue;
-                }
-            }
-            local.add(s);
-        }
-        String params = ps.size() == 0 ? "" : ", " + collectionToDelimitedString(ps, ", ");
-
-        CharArrayWriter buffer = new CharArrayWriter();
-        PrintWriter writer = new PrintWriter(buffer);
-
-        writer.println("    public " + className + "(" + params + ") {");
-        writer.println("        super(" + collectionToDelimitedString(ss, ", ") + ");");
-//        writer.println("        this.transactionManager = _transactionManager_;");
-        for (String s : local) {
-            writer.println("        this." + s + " = " + s);
+        for (String s : method.body) {
+            writer.print("        ");
+            writer.println(s);
         }
         writer.println("    }");
     }
diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Constructor.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Constructor.java
new file mode 100644
index 0000000..43800ce
--- /dev/null
+++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/model/Constructor.java
@@ -0,0 +1,38 @@
+package io.trygvis.container.compiler.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.springframework.util.StringUtils.collectionToDelimitedString;
+
+public class Constructor {
+
+    private final ClassG g;
+    private final Parameters parameters;
+    private final List<String> body;
+
+    public Constructor(ClassG g, Parameters parameters, List<String> body) {
+        this.g = g;
+        this.parameters = parameters;
+        this.body = body;
+    }
+
+    public List<String> write() {
+        List<String> body = new ArrayList<>();
+
+        List<String> ps = new ArrayList<>();
+        for (ParameterRef p : parameters) {
+            ps.add(p.klass.name + " " + p.name);
+        }
+
+        String params = collectionToDelimitedString(ps, ", ");
+
+        body.add("    public " + g.className + "(" + params + ") {");
+        for (String s : this.body) {
+            body.add("        " + s);
+        }
+        body.add("    }");
+
+        return body;
+    }
+}
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 0b2cf89..36f61e8 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,13 +1,15 @@
 package io.trygvis.container.compiler.model;
 
+import java.util.List;
+
 public class MethodRef {
     public final TypeRef returnType;
     public final String name;
     public final ParameterRef[] parameters;
-    public final String body;
+    public final List<String> body;
 
     public
-    MethodRef(TypeRef returnType, String name, ParameterRef[] parameters, String body) {
+    MethodRef(TypeRef returnType, String name, ParameterRef[] parameters, List<String> body) {
         this.returnType = returnType;
         this.name = name;
         this.parameters = parameters;
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 bfb32b6..7c1ab5b 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
@@ -1,4 +1,35 @@
 package io.trygvis.container.compiler.model;
 
-public class Parameters {
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+public class Parameters implements Iterable<ParameterRef> {
+    private final List<ParameterRef> parameters = new ArrayList<>();
+
+    public ParameterRef addParameter(TypeRef klass, String name) {
+
+        while (taken(name)) {
+            name = name + "_";
+        }
+
+        ParameterRef ref = new ParameterRef(klass, name);
+        parameters.add(ref);
+        return ref;
+    }
+
+    private boolean taken(String name) {
+        for (ParameterRef parameter : parameters) {
+            if (parameter.name.equals(name)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public ListIterator<ParameterRef> iterator() {
+        return parameters.listIterator();
+    }
 }
-- 
cgit v1.2.3