package joist.sourcegen; import java.util.ArrayList; import java.util.List; import joist.util.Interpolate; import joist.util.Join; import joist.util.StringBuilderr; public class GMethod { public final StringBuilderr body = new StringBuilderr(); private final GClass gclass; private final String name; private final List<Argument> arguments = new ArrayList<Argument>(); private final List<String> annotations = new ArrayList<String>(); private final List<String> exceptions = new ArrayList<String>(); private String returnClassName = "void"; private String constructorFor = null; private Access access = Access.PUBLIC; private boolean isStatic; private boolean isAbstract; private String typeParameters = null; public GMethod(GClass gclass, String methodName) { this.gclass = gclass; this.name = methodName; } public GMethod returnType(Class<?> type) { return this.returnType(type.getName()); } public GMethod returnType(String returnClassName, Object... args) { this.returnClassName = this.gclass.stripAndImportPackageIfPossible(Interpolate.string(returnClassName, args)); return this; } public GMethod argument(String typeClassName, String name) { typeClassName = this.gclass.stripAndImportPackageIfPossible(typeClassName); this.arguments.add(new Argument(typeClassName, name)); return this; } /** @param typeAndNames could be either "Foo f, Bar b" or "Foo f", "Bar b" */ public GMethod arguments(String... typeAndNames) { String line = Join.commaSpace(typeAndNames); line = this.gclass.stripAndImportPackageIfPossible(line); this.arguments.addAll(Argument.split(line)); return this; } public GMethod arguments(List<Argument> args) { this.arguments.addAll(args); return this; } public GMethod constructorFor(String shortClassName) { this.constructorFor = shortClassName; return this; } public void setBody(String body) { this.body.append(body.replace("'", "\"")); } public String toCode() { StringBuilderr sb = new StringBuilderr(); for (String annotation : this.annotations) { sb.line(annotation); } boolean isStaticBlock = this.isStatic && this.constructorFor != null; if (!isStaticBlock) { sb.append(this.access.asPrefix()); } if (this.isStatic) { sb.append("static "); } if (this.isAbstract) { sb.append("abstract "); } if (this.typeParameters != null) { sb.append("<{}> ", this.typeParameters); } if (this.constructorFor != null) { if (!isStaticBlock) { sb.append(this.constructorFor); } } else { sb.append("{} {}", this.returnClassName, this.getName()); } if (!isStaticBlock) { sb.append("({})", Join.commaSpace(this.arguments)); } if (this.exceptions.size() > 0) { sb.append(" throws "); List<String> exceptionTypes = new ArrayList<String>(); for (String exception : this.exceptions) { exceptionTypes.add(this.gclass.stripAndImportPackageIfPossible(exception)); } sb.append(Join.commaSpace(exceptionTypes)); } if (this.gclass.isInterface || this.isAbstract) { sb.line(";"); } else { sb.line(" {"); sb.append(1, this.body.toString()); sb.lineIfNeeded(); // The body may or may not have a trailing new line on it sb.line(0, "}"); } return sb.toString(); } public String getName() { return this.name; } public GMethod setPrivate() { this.access = Access.PRIVATE; return this; } public GMethod setProtected() { this.access = Access.PROTECTED; return this; } public GMethod setAccess(Access access) { this.access = access; return this; } public GMethod setStatic() { this.isStatic = true; return this; } public GMethod setAbstract() { this.isAbstract = true; return this; } /** @return if we have the arguments */ public boolean hasArguments() { return this.arguments.size() > 0; } /** @return if we have the same arguments (based on types, not named) */ public boolean hasSameArguments(String... typeAndNames) { return this.hasSameArguments(Argument.split(typeAndNames)); } /** @return if we have the same arguments (based on types, not named) */ public boolean hasSameArguments(List<Argument> other) { if (other.size() != this.arguments.size()) { return false; } for (int i = 0; i < other.size(); i++) { if (!(other.get(i).type.equals(this.arguments.get(i).type))) { return false; } } return true; } public GMethod addAnnotation(String annotation, Object... args) { this.annotations.add(Interpolate.string(annotation, args)); return this; } public GMethod addOverride() { this.annotations.add("@Override"); return this; } public GMethod addThrows(String exception) { this.exceptions.add(exception); return this; } /** @param typeParameters e.g. <code>T, U</code> **/ public GMethod typeParameters(String typeParameters) { this.typeParameters = typeParameters; return this; } public GMethod assignFields() { for (Argument arg : this.arguments) { this.body.line("this.{} = {};", arg.name, arg.name); } return this; } }