pax_global_header00006660000000000000000000000064125517155670014530gustar00rootroot0000000000000052 comment=ebb3721a8d2c81439639bfbdfa0b7b857229346c javawriter-2.5.1/000077500000000000000000000000001255171556700137135ustar00rootroot00000000000000javawriter-2.5.1/.gitignore000066400000000000000000000002261255171556700157030ustar00rootroot00000000000000.classpath .project .settings .checkstyle eclipsebin bin gen build out lib target pom.xml.* release.properties .idea *.iml classes obj .DS_Store javawriter-2.5.1/.travis.yml000066400000000000000000000000551255171556700160240ustar00rootroot00000000000000language: java notifications: email: falsejavawriter-2.5.1/CHANGELOG.md000066400000000000000000000061451255171556700155320ustar00rootroot00000000000000Change Log ========== Version 2.5.1 *(2014-12-03)* ---------------------------- * New: `StringLiteral` type which encapsulates the behavior of `stringLiteral`. * Fix: Use canonical name when emitting a class import. * Fix: Apply type compression to varargs and array types. * Fix: Restore binary compatibility with pre-2.5 versions. Version 2.5.0 *(2014-04-18)* ---------------------------- * New: Methods in interfaces will always have no body declaration. * New: Control flow begin declaration now supports String format arguments. * Fix: Truncate any generic type when emitting constructors. * Fix: Do not emit trailing whitespace after '=' at end-of-line. Version 2.4.0 *(2014-01-10)* ---------------------------- * New: Properly indent hanging lines in field initializers. * New: `emitEnumValue` variant which exposes a boolean of whether the current value is the last. Version 2.3.1 *(2013-12-16)* ---------------------------- * Fix: Properly handle subpackages of `java.lang` in `compressType`. Version 2.3.0 *(2013-11-24)* ---------------------------- * New: Configurable indent level via `setIndent`. * New: `beginConstructor` method is a semantically clearer alternative for constructors. * New: `emitEnumValues` method emits a list of values followed by semicolon. * `emitImports` now supports `Class` arguments directly. * Previously-deprecated, `int`-based modifier methods have been removed. Version 2.2.1 *(2013-10-23)* ---------------------------- * Fix: Do not emit trailing whitespace for empty Javadoc lines. Version 2.2.0 *(2013-09-25)* ---------------------------- * `setCompressingTypes` controls whether types are emitted as fully-qualified or not. Version 2.1.2 *(2013-08-23)* ---------------------------- * Attempt to keep annotations on a single line. Version 2.1.1 *(2013-07-23)* ---------------------------- * Fix: `stringLiteral` now correctly handles escapes and control characters. Version 2.1.0 *(2013-07-15)* ---------------------------- * New: All methods now take a `Set` of `Modifier`s rather than an `int`. The `int` methods are now deprecated for removal in version 3.0. * Annotations with a single "value" attribute will now omit the key. Version 2.0.1 *(2013-06-17)* ---------------------------- * Correct casing of `emitSingleLineComment`. Version 2.0.0 *(2013-06-06)* ---------------------------- * Package name is now `com.squareup.javawriter`. * Support declaring `throws` clause on methods. Version 1.0.5 *(2013-05-08)* ---------------------------- * Fix: Fully qualify types whose simple name matches an import. Version 1.0.4 *(2013-03-15)* ---------------------------- * Fix: Static import emit now properly supports method imports. Version 1.0.3 *(2013-02-21)* ----------------------------- * Add support for emitting static imports. Version 1.0.2 *(2013-02-11)* ---------------------------- * Add `type` API for helping build generic types. * Minor performance improvements. Version 1.0.1 *(2013-02-03)* ---------------------------- * Expose `compressType` API. Version 1.0.0 *(2013-02-01)* ---------------------------- Initial release. javawriter-2.5.1/CONTRIBUTING.md000066400000000000000000000013221255171556700161420ustar00rootroot00000000000000Contributing ============ If you would like to contribute code you can do so through GitHub by forking the repository and sending a pull request. When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. Please also make sure your code compiles by running `mvn clean verify`. Checkstyle failures during compilation indicate errors in your style and can be viewed in the `checkstyle-result.xml` file. Before your code can be accepted into the project you must also sign the [Individual Contributor License Agreement (CLA)][1]. [1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1 javawriter-2.5.1/LICENSE.txt000066400000000000000000000261361255171556700155460ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 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. javawriter-2.5.1/README.md000066400000000000000000000040711255171556700151740ustar00rootroot00000000000000Java 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", EnumSet.of(PUBLIC, FINAL)) .emitField("String", "firstName", EnumSet.of(PRIVATE)) .emitField("String", "lastName", EnumSet.of(PRIVATE)) .emitJavadoc("Returns the person's full name.") .beginMethod("String", "getName", EnumSet.of(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 com.squareup javawriter 2.5.1 ``` or Gradle: ```groovy compile 'com.squareup:javawriter:2.5.1' ``` License ------- Copyright 2013 Square, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 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]: https://search.maven.org/remote_content?g=com.squareup&a=javawriter&v=LATEST javawriter-2.5.1/checkstyle.xml000066400000000000000000000101171255171556700165730ustar00rootroot00000000000000 javawriter-2.5.1/deploy_javadoc.sh000077500000000000000000000014251255171556700172370ustar00rootroot00000000000000#!/bin/bash set -ex REPO="git@github.com:square/javawriter.git" GROUP_ID="com.squareup" ARTIFACT_ID="javawriter" DIR=temp-clone # Delete any existing temporary website clone rm -rf $DIR # Clone the current repo into temp folder git clone $REPO $DIR # Move working directory into temp folder cd $DIR # Checkout and track the gh-pages branch git checkout -t origin/gh-pages # Delete everything rm -rf * # Download the latest javadoc curl -L "https://search.maven.org/remote_content?g=$GROUP_ID&a=$ARTIFACT_ID&v=LATEST&c=javadoc" > javadoc.zip unzip javadoc.zip rm javadoc.zip # Stage all files in git and create a commit git add . git add -u git commit -m "Website at $(date)" # Push the new files up to GitHub git push origin gh-pages # Delete our temp folder cd .. rm -rf $DIR javawriter-2.5.1/pom.xml000066400000000000000000000055011255171556700152310ustar00rootroot00000000000000 4.0.0 org.sonatype.oss oss-parent 7 com.squareup javawriter 2.5.1 JavaWriter A utility class which aids in generating Java source files. http://github.com/square/javawriter/ UTF-8 1.6 4.10 2.0M8 http://github.com/square/javawriter/ scm:git:git://github.com/square/javawriter.git scm:git:ssh://git@github.com/square/javawriter.git HEAD GitHub Issues http://github.com/square/javawriter/issues Apache 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt Square, Inc. http://squareup.com junit junit ${junit.version} test org.easytesting fest-assert-core ${fest.version} test org.apache.maven.plugins maven-compiler-plugin 3.0 ${java.version} ${java.version} org.apache.maven.plugins maven-checkstyle-plugin 2.9.1 true checkstyle.xml true verify checkstyle javawriter-2.5.1/src/000077500000000000000000000000001255171556700145025ustar00rootroot00000000000000javawriter-2.5.1/src/main/000077500000000000000000000000001255171556700154265ustar00rootroot00000000000000javawriter-2.5.1/src/main/java/000077500000000000000000000000001255171556700163475ustar00rootroot00000000000000javawriter-2.5.1/src/main/java/com/000077500000000000000000000000001255171556700171255ustar00rootroot00000000000000javawriter-2.5.1/src/main/java/com/squareup/000077500000000000000000000000001255171556700207725ustar00rootroot00000000000000javawriter-2.5.1/src/main/java/com/squareup/javawriter/000077500000000000000000000000001255171556700231505ustar00rootroot00000000000000javawriter-2.5.1/src/main/java/com/squareup/javawriter/JavaWriter.java000066400000000000000000000650261255171556700261020ustar00rootroot00000000000000// Copyright 2013 Square, Inc. package com.squareup.javawriter; import java.io.Closeable; import java.io.IOException; import java.io.Writer; import java.lang.annotation.Annotation; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Deque; import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.lang.model.element.Modifier; import static javax.lang.model.element.Modifier.ABSTRACT; /** A utility class which aids in generating Java source files. */ public class JavaWriter implements Closeable { private static final Pattern TYPE_TRAILER = Pattern.compile("(.*?)(\\.\\.\\.|(?:\\[\\])+)$"); private static final Pattern TYPE_PATTERN = Pattern.compile("(?:[\\w$]+\\.)*([\\w\\.*$]+)"); private static final int MAX_SINGLE_LINE_ATTRIBUTES = 3; private static final String INDENT = " "; /** Map fully qualified type names to their short names. */ private final Map importedTypes = new LinkedHashMap(); private String packagePrefix; private final Deque scopes = new ArrayDeque(); private final Deque types = new ArrayDeque(); private final Writer out; private boolean isCompressingTypes = true; private String indent = INDENT; /** * @param out the stream to which Java source will be written. This should be a buffered stream. */ public JavaWriter(Writer out) { this.out = out; } public void setCompressingTypes(boolean isCompressingTypes) { this.isCompressingTypes = isCompressingTypes; } public boolean isCompressingTypes() { return isCompressingTypes; } public void setIndent(String indent) { this.indent = indent; } public String getIndent() { return indent; } /** Emit a package declaration and empty line. */ public JavaWriter emitPackage(String packageName) throws IOException { if (this.packagePrefix != null) { throw new IllegalStateException(); } if (packageName.isEmpty()) { this.packagePrefix = ""; } else { out.write("package "); out.write(packageName); out.write(";\n\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 JavaWriter emitImports(String... types) throws IOException { return emitImports(Arrays.asList(types)); } /** * Emit an import for each {@code type} provided. For the duration of the file, all references to * these classes will be automatically shortened. */ public JavaWriter emitImports(Class... types) throws IOException { List classNames = new ArrayList(types.length); for (Class classToImport : types) { classNames.add(classToImport.getCanonicalName()); } return emitImports(classNames); } /** * 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 JavaWriter emitImports(Collection types) throws IOException { for (String type : new TreeSet(types)) { Matcher matcher = TYPE_PATTERN.matcher(type); if (!matcher.matches()) { throw new IllegalArgumentException(type); } if (importedTypes.put(type, matcher.group(1)) != null) { throw new IllegalArgumentException(type); } out.write("import "); out.write(type); out.write(";\n"); } return this; } /** * Emit a static import for each {@code type} provided. For the duration of the file, * all references to these classes will be automatically shortened. */ public JavaWriter emitStaticImports(String... types) throws IOException { return emitStaticImports(Arrays.asList(types)); } /** * Emit a static 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 JavaWriter emitStaticImports(Collection types) throws IOException { for (String type : new TreeSet(types)) { Matcher matcher = TYPE_PATTERN.matcher(type); if (!matcher.matches()) { throw new IllegalArgumentException(type); } if (importedTypes.put(type, matcher.group(1)) != null) { throw new IllegalArgumentException(type); } out.write("import static "); out.write(type); out.write(";\n"); } return this; } /** * Emits a name like {@code java.lang.String} or {@code java.util.List}, * compressing it with imports if possible. Type compression will only be enabled if * {@link #isCompressingTypes} is true. */ private JavaWriter emitCompressedType(String type) throws IOException { if (isCompressingTypes) { out.write(compressType(type)); } else { out.write(type); } return this; } /** Try to compress a fully-qualified class name to only the class name. */ public String compressType(String type) { Matcher trailer = TYPE_TRAILER.matcher(type); if (trailer.matches()) { type = trailer.group(1); } StringBuilder sb = new StringBuilder(); if (this.packagePrefix == null) { throw new IllegalStateException(); } Matcher m = TYPE_PATTERN.matcher(type); int pos = 0; while (true) { boolean found = m.find(pos); // Copy non-matching characters like "<". int typeStart = found ? m.start() : type.length(); sb.append(type, pos, typeStart); if (!found) { break; } // Copy a single class name, shortening it if possible. String name = m.group(0); String imported = importedTypes.get(name); if (imported != null) { sb.append(imported); } else if (isClassInPackage(name, packagePrefix)) { String compressed = name.substring(packagePrefix.length()); if (isAmbiguous(compressed)) { sb.append(name); } else { sb.append(compressed); } } else if (isClassInPackage(name, "java.lang.")) { sb.append(name.substring("java.lang.".length())); } else { sb.append(name); } pos = m.end(); } if (trailer.matches()) { sb.append(trailer.group(2)); } return sb.toString(); } private static boolean isClassInPackage(String name, String packagePrefix) { if (name.startsWith(packagePrefix)) { if (name.indexOf('.', packagePrefix.length()) == -1) { return true; } // check to see if the part after the package looks like a class if (Character.isUpperCase(name.charAt(packagePrefix.length()))) { return true; } } return false; } /** * Returns true if the imports contain a class with same simple name as {@code compressed}. * * @param compressed simple name of the type */ private boolean isAmbiguous(String compressed) { return importedTypes.values().contains(compressed); } /** * Emits an initializer declaration. * * @param isStatic true if it should be an static initializer, false for an instance initializer. */ public JavaWriter beginInitializer(boolean isStatic) throws IOException { indent(); if (isStatic) { out.write("static"); out.write(" {\n"); } else { out.write("{\n"); } scopes.push(Scope.INITIALIZER); return this; } /** Ends the current initializer declaration. */ public JavaWriter endInitializer() throws IOException { popScope(Scope.INITIALIZER); indent(); out.write("}\n"); return this; } /** * Emits a type declaration. * * @param kind such as "class", "interface" or "enum". */ public JavaWriter beginType(String type, String kind) throws IOException { return beginType(type, kind, EnumSet.noneOf(Modifier.class), null); } /** * Emits a type declaration. * * @param kind such as "class", "interface" or "enum". */ public JavaWriter beginType(String type, String kind, Set modifiers) throws IOException { return beginType(type, kind, modifiers, null); } /** * Emits a type declaration. * * @param kind such as "class", "interface" or "enum". * @param extendsType the class to extend, or null for no extends clause. */ public JavaWriter beginType(String type, String kind, Set modifiers, String extendsType, String... implementsTypes) throws IOException { indent(); emitModifiers(modifiers); out.write(kind); out.write(" "); emitCompressedType(type); if (extendsType != null) { out.write(" extends "); emitCompressedType(extendsType); } if (implementsTypes.length > 0) { out.write("\n"); indent(); out.write(" implements "); for (int i = 0; i < implementsTypes.length; i++) { if (i != 0) { out.write(", "); } emitCompressedType(implementsTypes[i]); } } out.write(" {\n"); scopes.push("interface".equals(kind) ? Scope.INTERFACE_DECLARATION : Scope.TYPE_DECLARATION); types.push(type); return this; } /** Completes the current type declaration. */ public JavaWriter endType() throws IOException { popScope(Scope.TYPE_DECLARATION, Scope.INTERFACE_DECLARATION); types.pop(); indent(); out.write("}\n"); return this; } /** Emits a field declaration. */ public JavaWriter emitField(String type, String name) throws IOException { return emitField(type, name, EnumSet.noneOf(Modifier.class), null); } /** Emits a field declaration. */ public JavaWriter emitField(String type, String name, Set modifiers) throws IOException { return emitField(type, name, modifiers, null); } /** Emits a field declaration. */ public JavaWriter emitField(String type, String name, Set modifiers, String initialValue) throws IOException { indent(); emitModifiers(modifiers); emitCompressedType(type); out.write(" "); out.write(name); if (initialValue != null) { out.write(" ="); if (!initialValue.startsWith("\n")) { out.write(" "); } String[] lines = initialValue.split("\n", -1); out.write(lines[0]); for (int i = 1; i < lines.length; i++) { out.write("\n"); hangingIndent(); out.write(lines[i]); } } out.write(";\n"); return this; } /** * Emit a method declaration. * *

A {@code null} return type may be used to indicate a constructor, but * {@link #beginConstructor(Set, String...)} should be preferred. This behavior may be removed in * a future release. * * @param returnType the method's return type, or null for constructors * @param name the method name, or the fully qualified class name for constructors. * @param modifiers the set of modifiers to be applied to the method * @param parameters alternating parameter types and names. */ public JavaWriter beginMethod(String returnType, String name, Set modifiers, String... parameters) throws IOException { return beginMethod(returnType, name, modifiers, Arrays.asList(parameters), null); } /** * Emit a method declaration. * *

A {@code null} return type may be used to indicate a constructor, but * {@link #beginConstructor(Set, List, List)} should be preferred. This behavior may be removed in * a future release. * * @param returnType the method's return type, or null for constructors. * @param name the method name, or the fully qualified class name for constructors. * @param modifiers the set of modifiers to be applied to the method * @param parameters alternating parameter types and names. * @param throwsTypes the classes to throw, or null for no throws clause. */ public JavaWriter beginMethod(String returnType, String name, Set modifiers, List parameters, List throwsTypes) throws IOException { indent(); emitModifiers(modifiers); if (returnType != null) { emitCompressedType(returnType); out.write(" "); out.write(name); } else { emitCompressedType(name); } out.write("("); if (parameters != null) { for (int p = 0; p < parameters.size();) { if (p != 0) { out.write(", "); } emitCompressedType(parameters.get(p++)); out.write(" "); emitCompressedType(parameters.get(p++)); } } out.write(")"); if (throwsTypes != null && throwsTypes.size() > 0) { out.write("\n"); indent(); out.write(" throws "); for (int i = 0; i < throwsTypes.size(); i++) { if (i != 0) { out.write(", "); } emitCompressedType(throwsTypes.get(i)); } } if (modifiers.contains(ABSTRACT) || Scope.INTERFACE_DECLARATION.equals(scopes.peek())) { out.write(";\n"); scopes.push(Scope.ABSTRACT_METHOD); } else { out.write(" {\n"); scopes.push(returnType == null ? Scope.CONSTRUCTOR : Scope.NON_ABSTRACT_METHOD); } return this; } public JavaWriter beginConstructor(Set modifiers, String... parameters) throws IOException { beginMethod(null, rawType(types.peekFirst()), modifiers, parameters); return this; } public JavaWriter beginConstructor(Set modifiers, List parameters, List throwsTypes) throws IOException { beginMethod(null, rawType(types.peekFirst()), modifiers, parameters, throwsTypes); return this; } /** Emits some Javadoc comments with line separated by {@code \n}. */ public JavaWriter emitJavadoc(String javadoc, Object... params) throws IOException { String formatted = String.format(javadoc, params); indent(); out.write("/**\n"); for (String line : formatted.split("\n")) { indent(); out.write(" *"); if (!line.isEmpty()) { out.write(" "); out.write(line); } out.write("\n"); } indent(); out.write(" */\n"); return this; } /** Emits a single line comment. */ public JavaWriter emitSingleLineComment(String comment, Object... args) throws IOException { indent(); out.write("// "); out.write(String.format(comment, args)); out.write("\n"); return this; } public JavaWriter emitEmptyLine() throws IOException { out.write("\n"); return this; } public JavaWriter emitEnumValue(String name) throws IOException { indent(); out.write(name); out.write(",\n"); return this; } /** * A simple switch to emit the proper enum depending if its last causing it to be terminated * by a semi-colon ({@code ;}). */ public JavaWriter emitEnumValue(String name, boolean isLast) throws IOException { return isLast ? emitLastEnumValue(name) : emitEnumValue(name); } private JavaWriter emitLastEnumValue(String name) throws IOException { indent(); out.write(name); out.write(";\n"); return this; } /** Emit a list of enum values followed by a semi-colon ({@code ;}). */ public JavaWriter emitEnumValues(Iterable names) throws IOException { Iterator iterator = names.iterator(); while (iterator.hasNext()) { String name = iterator.next(); if (iterator.hasNext()) { emitEnumValue(name); } else { emitLastEnumValue(name); } } return this; } /** Equivalent to {@code annotation(annotation, emptyMap())}. */ public JavaWriter emitAnnotation(String annotation) throws IOException { return emitAnnotation(annotation, Collections.emptyMap()); } /** Equivalent to {@code annotation(annotationType.getName(), emptyMap())}. */ public JavaWriter emitAnnotation(Class annotationType) throws IOException { return emitAnnotation(type(annotationType), Collections.emptyMap()); } /** * Annotates the next element with {@code annotationType} and a {@code value}. * * @param value an object used as the default (value) parameter of the annotation. The value will * be encoded using Object.toString(); use {@link #stringLiteral} for String values. Object * arrays are written one element per line. */ public JavaWriter emitAnnotation(Class annotationType, Object value) throws IOException { return emitAnnotation(type(annotationType), value); } /** * Annotates the next element with {@code annotation} and a {@code value}. * * @param value an object used as the default (value) parameter of the annotation. The value will * be encoded using Object.toString(); use {@link #stringLiteral} for String values. Object * arrays are written one element per line. */ public JavaWriter emitAnnotation(String annotation, Object value) throws IOException { indent(); out.write("@"); emitCompressedType(annotation); out.write("("); emitAnnotationValue(value); out.write(")"); out.write("\n"); return this; } /** Equivalent to {@code annotation(annotationType.getName(), attributes)}. */ public JavaWriter emitAnnotation(Class annotationType, Map attributes) throws IOException { return emitAnnotation(type(annotationType), attributes); } /** * Annotates the next element with {@code annotation} and {@code attributes}. * * @param attributes a map from annotation attribute names to their values. Values are encoded * using Object.toString(); use {@link #stringLiteral} for String values. Object arrays are * written one element per line. */ public JavaWriter emitAnnotation(String annotation, Map attributes) throws IOException { indent(); out.write("@"); emitCompressedType(annotation); switch (attributes.size()) { case 0: break; case 1: Entry onlyEntry = attributes.entrySet().iterator().next(); out.write("("); if (!"value".equals(onlyEntry.getKey())) { out.write(onlyEntry.getKey()); out.write(" = "); } emitAnnotationValue(onlyEntry.getValue()); out.write(")"); break; default: boolean split = attributes.size() > MAX_SINGLE_LINE_ATTRIBUTES || containsArray(attributes.values()); out.write("("); scopes.push(Scope.ANNOTATION_ATTRIBUTE); String separator = split ? "\n" : ""; for (Map.Entry entry : attributes.entrySet()) { out.write(separator); separator = split ? ",\n" : ", "; if (split) { indent(); } out.write(entry.getKey()); out.write(" = "); Object value = entry.getValue(); emitAnnotationValue(value); } popScope(Scope.ANNOTATION_ATTRIBUTE); if (split) { out.write("\n"); indent(); } out.write(")"); break; } out.write("\n"); return this; } private boolean containsArray(Collection values) { for (Object value : values) { if (value instanceof Object[]) { return true; } } return false; } /** * Writes a single annotation value. If the value is an array, each element in the array will be * written to its own line. */ private JavaWriter emitAnnotationValue(Object value) throws IOException { if (value instanceof Object[]) { out.write("{"); boolean firstValue = true; scopes.push(Scope.ANNOTATION_ARRAY_VALUE); for (Object o : ((Object[]) value)) { if (firstValue) { firstValue = false; out.write("\n"); } else { out.write(",\n"); } indent(); out.write(o.toString()); } popScope(Scope.ANNOTATION_ARRAY_VALUE); out.write("\n"); indent(); out.write("}"); } else { out.write(value.toString()); } return this; } /** * @param pattern a code pattern like "int i = %s". Newlines will be further indented. Should not * contain trailing semicolon. */ public JavaWriter emitStatement(String pattern, Object... args) throws IOException { checkInMethod(); String[] lines = String.format(pattern, args).split("\n", -1); indent(); out.write(lines[0]); for (int i = 1; i < lines.length; i++) { out.write("\n"); hangingIndent(); out.write(lines[i]); } 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. */ // NOTE: This method is for binary compatibility with previous versions. public JavaWriter beginControlFlow(String controlFlow) throws IOException { return beginControlFlow(controlFlow, new Object[0]); } /** * @param controlFlow the control flow construct and its code, such as "if (foo == 5)". Shouldn't * contain braces or newline characters. */ public JavaWriter beginControlFlow(String controlFlow, Object... args) throws IOException { checkInMethod(); indent(); out.write(String.format(controlFlow, args)); out.write(" {\n"); scopes.push(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. */ // NOTE: This method is for binary compatibility with previous versions. public JavaWriter nextControlFlow(String controlFlow) throws IOException { return nextControlFlow(controlFlow, new Object[0]); } /** * @param controlFlow the control flow construct and its code, such as "else if (foo == 10)". * Shouldn't contain braces or newline characters. */ public JavaWriter nextControlFlow(String controlFlow, Object... args) throws IOException { popScope(Scope.CONTROL_FLOW); indent(); scopes.push(Scope.CONTROL_FLOW); out.write("} "); out.write(String.format(controlFlow, args)); out.write(" {\n"); return this; } 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. */ // NOTE: This method is for binary compatibility with previous versions. public JavaWriter endControlFlow(String controlFlow) throws IOException { return endControlFlow(controlFlow, new Object[0]); } /** * @param controlFlow the optional control flow construct and its code, such as * "while(foo == 20)". Only used for "do/while" control flows. */ public JavaWriter endControlFlow(String controlFlow, Object... args) throws IOException { popScope(Scope.CONTROL_FLOW); indent(); if (controlFlow != null) { out.write("} "); out.write(String.format(controlFlow, args)); out.write(";\n"); } else { out.write("}\n"); } return this; } /** Completes the current method declaration. */ public JavaWriter endMethod() throws IOException { Scope popped = scopes.pop(); // support calling a constructor a "method" to support the legacy code if (popped == Scope.NON_ABSTRACT_METHOD || popped == Scope.CONSTRUCTOR) { indent(); out.write("}\n"); } else if (popped != Scope.ABSTRACT_METHOD) { throw new IllegalStateException(); } return this; } /** Completes the current constructor declaration. */ public JavaWriter endConstructor() throws IOException { popScope(Scope.CONSTRUCTOR); indent(); out.write("}\n"); return this; } /** * Returns the string literal representing {@code data}, including wrapping quotes. * * @deprecated use {@link StringLiteral} and its {@link StringLiteral#literal()} method instead. */ @Deprecated public static String stringLiteral(String data) { return StringLiteral.forValue(data).literal(); } /** Build a string representation of a type and optionally its generic type arguments. */ public static String type(Class raw, String... parameters) { if (parameters.length == 0) { return raw.getCanonicalName(); } if (raw.getTypeParameters().length != parameters.length) { throw new IllegalArgumentException(); } StringBuilder result = new StringBuilder(); result.append(raw.getCanonicalName()); result.append("<"); result.append(parameters[0]); for (int i = 1; i < parameters.length; i++) { result.append(", "); result.append(parameters[i]); } result.append(">"); return result.toString(); } /** Build a string representation of the raw type for a (optionally generic) type. */ public static String rawType(String type) { int lessThanIndex = type.indexOf('<'); if (lessThanIndex != -1) { return type.substring(0, lessThanIndex); } return type; } @Override public void close() throws IOException { out.close(); } /** Emits the modifiers to the writer. */ private void emitModifiers(Set modifiers) throws IOException { if (modifiers.isEmpty()) { return; } // Use an EnumSet to ensure the proper ordering if (!(modifiers instanceof EnumSet)) { modifiers = EnumSet.copyOf(modifiers); } for (Modifier modifier : modifiers) { out.append(modifier.toString()).append(' '); } } private void indent() throws IOException { for (int i = 0, count = scopes.size(); i < count; i++) { out.write(indent); } } private void hangingIndent() throws IOException { for (int i = 0, count = scopes.size() + 2; i < count; i++) { out.write(indent); } } private static final EnumSet METHOD_SCOPES = EnumSet.of( Scope.NON_ABSTRACT_METHOD, Scope.CONSTRUCTOR, Scope.CONTROL_FLOW, Scope.INITIALIZER); private void checkInMethod() { if (!METHOD_SCOPES.contains(scopes.peekFirst())) { throw new IllegalArgumentException(); } } private void popScope(Scope... expected) { if (!EnumSet.copyOf(Arrays.asList(expected)).contains(scopes.pop())) { throw new IllegalStateException(); } } private enum Scope { TYPE_DECLARATION, INTERFACE_DECLARATION, ABSTRACT_METHOD, NON_ABSTRACT_METHOD, CONSTRUCTOR, CONTROL_FLOW, ANNOTATION_ATTRIBUTE, ANNOTATION_ARRAY_VALUE, INITIALIZER } } javawriter-2.5.1/src/main/java/com/squareup/javawriter/StringLiteral.java000066400000000000000000000041061255171556700265770ustar00rootroot00000000000000// Copyright 2014 Square, Inc. package com.squareup.javawriter; import java.util.Formatter; /** * Represents a string literal as found in Java source code. */ public final class StringLiteral { /** Returns a new {@link StringLiteral} instance for the intended value of the literal. */ public static StringLiteral forValue(String value) { return new StringLiteral(value, stringLiteral(value)); } /** Returns the string literal representing {@code data}, including wrapping quotes. */ private static String stringLiteral(String value) { StringBuilder result = new StringBuilder(); result.append('"'); for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); switch (c) { case '"': result.append("\\\""); break; case '\\': result.append("\\\\"); break; case '\b': result.append("\\b"); break; case '\t': result.append("\\t"); break; case '\n': result.append("\\n"); break; case '\f': result.append("\\f"); break; case '\r': result.append("\\r"); break; default: if (Character.isISOControl(c)) { new Formatter(result).format("\\u%04x", (int) c); } else { result.append(c); } } } result.append('"'); return result.toString(); } private final String value; private final String literal; private StringLiteral(String value, String literal) { this.value = value; this.literal = literal; } public String value() { return value; } public String literal() { return literal; } @Override public String toString() { return literal; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj instanceof StringLiteral) { return this.value.equals(((StringLiteral) obj).value); } else { return false; } } @Override public int hashCode() { return value.hashCode(); } } javawriter-2.5.1/src/test/000077500000000000000000000000001255171556700154615ustar00rootroot00000000000000javawriter-2.5.1/src/test/java/000077500000000000000000000000001255171556700164025ustar00rootroot00000000000000javawriter-2.5.1/src/test/java/com/000077500000000000000000000000001255171556700171605ustar00rootroot00000000000000javawriter-2.5.1/src/test/java/com/example/000077500000000000000000000000001255171556700206135ustar00rootroot00000000000000javawriter-2.5.1/src/test/java/com/example/Binding.java000066400000000000000000000001211255171556700230220ustar00rootroot00000000000000// Copyright 2013 Square, Inc. package com.example; public class Binding { } javawriter-2.5.1/src/test/java/com/squareup/000077500000000000000000000000001255171556700210255ustar00rootroot00000000000000javawriter-2.5.1/src/test/java/com/squareup/javawriter/000077500000000000000000000000001255171556700232035ustar00rootroot00000000000000javawriter-2.5.1/src/test/java/com/squareup/javawriter/JavaWriterTest.java000066400000000000000000001015551255171556700267730ustar00rootroot00000000000000// Copyright 2013 Square, Inc. package com.squareup.javawriter; import com.example.Binding; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.lang.model.element.Modifier; import org.junit.Test; import static javax.lang.model.element.Modifier.ABSTRACT; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PRIVATE; import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; import static org.fest.assertions.api.Assertions.assertThat; import static org.fest.assertions.api.Assertions.failBecauseExceptionWasNotThrown; public final class JavaWriterTest { private final StringWriter stringWriter = new StringWriter(); private final JavaWriter javaWriter = new JavaWriter(stringWriter); @Test public void typeDeclaration() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "public final class Foo {\n" + "}\n"); } @Test public void enumDeclaration() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "enum", EnumSet.of(PUBLIC)); javaWriter.emitEnumValue("BAR"); javaWriter.emitEnumValue("BAZ"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "public enum Foo {\n" + " BAR,\n" + " BAZ,\n" + "}\n"); } @Test public void enumDeclarationWithMethod() throws IOException{ javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "enum", EnumSet.of(PUBLIC)); javaWriter.emitEnumValues(Arrays.asList("BAR", "BAZ")); javaWriter.beginMethod("void", "foo", EnumSet.of(PUBLIC)); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "public enum Foo {\n" + " BAR,\n" + " BAZ;\n" + " public void foo() {\n" + " }\n" + "}\n"); } @Test public void enumDeclarationWithAnnotationAndMethod() throws IOException{ javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "enum", EnumSet.of(PUBLIC)); List list = Arrays.asList("BAR", "BAZ"); int index = 0; for (Iterator i = list.iterator(); i.hasNext(); ) { javaWriter.emitAnnotation("ProtoEnum", index); javaWriter.emitEnumValue(i.next(), !i.hasNext()); index++; } javaWriter.beginMethod("void", "foo", EnumSet.of(PUBLIC)); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "public enum Foo {\n" + " @ProtoEnum(0)\n" + " BAR,\n" + " @ProtoEnum(1)\n" + " BAZ;\n" + " public void foo() {\n" + " }\n" + "}\n"); } @Test public void fieldDeclaration() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.emitField("java.lang.String", "string", EnumSet.of(PRIVATE, STATIC)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " private static String string;\n" + "}\n"); } @Test public void fieldDeclarationWithInitialValue() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.emitField("java.lang.String", "string", EnumSet.noneOf(Modifier.class), "\"bar\" + \"baz\""); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " String string = \"bar\" + \"baz\";\n" + "}\n"); } @Test public void fieldDeclarationWithWrappingInitialValue() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.emitField("java.lang.String", "string", EnumSet.noneOf(Modifier.class), "\"bar\"\n+ \"baz\"\n+ \"biz\""); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " String string = \"bar\"\n" + " + \"baz\"\n" + " + \"biz\";\n" + "}\n"); } // If the initializer begins with a newline, don't emit a space after the '='. @Test public void fieldDeclarationWithNewlineInitialValue() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.emitField("java.lang.String", "string", EnumSet.noneOf(Modifier.class), "\n\"bar\"\n+ \"baz\"\n+ \"biz\""); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " String string =\n" + " \"bar\"\n" + " + \"baz\"\n" + " + \"biz\";\n" + "}\n"); } @Test public void abstractMethodDeclaration() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("java.lang.String", "foo", EnumSet.of(ABSTRACT, PUBLIC), "java.lang.Object", "object", "java.lang.String", "s"); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " public abstract String foo(Object object, String s);\n" + "}\n"); } @Test public void abstractMethodDeclarationWithThrows() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("java.lang.String", "foo", EnumSet.of(ABSTRACT, PUBLIC), Arrays.asList("java.lang.Object", "object", "java.lang.String", "s"), Arrays.asList("java.io.IOException")); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " public abstract String foo(Object object, String s)\n" + " throws java.io.IOException;\n" + "}\n"); } @Test public void nonAbstractMethodDeclaration() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("int", "foo", EnumSet.noneOf(Modifier.class), "java.lang.String", "s"); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " int foo(String s) {\n" + " }\n" + "}\n"); } @Test public void nonAbstractMethodDeclarationWithThrows() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("int", "foo", EnumSet.noneOf(Modifier.class), Arrays.asList("java.lang.String", "s"), Arrays.asList("java.io.IOException")); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " int foo(String s)\n" + " throws java.io.IOException {\n" + " }\n" + "}\n"); } @Test public void interfaceMethodDeclaration() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "interface"); javaWriter.beginMethod("java.lang.String", "foo", EnumSet.noneOf(Modifier.class), "java.lang.Object", "object", "java.lang.String", "s"); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "interface Foo {\n" + " String foo(Object object, String s);\n" + "}\n"); } @Test public void interfaceMethodDeclarationWithThrows() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "interface"); javaWriter.beginMethod("java.lang.String", "foo", EnumSet.noneOf(Modifier.class), Arrays.asList("java.lang.Object", "object", "java.lang.String", "s"), Arrays.asList("java.io.IOException")); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "interface Foo {\n" + " String foo(Object object, String s)\n" + " throws java.io.IOException;\n" + "}\n"); } @Test public void constructorDeclaration() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginConstructor(EnumSet.of(PUBLIC), "java.lang.String", "s"); javaWriter.endConstructor(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " public Foo(String s) {\n" + " }\n" + "}\n"); } @Test public void simpleConstructor() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginConstructor(EnumSet.of(PUBLIC), "java.lang.String", "s"); javaWriter.emitStatement("if (%s == null) throw new NullPointerException()", "s"); javaWriter.endConstructor(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " public Foo(String s) {\n" + " if (s == null) throw new NullPointerException();\n" + " }\n" + "}\n"); } @Test public void genericsConstructor() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.emitField("T", "fooType", EnumSet.of(PRIVATE)); javaWriter.beginConstructor(EnumSet.of(PUBLIC), "T", "s"); javaWriter.emitStatement("if (%s == null) throw new NullPointerException()", "s"); javaWriter.endConstructor(); javaWriter.beginMethod("T", "getFooType", EnumSet.of(PUBLIC)); javaWriter.emitStatement("return fooType"); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " private T fooType;\n" + " public Foo(T s) {\n" + " if (s == null) throw new NullPointerException();\n" + " }\n" + " public T getFooType() {\n" + " return fooType;\n" + " }\n" + "}\n"); } @Test public void constructorDeclarationInNestedTypes() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginConstructor(EnumSet.of(PUBLIC), "java.lang.String", "s"); javaWriter.endConstructor(); javaWriter.beginType("com.squareup.Bar", "class"); javaWriter.beginConstructor(EnumSet.noneOf(Modifier.class)); javaWriter.endConstructor(); javaWriter.endType(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " public Foo(String s) {\n" + " }\n" + " class Bar {\n" + " Bar() {\n" + " }\n" + " }\n" + "}\n"); } @Test public void constructorDeclarationWithThrows() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginConstructor(EnumSet.of(PUBLIC), Arrays.asList("java.lang.String", "s"), Arrays.asList("java.io.IOException")); javaWriter.endConstructor(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " public Foo(String s)\n" + " throws java.io.IOException {\n" + " }\n" + "}\n"); } @Test public void statement() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("int", "foo", EnumSet.noneOf(Modifier.class), "java.lang.String", "s"); javaWriter.emitStatement("int j = s.length() + %s", 13); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " int foo(String s) {\n" + " int j = s.length() + 13;\n" + " }\n" + "}\n"); } @Test public void statementPrecededByComment() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("int", "foo", EnumSet.noneOf(Modifier.class), "java.lang.String", "s"); javaWriter.emitSingleLineComment("foo"); javaWriter.emitStatement("int j = s.length() + %s", 13); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " int foo(String s) {\n" + " // foo\n" + " int j = s.length() + 13;\n" + " }\n" + "}\n"); } @Test public void multiLineStatement() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Triangle", "class"); javaWriter.beginMethod("double", "pythagorean", EnumSet.noneOf(Modifier.class), "int", "a", "int", "b"); javaWriter.emitStatement("int cSquared = a * a\n+ b * b"); javaWriter.emitStatement("return Math.sqrt(cSquared)"); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Triangle {\n" + " double pythagorean(int a, int b) {\n" + " int cSquared = a * a\n" + " + b * b;\n" + " return Math.sqrt(cSquared);\n" + " }\n" + "}\n"); } @Test public void addImport() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitImports("java.util.ArrayList"); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.emitField("java.util.ArrayList", "list", EnumSet.noneOf(Modifier.class), "new java.util.ArrayList()"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "import java.util.ArrayList;\n" + "public final class Foo {\n" + " ArrayList list = new java.util.ArrayList();\n" + "}\n"); } @Test public void addImportAsClass() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitImports(ArrayList.class); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.emitField("java.util.ArrayList", "list", EnumSet.noneOf(Modifier.class), "new java.util.ArrayList()"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "import java.util.ArrayList;\n" + "public final class Foo {\n" + " ArrayList list = new java.util.ArrayList();\n" + "}\n"); } @Test public void addStaticImport() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitStaticImports("java.lang.System.getProperty"); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.emitField("String", "bar", EnumSet.noneOf(Modifier.class), "getProperty(\"bar\")"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "import static java.lang.System.getProperty;\n" + "public final class Foo {\n" + " String bar = getProperty(\"bar\");\n" + "}\n"); } @Test public void addNestedClassImportAsClass() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitImports(NestedClass.class); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.emitField("com.squareup.javawriter.JavaWriterTest.NestedClass", "nestedClass", EnumSet.noneOf(Modifier.class), "new NestedClass()"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "import com.squareup.javawriter.JavaWriterTest.NestedClass;\n" + "public final class Foo {\n" + " NestedClass nestedClass = new NestedClass();\n" + "}\n"); } public static class NestedClass {} @Test public void addStaticWildcardImport() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitStaticImports("java.lang.System.*"); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.emitField("String", "bar", EnumSet.noneOf(Modifier.class), "getProperty(\"bar\")"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "import static java.lang.System.*;\n" + "public final class Foo {\n" + " String bar = getProperty(\"bar\");\n" + "}\n"); } @Test public void emptyImports() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitImports(Collections.emptyList()); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "public final class Foo {\n" + "}\n"); } @Test public void emptyStaticImports() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitStaticImports(Collections.emptyList()); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "public final class Foo {\n" + "}\n"); } @Test public void addImportFromSubpackage() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class", EnumSet.of(PUBLIC, FINAL)); javaWriter.emitField("com.squareup.bar.Baz", "baz"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "public final class Foo {\n" + " com.squareup.bar.Baz baz;\n" + "}\n"); } @Test public void ifControlFlow() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("int", "foo", EnumSet.noneOf(Modifier.class), "java.lang.String", "s"); javaWriter.beginControlFlow("if (s.isEmpty())"); javaWriter.emitStatement("int j = s.length() + %s", 13); javaWriter.endControlFlow(); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " int foo(String s) {\n" + " if (s.isEmpty()) {\n" + " int j = s.length() + 13;\n" + " }\n" + " }\n" + "}\n"); } @Test public void doWhileControlFlow() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("int", "foo", EnumSet.noneOf(Modifier.class), "java.lang.String", "s"); javaWriter.beginControlFlow("do"); javaWriter.emitStatement("int j = s.length() + %s", 13); javaWriter.endControlFlow("while (s.isEmpty())"); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " int foo(String s) {\n" + " do {\n" + " int j = s.length() + 13;\n" + " } while (s.isEmpty());\n" + " }\n" + "}\n"); } @Test public void tryCatchFinallyControlFlow() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.beginMethod("int", "foo", EnumSet.noneOf(Modifier.class), "java.lang.String", "s"); javaWriter.beginControlFlow("try"); javaWriter.emitStatement("int j = s.length() + %s", 13); javaWriter.nextControlFlow("catch (RuntimeException e)"); javaWriter.emitStatement("e.printStackTrace()"); javaWriter.nextControlFlow("finally"); javaWriter.emitStatement("int k = %s", 13); javaWriter.endControlFlow(); javaWriter.endMethod(); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " int foo(String s) {\n" + " try {\n" + " int j = s.length() + 13;\n" + " } catch (RuntimeException e) {\n" + " e.printStackTrace();\n" + " } finally {\n" + " int k = 13;\n" + " }\n" + " }\n" + "}\n"); } @Test public void annotatedType() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitImports("javax.inject.Singleton"); javaWriter.emitAnnotation("javax.inject.Singleton"); javaWriter.emitAnnotation(SuppressWarnings.class, StringLiteral.forValue("unchecked")); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "import javax.inject.Singleton;\n" + "@Singleton\n" + "@SuppressWarnings(\"unchecked\")\n" + "class Foo {\n" + "}\n"); } @Test public void annotatedMember() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.emitAnnotation(Deprecated.class); javaWriter.emitField("java.lang.String", "s"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " @Deprecated\n" + " String s;\n" + "}\n"); } @Test public void annotatedWithSingleAttribute() throws IOException { Map attributes = new LinkedHashMap(); attributes.put("overrides", true); javaWriter.emitPackage("com.squareup"); javaWriter.emitAnnotation("Module", attributes); javaWriter.beginType("com.squareup.FooModule", "class", EnumSet.noneOf(Modifier.class)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "@Module(overrides = true)\n" + "class FooModule {\n" + "}\n"); } @Test public void annotatedWithSingleValueAttribute() throws IOException { Map attributes = new LinkedHashMap(); attributes.put("value", StringLiteral.forValue("blah.Generator")); javaWriter.emitPackage("com.squareup"); javaWriter.emitAnnotation("Generated", attributes); javaWriter.beginType("com.squareup.FooModule", "class", EnumSet.noneOf(Modifier.class)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "@Generated(\"blah.Generator\")\n" + "class FooModule {\n" + "}\n"); } @Test public void annotatedWithTwoNonArrayAttributes() throws IOException { Map attributes = new LinkedHashMap(); attributes.put("overrides", true); attributes.put("foo", "bar"); javaWriter.emitPackage("com.squareup"); javaWriter.emitAnnotation("Module", attributes); javaWriter.beginType("com.squareup.FooModule", "class", EnumSet.noneOf(Modifier.class)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "@Module(overrides = true, foo = bar)\n" + "class FooModule {\n" + "}\n"); } @Test public void annotatedWithThreeNonArrayAttributes() throws IOException { Map attributes = new LinkedHashMap(); attributes.put("overrides", true); attributes.put("foo", "bar"); attributes.put("bar", "baz"); javaWriter.emitPackage("com.squareup"); javaWriter.emitAnnotation("Module", attributes); javaWriter.beginType("com.squareup.FooModule", "class", EnumSet.noneOf(Modifier.class)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "@Module(overrides = true, foo = bar, bar = baz)\n" + "class FooModule {\n" + "}\n"); } @Test public void annotatedWithAttributes() throws IOException { Map attributes = new LinkedHashMap(); attributes.put("overrides", true); attributes.put("entryPoints", new Object[] { "entryPointA", "entryPointB", "entryPointC" }); attributes.put("staticInjections", "com.squareup.Quux"); javaWriter.emitPackage("com.squareup"); javaWriter.emitAnnotation("Module", attributes); javaWriter.beginType("com.squareup.FooModule", "class"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "@Module(\n" + " overrides = true,\n" + " entryPoints = {\n" + " entryPointA,\n" + " entryPointB,\n" + " entryPointC\n" + " },\n" + " staticInjections = com.squareup.Quux\n" + ")\n" + "class FooModule {\n" + "}\n"); } @Test public void parameterizedType() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.emitImports("java.util.Map", "java.util.Date"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.emitField("java.util.Map", "map", EnumSet.noneOf(Modifier.class)); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "import java.util.Date;\n" + "import java.util.Map;\n" + "class Foo {\n" + " Map map;\n" + "}\n"); } @Test public void eolComment() throws IOException { javaWriter.emitSingleLineComment("foo"); assertCode("// foo\n"); } @Test public void javadoc() throws IOException { javaWriter.emitJavadoc("foo"); assertCode("" + "/**\n" + " * foo\n" + " */\n"); } @Test public void multilineJavadoc() throws IOException { javaWriter.emitJavadoc("0123456789 0123456789 0123456789 0123456789 0123456789 0123456789\n" + "0123456789 0123456789 0123456789 0123456789"); assertCode("" + "/**\n" + " * 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789\n" + " * 0123456789 0123456789 0123456789 0123456789\n" + " */\n"); } @Test public void multilineJavadocDoesNotEmitTrailingSpaceForEmptyLines() throws IOException { javaWriter.emitJavadoc("Foo\n\nBar"); assertCode("" + "/**\n" + " * Foo\n" + " *\n" + " * Bar\n" + " */\n" ); } @Test public void testType() { assertThat(JavaWriter.type(String.class)).as("simple type").isEqualTo("java.lang.String"); assertThat(JavaWriter.type(Set.class)).as("raw type").isEqualTo("java.util.Set"); assertThat(JavaWriter.type(Set.class, "?")).as("wildcard type").isEqualTo("java.util.Set"); assertThat(JavaWriter.type(Map.class, JavaWriter.type(String.class), "?")) .as("mixed type and wildcard generic type parameters") .isEqualTo("java.util.Map"); try { JavaWriter.type(String.class, "foo"); failBecauseExceptionWasNotThrown(IllegalArgumentException.class); } catch (Throwable e) { assertThat(e).as("parameterized non-generic").isInstanceOf(IllegalArgumentException.class); } try { JavaWriter.type(Map.class, "foo"); failBecauseExceptionWasNotThrown(IllegalArgumentException.class); } catch (Throwable e) { assertThat(e).as("too few type arguments").isInstanceOf(IllegalArgumentException.class); } try { JavaWriter.type(Set.class, "foo", "bar"); failBecauseExceptionWasNotThrown(IllegalArgumentException.class); } catch (Throwable e) { assertThat(e).as("too many type arguments").isInstanceOf(IllegalArgumentException.class); } } @Test public void testRawType() { assertThat(JavaWriter.rawType(JavaWriter.type(Set.class))) .as("raw type").isEqualTo("java.util.Set"); assertThat(JavaWriter.rawType(JavaWriter.type(Set.class, "?"))) .as("wildcard type").isEqualTo("java.util.Set"); assertThat(JavaWriter.rawType(JavaWriter.type(Set.class, "String"))) .as("parameterized type").isEqualTo("java.util.Set"); assertThat(JavaWriter.rawType(JavaWriter.type(Map.class, "String", "Integer"))) .as("parameterized type").isEqualTo("java.util.Map"); assertThat(JavaWriter.rawType("java.util.Set>")) .as("nested parameterized type").isEqualTo("java.util.Set"); } @Test public void compressType() throws IOException { javaWriter.emitPackage("com.blah"); javaWriter.emitImports(Set.class.getCanonicalName(), Binding.class.getCanonicalName()); String actual = javaWriter.compressType("java.util.Set>"); assertThat(actual).isEqualTo("Set>"); } @Test public void compressDeeperType() throws IOException { javaWriter.emitPackage("com.blah"); javaWriter.emitImports(Binding.class.getCanonicalName()); String actual = javaWriter.compressType("com.example.Binding"); assertThat(actual).isEqualTo("Binding"); } @Test public void compressNestedType() throws IOException { javaWriter.emitPackage("com.blah"); String actual = javaWriter.compressType("com.blah.Enclosing.Nested"); assertThat(actual).isEqualTo("Enclosing.Nested"); } @Test public void compressWildcardType() throws IOException { javaWriter.emitPackage("com.blah"); javaWriter.emitImports(Binding.class.getCanonicalName()); String actual = javaWriter.compressType("com.example.Binding"); assertThat(actual).isEqualTo("Binding"); } @Test public void compressSimpleNameCollisionInSamePackage() throws IOException { javaWriter.emitPackage("denominator"); javaWriter.emitImports("javax.inject.Provider", "dagger.internal.Binding"); String actual = javaWriter.compressType("dagger.internal.Binding"); assertThat(actual).isEqualTo("Binding"); } @Test public void compressJavaLangClass() throws IOException { javaWriter.emitPackage("com.blah"); String actual = javaWriter.compressType("java.lang.Class"); assertThat(actual).isEqualTo("Class"); } @Test public void compressJavaLangSubPackageClass() throws IOException { javaWriter.emitPackage("com.blah"); String actual = javaWriter.compressType("java.lang.annotation.Annotation"); assertThat(actual).isEqualTo("java.lang.annotation.Annotation"); } @Test public void compressVarargsType() throws IOException { javaWriter.emitPackage("com.blah"); javaWriter.emitImports("java.util.File"); String actual = javaWriter.compressType("java.util.File..."); assertThat(actual).isEqualTo("File..."); } @Test public void compressArrayType() throws IOException { javaWriter.emitPackage("com.blah"); javaWriter.emitImports("java.util.File"); String actual1 = javaWriter.compressType("java.util.File[]"); assertThat(actual1).isEqualTo("File[]"); String actual2 = javaWriter.compressType("java.util.File[][][]"); assertThat(actual2).isEqualTo("File[][][]"); } @Test public void configurableIndent() throws IOException { javaWriter.setIndent(" "); javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class"); javaWriter.emitField("String", "bar"); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + " String bar;\n" + "}\n"); } @Test public void outOfOrderModifierSet() throws IOException { Set modifiers = new LinkedHashSet(Arrays.asList(FINAL, PUBLIC)); javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class", modifiers); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "public final class Foo {\n" + "}\n"); } @Test public void emptyNonEnumModifierSet() throws IOException { javaWriter.emitPackage("com.squareup"); javaWriter.beginType("com.squareup.Foo", "class", new LinkedHashSet()); javaWriter.endType(); assertCode("" + "package com.squareup;\n" + "\n" + "class Foo {\n" + "}\n"); } private void assertCode(String expected) { assertThat(stringWriter.toString()).isEqualTo(expected); } } javawriter-2.5.1/src/test/java/com/squareup/javawriter/StringLiteralTest.java000066400000000000000000000033021255171556700274670ustar00rootroot00000000000000// Copyright 2014 Square, Inc. package com.squareup.javawriter; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import static org.fest.assertions.api.Assertions.assertThat; @RunWith(JUnit4.class) public final class StringLiteralTest { @Test public void stringLiteral() { assertThat(StringLiteral.forValue("").toString()).isEqualTo("\"\""); assertThat(StringLiteral.forValue("JavaWriter").toString()).isEqualTo("\"JavaWriter\""); assertThat(StringLiteral.forValue("\\").toString()).isEqualTo("\"\\\\\""); assertThat(StringLiteral.forValue("\"").toString()).isEqualTo("\"\\\"\""); assertThat(StringLiteral.forValue("\b").toString()).isEqualTo("\"\\b\""); assertThat(StringLiteral.forValue("\t").toString()).isEqualTo("\"\\t\""); assertThat(StringLiteral.forValue("\n").toString()).isEqualTo("\"\\n\""); assertThat(StringLiteral.forValue("\f").toString()).isEqualTo("\"\\f\""); assertThat(StringLiteral.forValue("\r").toString()).isEqualTo("\"\\r\""); // Control characters for (char i = 0x1; i <= 0x1f; i++) { checkCharEscape(i); } for (char i = 0x7f; i <= 0x9f; i++) { checkCharEscape(i); } } private void checkCharEscape(char codePoint) { String test = "" + codePoint; String expected; switch (codePoint) { case 8: expected = "\"\\b\""; break; case 9: expected = "\"\\t\""; break; case 10: expected = "\"\\n\""; break; case 12: expected = "\"\\f\""; break; case 13: expected = "\"\\r\""; break; default: expected = "\"\\u" + String.format("%04x", (int) codePoint) + "\""; } assertThat(StringLiteral.forValue(test).toString()).isEqualTo(expected); } }