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 CodeBuilder {
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;
}
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;
}
/**
* 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 Block newJavaBlock(String header, String footer) {
if (header == null) {
header = "{";
} else {
header += " {";
}
if (footer == null) {
footer = "}";
} else {
footer = "} " + footer;
}
Block block = new Block(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 Block newJavaBlock(String header) {
return newJavaBlock(header, null);
}
/**
* Adds a {@code Block} of javadoc as a child of this one.
*
* @return the new child {@code Block}.
*/
public Block newJavadocBlock() {
Block block = new Block(this, "/**", " * ", " */");
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;
}
/**
* The parent {@code Block}.
*/
public Block endBlock() {
return parent;
}
/**
* 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();
}
}
/**
* @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 Block newBlock() {
return new Block();
}
/**
* 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 Block newJavaBlock(String header, String footer) {
if (header == null) {
header = "{";
} else {
header += " {";
}
if (footer == null) {
footer = "}";
} else {
footer = "} " + footer;
}
return new Block(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 Block newJavaBlock(String header) {
return newJavaBlock(header, null);
}
/**
* Adds a {@code Block} of javadoc as a child of this one.
*
* @return the new child {@code Block}.
*/
public static Block newJavadocBlock() {
return new Block("/**", " * ", " */");
}
/**
* 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);
}
}