package io.trygvis.container.compiler.model; import org.apache.commons.lang.StringUtils; import javax.annotation.Generated; import javax.lang.model.type.TypeMirror; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import static io.trygvis.container.compiler.Utils.toJavaString; import static java.lang.reflect.Modifier.*; import static java.util.Arrays.asList; import static org.apache.commons.lang.StringUtils.join; import static org.springframework.util.StringUtils.collectionToDelimitedString; public class ClassG { public final int modifiers; public final TypeRef type; private TypeRef extendsType; private List implementsTypes = new ArrayList<>(); public final Imports imports = new Imports(); private final Set fields = new TreeSet<>(); private final List methods = new ArrayList<>(); private final List constructors = new ArrayList<>(); private final List innerClasses = new ArrayList<>(); public static class InnerClassG { public final ClassG inner; public InnerClassG(ClassG inner) { this.inner = inner; } } public ClassG(int modifiers, TypeRef type) { if ((Modifier.classModifiers() & modifiers) != modifiers) { throw new RuntimeException("Invalid modifiers for class: " + Modifier.toString(modifiers)); } this.modifiers = modifiers; this.type = type; } public ClassG extendsType(TypeRef extendsType) { this.extendsType = extendsType; return this; } public ClassG implementsType(TypeRef... implementsTypes) { this.implementsTypes.addAll(asList(implementsTypes)); return this; } public FieldRef addField(TypeMirror klass, String name) { TypeRef type = imports.add(klass); FieldRef ref = new FieldRef(PRIVATE | FINAL, type, name); fields.add(ref); return ref; } public FieldRef addField(int modifiers, TypeRef type, String name) { TypeRef t = imports.add(type); FieldRef ref = new FieldRef(modifiers, t, name); fields.add(ref); return ref; } public FieldRef addField(TypeRef type, String name) { return addField(PRIVATE | FINAL, type, name); } public FieldRef addPublicFinalField(TypeRef type, String name) { return addField(PUBLIC | FINAL, type, name); } public FieldRef addPublicStaticFinalField(TypeRef type, String name) { return addField(PUBLIC | STATIC | FINAL, type, name); } public Constructor addConstructor(Parameters parameters, List body) { Constructor constructor = new Constructor(this, parameters, body); constructors.add(constructor); return constructor; } public ClassG addMethod(MethodRef methodRef) { this.methods.add(methodRef); return this; } // public MethodRef addMethod(List body, TypeRef returnType, String name, Parameters parameters) { // MethodRef ref = new MethodRef(PUBLIC, returnType, name, parameters, body); // methods.add(ref); // return ref; // } // // public MethodRef addStaticMethod(List body, TypeRef returnType, String name, Parameters parameters) { // MethodRef ref = new MethodRef(PUBLIC | STATIC, returnType, name, parameters, body); // methods.add(ref); // return ref; // } public InnerClassG addInnerClass(ClassG inner) { InnerClassG i = new InnerClassG(inner); innerClasses.add(i); return i; } public final List generate() { return generate(false); } public final List generate(boolean isInner) { TypeRef generatedType = imports.add(Generated.class); List body = new ArrayList<>(); if (!type.inUnnamedPackage() && !isInner) { body.add("package " + type.packageName() + ";"); body.add(""); } if (!isInner) { body.addAll(imports.generate()); } String extendsString = extendsType == null ? "" : " extends " + extendsType; if (!implementsTypes.isEmpty()) { extendsString += " implements " + join(implementsTypes, ", "); } body.add("@" + generatedType + "(" + toJavaString("SQL Persistence, yay!!") + ")"); body.add(Modifier.toString(modifiers) + " class " + type.className + extendsString + " {"); for (FieldRef field : fields) { body.add(""); body.add(" " + field.toJava() + ";"); } for (InnerClassG innerClass : innerClasses) { body.add(""); addAll(1, body, innerClass.inner.generate(true)); } for (Constructor constructor : constructors) { body.add(""); addAll(1, body, constructor.write()); } for (MethodRef method : methods) { body.add(""); addAll(1, body, write(method)); } body.add("}"); return body; } public static void addAll(int indent, List body, List innerBody) { String prefix = StringUtils.leftPad("", indent * 4); for (String s : innerBody) { body.add(prefix + s); } } private List write(MethodRef method) { List body = new ArrayList<>(); String returnString; if (method.returnType == TypeRef.VOID) { returnString = "void"; } else { returnString = method.returnType.toString(); } List parameters = new ArrayList<>(); for (Parameters.ParameterRef p : method.parameters) { parameters.add("final " + p.klass + " " + p.name); } String m = Modifier.toString(method.modifiers) + " " + returnString + " " + method.name + "(" + collectionToDelimitedString(parameters, ", ") + ")"; if (method.exceptions.isEmpty()) { body.add(m + " {"); } else { ArrayList typeRefs = new ArrayList<>(method.exceptions); String end = typeRefs.size() == 1 ? " {" : ","; body.add(m + " throws " + typeRefs.get(0).toString() + end); for (int i = 1; i < typeRefs.size(); i++) { TypeRef e = typeRefs.get(i); String s = " " + e; if (i < typeRefs.size() - 1) { s += ","; } else { s += " {"; } body.add(s); } } addAll(1, body, method.body); body.add("}"); return body; } }