diff options
author | Jake Wharton <jw@squareup.com> | 2013-01-31 15:00:52 -0800 |
---|---|---|
committer | Jake Wharton <jw@squareup.com> | 2013-01-31 15:34:15 -0800 |
commit | aed50f772034c1235482ecc98fb2c9be794a0449 (patch) | |
tree | b95b3b79be1befcd991c8be5f38e4748f12365c0 | |
parent | e8cd8f4881897b00043c8114aac7537ab11c4b16 (diff) | |
download | javapoet-aed50f772034c1235482ecc98fb2c9be794a0449.tar.gz |
Make all methods fluent. Add simple example in README.
-rw-r--r-- | README.md | 63 | ||||
-rw-r--r-- | pom.xml | 2 | ||||
-rw-r--r-- | src/main/java/com/squareup/java/JavaWriter.java (renamed from src/main/java/com/squareup/java/JavaSourceWriter.java) | 93 | ||||
-rw-r--r-- | src/test/java/com/squareup/java/JavaWriterTest.java (renamed from src/test/java/com/squareup/java/JavaSourceWriterTest.java) | 18 |
4 files changed, 126 insertions, 50 deletions
@@ -1,7 +1,60 @@ -JavaSourceWriter -================ +Java Writer +=========== + +`JavaWriter` is a utility class which aids in generating Java source files. + +Source file generation can useful when doing things such as annotation processing or interacting +with metadata files (e.g., database schemas, protocol formats). By generating code, you eliminate +the need to write boilerplate while also keeping a single source of truth for the metadata. + + + +Example +------- + +```java +writer.emitPackage("com.example") + .beginType("com.example.Person", "class", PUBLIC | FINAL) + .emitField("String", "firstName", PRIVATE) + .emitField("String", "lastName", PRIVATE) + .emitJavadoc("Returns the person's full name.") + .beginMethod("String", "getName", PUBLIC) + .emitStatement("return firstName + \" \" + lastName;") + .endMethod() + .endType(); +``` + +Would produce the following source output: + +```java +package com.example; +public final class Person { + private String firstName; + private String lastName; + /** + * Returns the person's full name. + */ + public String getName() { + return firstName + " " + lastName;; + } +} +``` + + + +Download +-------- + +Download [the latest .jar][dl] or depend via Maven: + +```xml +<dependency> + <groupId>com.squareup</groupId> + <artifactId>javawriter</artifactId> + <version>(insert latest version)</version> +</dependency> +``` -TODO License @@ -20,3 +73,7 @@ License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + + + + [dl]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.squareup&a=javawriter&v=LATEST @@ -14,7 +14,7 @@ <version>1.0.0-SNAPSHOT</version> <name>JavaWriter</name> - <description>Emits Java source files.</description> + <description>A utility class which aids in generating Java source files.</description> <url>http://github.com/square/javawriter/</url> <properties> diff --git a/src/main/java/com/squareup/java/JavaSourceWriter.java b/src/main/java/com/squareup/java/JavaWriter.java index 1d43b50..f6a2eb7 100644 --- a/src/main/java/com/squareup/java/JavaSourceWriter.java +++ b/src/main/java/com/squareup/java/JavaWriter.java @@ -17,8 +17,8 @@ import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; -/** Emits Java source files. */ -public final class JavaSourceWriter implements Closeable { +/** A utility class which aids in generating Java source files. */ +public final class JavaWriter implements Closeable { private static final Pattern TYPE_PATTERN = Pattern.compile("(?:[\\w$]+\\.)*([\\w$]+)"); private static final String INDENT = " "; @@ -32,12 +32,12 @@ public final class JavaSourceWriter implements Closeable { /** * @param out the stream to which Java source will be written. This should be a buffered stream. */ - public JavaSourceWriter(Writer out) { + public JavaWriter(Writer out) { this.out = out; } /** Emit a package declaration. */ - public void emitPackage(String packageName) throws IOException { + public JavaWriter emitPackage(String packageName) throws IOException { if (this.packagePrefix != null) { throw new IllegalStateException(); } @@ -49,21 +49,22 @@ public final class JavaSourceWriter implements Closeable { out.write(";\n"); this.packagePrefix = packageName + "."; } + return this; } /** * Emit an import for each {@code type} provided. For the duration of the file, all references to * these classes will be automatically shortened. */ - public void emitImports(String... types) throws IOException { - emitImports(Arrays.asList(types)); + public JavaWriter emitImports(String... types) throws IOException { + return emitImports(Arrays.asList(types)); } /** * Emit an import for each {@code type} in the provided {@code Collection}. For the duration of * the file, all references to these classes will be automatically shortened. */ - public void emitImports(Collection<String> types) throws IOException { + public JavaWriter emitImports(Collection<String> types) throws IOException { for (String type : new TreeSet<String>(types)) { Matcher matcher = TYPE_PATTERN.matcher(type); if (!matcher.matches()) { @@ -77,14 +78,16 @@ public final class JavaSourceWriter implements Closeable { out.write(";\n"); } emitEmptyLine(); + return this; } /** * Emits a name like {@code java.lang.String} or {@code java.util.List<java.lang.String>}, * shorting it with imports if possible. */ - private void emitType(String type) throws IOException { + private JavaWriter emitType(String type) throws IOException { out.write(compressType(type)); + return this; } String compressType(String type) { @@ -141,8 +144,8 @@ public final class JavaSourceWriter implements Closeable { * * @param kind such as "class", "interface" or "enum". */ - public void beginType(String type, String kind, int modifiers) throws IOException { - beginType(type, kind, modifiers, null); + public JavaWriter beginType(String type, String kind, int modifiers) throws IOException { + return beginType(type, kind, modifiers, null); } /** @@ -151,7 +154,7 @@ public final class JavaSourceWriter implements Closeable { * @param kind such as "class", "interface" or "enum". * @param extendsType the class to extend, or null for no extends clause. */ - public void beginType(String type, String kind, int modifiers, String extendsType, + public JavaWriter beginType(String type, String kind, int modifiers, String extendsType, String... implementsTypes) throws IOException { indent(); out.write(modifiers(modifiers).toString()); @@ -175,21 +178,23 @@ public final class JavaSourceWriter implements Closeable { } out.write(" {\n"); pushScope(Scope.TYPE_DECLARATION); + return this; } /** Completes the current type declaration. */ - public void endType() throws IOException { + public JavaWriter endType() throws IOException { popScope(Scope.TYPE_DECLARATION); indent(); out.write("}\n"); + return this; } /** Emits a field declaration. */ - public void emitField(String type, String name, int modifiers) throws IOException { - emitField(type, name, modifiers, null); + public JavaWriter emitField(String type, String name, int modifiers) throws IOException { + return emitField(type, name, modifiers, null); } - public void emitField(String type, String name, int modifiers, String initialValue) + public JavaWriter emitField(String type, String name, int modifiers, String initialValue) throws IOException { indent(); out.write(modifiers(modifiers).toString()); @@ -202,16 +207,17 @@ public final class JavaSourceWriter implements Closeable { out.write(initialValue); } out.write(";\n"); + return this; } /** * Emit a method declaration. * * @param returnType the method's return type, or null for constructors. - * @param parameters alternating parameter types and names. * @param name the method name, or the fully qualified class name for constructors. + * @param parameters alternating parameter types and names. */ - public void beginMethod(String returnType, String name, int modifiers, String... parameters) + public JavaWriter beginMethod(String returnType, String name, int modifiers, String... parameters) throws IOException { indent(); out.write(modifiers(modifiers).toString()); @@ -239,10 +245,11 @@ public final class JavaSourceWriter implements Closeable { out.write(" {\n"); pushScope(Scope.NON_ABSTRACT_METHOD); } + return this; } /** Emits some Javadoc comments with line separated by {@code \n}. */ - public void emitJavadoc(String javadoc, Object... params) throws IOException { + public JavaWriter emitJavadoc(String javadoc, Object... params) throws IOException { String formatted = String.format(javadoc, params); indent(); out.write("/**\n"); @@ -254,27 +261,30 @@ public final class JavaSourceWriter implements Closeable { } indent(); out.write(" */\n"); + return this; } /** Emits some Javadoc comments. */ - public void emitEndOfLineComment(String comment) throws IOException { + public JavaWriter emitEndOfLineComment(String comment) throws IOException { out.write("// "); out.write(comment); out.write("\n"); + return this; } - public void emitEmptyLine() throws IOException { + public JavaWriter emitEmptyLine() throws IOException { out.write("\n"); + return this; } /** Equivalent to {@code annotation(annotation, emptyMap())}. */ - public void emitAnnotation(String annotation) throws IOException { - emitAnnotation(annotation, Collections.<String, Object>emptyMap()); + public JavaWriter emitAnnotation(String annotation) throws IOException { + return emitAnnotation(annotation, Collections.<String, Object>emptyMap()); } /** Equivalent to {@code annotation(annotationType.getName(), emptyMap())}. */ - public void emitAnnotation(Class<? extends Annotation> annotationType) throws IOException { - emitAnnotation(annotationType.getName(), Collections.<String, Object>emptyMap()); + public JavaWriter emitAnnotation(Class<? extends Annotation> annotationType) throws IOException { + return emitAnnotation(annotationType.getName(), Collections.<String, Object>emptyMap()); } /** @@ -284,7 +294,7 @@ public final class JavaSourceWriter implements Closeable { * be encoded using Object.toString(); use {@link #stringLiteral} for String values. Object * arrays are written one element per line. */ - public void emitAnnotation(Class<? extends Annotation> annotation, Object value) + public JavaWriter emitAnnotation(Class<? extends Annotation> annotation, Object value) throws IOException { indent(); out.write("@"); @@ -293,12 +303,13 @@ public final class JavaSourceWriter implements Closeable { emitAnnotationValue(value); out.write(")"); out.write("\n"); + return this; } /** Equivalent to {@code annotation(annotationType.getName(), attributes)}. */ - public void emitAnnotation(Class<? extends Annotation> annotationType, Map<String, ?> attributes) - throws IOException { - emitAnnotation(annotationType.getName(), attributes); + public JavaWriter emitAnnotation(Class<? extends Annotation> annotationType, + Map<String, ?> attributes) throws IOException { + return emitAnnotation(annotationType.getName(), attributes); } /** @@ -308,7 +319,8 @@ public final class JavaSourceWriter implements Closeable { * using Object.toString(); use {@link #stringLiteral} for String values. Object arrays are * written one element per line. */ - public void emitAnnotation(String annotation, Map<String, ?> attributes) throws IOException { + public JavaWriter emitAnnotation(String annotation, Map<String, ?> attributes) + throws IOException { indent(); out.write("@"); emitType(annotation); @@ -335,13 +347,14 @@ public final class JavaSourceWriter implements Closeable { out.write(")"); } out.write("\n"); + return this; } /** * Writes a single annotation value. If the value is an array, each element in the array will be * written to its own line. */ - private void emitAnnotationValue(Object value) throws IOException { + private JavaWriter emitAnnotationValue(Object value) throws IOException { if (value instanceof Object[]) { out.write("{"); boolean firstValue = true; @@ -363,53 +376,57 @@ public final class JavaSourceWriter implements Closeable { } else { out.write(value.toString()); } + return this; } /** * @param pattern a code pattern like "int i = %s". Shouldn't contain a trailing semicolon or * newline character. */ - public void emitStatement(String pattern, Object... args) throws IOException { + public JavaWriter emitStatement(String pattern, Object... args) throws IOException { checkInMethod(); indent(); out.write(String.format(pattern, args)); out.write(";\n"); + return this; } /** * @param controlFlow the control flow construct and its code, such as "if (foo == 5)". Shouldn't * contain braces or newline characters. */ - public void beginControlFlow(String controlFlow) throws IOException { + public JavaWriter beginControlFlow(String controlFlow) throws IOException { checkInMethod(); indent(); out.write(controlFlow); out.write(" {\n"); pushScope(Scope.CONTROL_FLOW); + return this; } /** * @param controlFlow the control flow construct and its code, such as "else if (foo == 10)". * Shouldn't contain braces or newline characters. */ - public void nextControlFlow(String controlFlow) throws IOException { + public JavaWriter nextControlFlow(String controlFlow) throws IOException { popScope(Scope.CONTROL_FLOW); indent(); pushScope(Scope.CONTROL_FLOW); out.write("} "); out.write(controlFlow); out.write(" {\n"); + return this; } - public void endControlFlow() throws IOException { - endControlFlow(null); + public JavaWriter endControlFlow() throws IOException { + return endControlFlow(null); } /** * @param controlFlow the optional control flow construct and its code, such as * "while(foo == 20)". Only used for "do/while" control flows. */ - public void endControlFlow(String controlFlow) throws IOException { + public JavaWriter endControlFlow(String controlFlow) throws IOException { popScope(Scope.CONTROL_FLOW); indent(); if (controlFlow != null) { @@ -419,10 +436,11 @@ public final class JavaSourceWriter implements Closeable { } else { out.write("}\n"); } + return this; } /** Completes the current method declaration. */ - public void endMethod() throws IOException { + public JavaWriter endMethod() throws IOException { Scope popped = popScope(); if (popped == Scope.NON_ABSTRACT_METHOD) { indent(); @@ -430,6 +448,7 @@ public final class JavaSourceWriter implements Closeable { } else if (popped != Scope.ABSTRACT_METHOD) { throw new IllegalStateException(); } + return this; } /** Returns the string literal representing {@code data}, including wrapping quotes. */ diff --git a/src/test/java/com/squareup/java/JavaSourceWriterTest.java b/src/test/java/com/squareup/java/JavaWriterTest.java index a419dfd..5fc4415 100644 --- a/src/test/java/com/squareup/java/JavaSourceWriterTest.java +++ b/src/test/java/com/squareup/java/JavaWriterTest.java @@ -12,9 +12,9 @@ import org.junit.Test; import static org.fest.assertions.api.Assertions.assertThat; -public final class JavaSourceWriterTest { +public final class JavaWriterTest { private final StringWriter stringWriter = new StringWriter(); - private final JavaSourceWriter javaWriter = new JavaSourceWriter(stringWriter); + private final JavaWriter javaWriter = new JavaWriter(stringWriter); @Test public void typeDeclaration() throws IOException { javaWriter.emitPackage("com.squareup"); @@ -208,7 +208,7 @@ public final class JavaSourceWriterTest { javaWriter.emitImports("javax.inject.Singleton"); javaWriter.emitAnnotation("javax.inject.Singleton"); javaWriter.emitAnnotation(SuppressWarnings.class, - JavaSourceWriter.stringLiteral("unchecked")); + JavaWriter.stringLiteral("unchecked")); javaWriter.beginType("com.squareup.Foo", "class", 0); javaWriter.endType(); assertCode("" @@ -301,12 +301,12 @@ public final class JavaSourceWriterTest { } @Test public void testStringLiteral() { - assertThat(JavaSourceWriter.stringLiteral("")).isEqualTo("\"\""); - assertThat(JavaSourceWriter.stringLiteral("JavaWriter")).isEqualTo("\"JavaWriter\""); - assertThat(JavaSourceWriter.stringLiteral("\\")).isEqualTo("\"\\\\\""); - assertThat(JavaSourceWriter.stringLiteral("\"")).isEqualTo("\"\\\"\""); - assertThat(JavaSourceWriter.stringLiteral("\t")).isEqualTo("\"\\\t\""); - assertThat(JavaSourceWriter.stringLiteral("\n")).isEqualTo("\"\\\n\""); + assertThat(JavaWriter.stringLiteral("")).isEqualTo("\"\""); + assertThat(JavaWriter.stringLiteral("JavaWriter")).isEqualTo("\"JavaWriter\""); + assertThat(JavaWriter.stringLiteral("\\")).isEqualTo("\"\\\\\""); + assertThat(JavaWriter.stringLiteral("\"")).isEqualTo("\"\\\"\""); + assertThat(JavaWriter.stringLiteral("\t")).isEqualTo("\"\\\t\""); + assertThat(JavaWriter.stringLiteral("\n")).isEqualTo("\"\\\n\""); } @Test public void compressType() throws IOException { |