package org.andork.codegen;
import java.util.ArrayList;
import java.util.List;
/**
* Simple tool for generating Java code. It inserts braces, indentation, javadoc
* markers, and comment markers for you.
*
* @author james.a.edwards
*/
public class CodeBuilder2 {
private static interface Element {
public void append(StringBuffer sb, String tabs);
}
private static class Line implements Element {
StringBuffer line;
private Line(StringBuffer line) {
super();
this.line = line;
}
private Line(String line) {
this(new StringBuffer(line));
}
public void append(StringBuffer sb, String tabs) {
sb.append(tabs).append(line).append('\n');
}
}
/**
* Represents a group of lines of code. This may be the root block, a Java
* code block for a class, method, etc., a Javadoc block, or a comment
* block. The block may contain sub-blocks, and it may indent/format them
* based upon its type. To get the formatted code, just call
* {@link #toString()}.
*
* @author james.a.edwards
*/
public static class Block implements Element {
Block parent;
String header;
String indenter;
String footer;
List<Element> contents = new ArrayList<Element>();
private Block() {
}
private Block(String header, String indenter, String footer) {
this(null, header, indenter, footer);
}
private Block(Block parent, String header, String indenter, String footer) {
this.parent = parent;
this.header = header;
this.indenter = indenter;
this.footer = footer;
}
/**
* Adds a block to the inside of this block.
*
* @param block
* the block to add
* @throws IllegalArgumentException
* if {@code block} already has a parent
*/
public void addBlock(Block block) {
if (block.parent != null) {
throw new IllegalArgumentException("block already has a parent");
}
block.parent = this;
contents.add(block);
}
/**
* Adds a line of text to this block.
*
* @param line
* the text to add.
* @return a {@link StringBuffer} representing the new line, which may
* be modified.
*/
public StringBuffer addLine(String line) {
StringBuffer sb = addLine();
sb.append(line);
return sb;
}
/**
* Adds an (initially empty) line of text to this block.
*
* @return a {@link StringBuffer} representing the new line, which may
* be modified.
*/
public StringBuffer addLine() {
StringBuffer sb = new StringBuffer();
contents.add(new Line(sb));
return sb;
}
/**
* Appends the contents of this block into a {@link StringBuffer}.
*
* @param sb
* the {@code StringBuffer} to append to.
* @param tabs
* the text to append to {@code sb} before each line of this
* block.
*/
public void append(StringBuffer sb, String tabs) {
if (header != null) {
sb.append(tabs).append(header).append("\n");
}
String childTabs = tabs;
if (indenter != null) {
childTabs += indenter;
}
for (Element statement : contents) {
statement.append(sb, childTabs);
}
if (footer != null) {
sb.append(tabs).append(footer).append("\n");
}
}
public String toString() {
StringBuffer sb = new StringBuffer();
append(sb, "");
return sb.toString();
}
}
public static class JavaBlock extends Block {
private JavaBlock() {
this(null, null, null, null);
}
private JavaBlock(JavaBlock parent, String header, String indenter, String footer) {
this.parent = parent;
this.header = header;
this.indenter = indenter;
this.footer = footer;
}
/**
* Adds a {@code Block} of java code as a child of this one.
*
* @param header
* the code that comes before the start brace.
* @param footer
* the code that comes after the end brace.
* @return the new child {@code Block}.
*/
public JavaBlock newJavaBlock(String header, String footer) {
if (header == null) {
header = "{";
} else {
header += " {";
}
if (footer == null) {
footer = "}";
} else {
footer = "} " + footer;
}
JavaBlock block = new JavaBlock(this, header, "\t", footer);
contents.add(block);
return block;
}
/**
* Adds a {@code Block} of java code as a child of this one.
*
* @param header
* the code that comes before the start brace.
* @return the new child {@code Block}.
*/
public JavaBlock newJavaBlock(String header) {
return newJavaBlock(header, null);
}
/**
* Adds a {@code Block} of java code as a child of this one.
*
* @param header
* the code that comes before the start brace.
* @return the new child {@code Block}.
*/
public DeclBlock newDeclBlock(String header) {
if (header == null) {
header = "{";
} else {
header += " {";
}
DeclBlock block = new DeclBlock(this, header, "\t", "}");
contents.add(block);
return block;
}
/**
* Adds a {@code Block} of comments as a child of this one.
*
* @return the new child {@code Block}.
*/
public Block newCommentBlock() {
Block block = new Block(this, null, "// ", null);
contents.add(block);
return block;
}
}
public static class DeclBlock extends JavaBlock {
JavadocBlock javadoc;
List<Line> annotations = new ArrayList<Line>();
private DeclBlock(JavaBlock parent, String header, String indenter, String footer) {
super(parent, header, indenter, footer);
}
public StringBuffer addAnnotation() {
return addAnnotation("");
}
public StringBuffer addAnnotation(String annotation) {
Line line = new Line(annotation);
annotations.add(line);
return line.line;
}
public JavadocBlock javadoc() {
if (javadoc == null) {
javadoc = new JavadocBlock(this);
}
return javadoc;
}
@Override
public void append(StringBuffer sb, String tabs) {
if (javadoc != null) {
javadoc.append(sb, tabs);
}
for (Line annotation : annotations) {
annotation.append(sb, tabs);
}
super.append(sb, tabs);
}
}
public static class JavadocBlock extends Block {
private JavadocBlock() {
this(null);
}
private JavadocBlock(DeclBlock parent) {
super(parent, "/**", " * ", " */");
}
}
/**
* @return a new root {@link Block}. It will not apply any formatting to its
* lines. To add code, use {@link Block#newJavaBlock(String)}.
*/
public static JavaBlock newJavaBlock() {
return new JavaBlock();
}
/**
* Adds a {@code Block} of java code as a child of this one.
*
* @param header
* the code that comes before the start brace.
* @param footer
* the code that comes after the end brace.
* @return the new child {@code Block}.
*/
public static JavaBlock newJavaBlock(String header, String footer) {
if (header == null) {
header = "{";
} else {
header += " {";
}
if (footer == null) {
footer = "}";
} else {
footer = "} " + footer;
}
return new JavaBlock(null, header, "\t", footer);
}
/**
* Adds a {@code Block} of java code as a child of this one.
*
* @param header
* the code that comes before the start brace.
* @return the new child {@code Block}.
*/
public static JavaBlock newJavaBlock(String header) {
return newJavaBlock(header, null);
}
/**
* Adds a {@code Block} of java code as a child of this one.
*
* @param header
* the code that comes before the start brace.
* @param footer
* the code that comes after the end brace.
* @return the new child {@code Block}.
*/
public static DeclBlock newDeclBlock(String header) {
if (header == null) {
header = "{";
} else {
header += " {";
}
return new DeclBlock(null, header, "\t", "}");
}
/**
* Adds a {@code Block} of javadoc as a child of this one.
*
* @return the new child {@code Block}.
*/
public static JavadocBlock newJavadocBlock() {
return new JavadocBlock();
}
/**
* Adds a {@code Block} of comments as a child of this one.
*
* @return the new child {@code Block}.
*/
public static Block newCommentBlock() {
return new Block(null, "// ", null);
}
}