com.salesforce.squareup.javapoet.JavaFile Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of AptSpringProcessor Show documentation
Show all versions of AptSpringProcessor Show documentation
This project contains the apt processor that implements all the checks enumerated in @Verify. It is a self contained, and
shaded jar.
The newest version!
/*
* Copyright (C) 2015 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.
*/
package com.salesforce.squareup.javapoet;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.annotation.processing.Filer;
import javax.lang.model.element.Element;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
import static com.salesforce.squareup.javapoet.Util.checkArgument;
import static com.salesforce.squareup.javapoet.Util.checkNotNull;
import static java.nio.charset.StandardCharsets.UTF_8;
/** A Java file containing a single top level class. */
public final class JavaFile {
private static final Appendable NULL_APPENDABLE = new Appendable() {
@Override public Appendable append(CharSequence charSequence) {
return this;
}
@Override public Appendable append(CharSequence charSequence, int start, int end) {
return this;
}
@Override public Appendable append(char c) {
return this;
}
};
public final CodeBlock fileComment;
public final String packageName;
public final TypeSpec typeSpec;
public final boolean skipJavaLangImports;
private final Set staticImports;
private final String indent;
private JavaFile(Builder builder) {
this.fileComment = builder.fileComment.build();
this.packageName = builder.packageName;
this.typeSpec = builder.typeSpec;
this.skipJavaLangImports = builder.skipJavaLangImports;
this.staticImports = Util.immutableSet(builder.staticImports);
this.indent = builder.indent;
}
public void writeTo(Appendable out) throws IOException {
// First pass: emit the entire class, just to collect the types we'll need to import.
CodeWriter importsCollector = new CodeWriter(NULL_APPENDABLE, indent, staticImports);
emit(importsCollector);
Map suggestedImports = importsCollector.suggestedImports();
// Second pass: write the code, taking advantage of the imports.
CodeWriter codeWriter = new CodeWriter(out, indent, suggestedImports, staticImports);
emit(codeWriter);
}
/** Writes this to {@code directory} as UTF-8 using the standard directory structure. */
public void writeTo(Path directory) throws IOException {
checkArgument(Files.notExists(directory) || Files.isDirectory(directory),
"path %s exists but is not a directory.", directory);
Path outputDirectory = directory;
if (!packageName.isEmpty()) {
for (String packageComponent : packageName.split("\\.")) {
outputDirectory = outputDirectory.resolve(packageComponent);
}
Files.createDirectories(outputDirectory);
}
Path outputPath = outputDirectory.resolve(typeSpec.name + ".java");
try (Writer writer = new OutputStreamWriter(Files.newOutputStream(outputPath), UTF_8)) {
writeTo(writer);
}
}
/** Writes this to {@code directory} as UTF-8 using the standard directory structure. */
public void writeTo(File directory) throws IOException {
writeTo(directory.toPath());
}
/** Writes this to {@code filer}. */
public void writeTo(Filer filer) throws IOException {
String fileName = packageName.isEmpty()
? typeSpec.name
: packageName + "." + typeSpec.name;
List originatingElements = typeSpec.originatingElements;
JavaFileObject filerSourceFile = filer.createSourceFile(fileName,
originatingElements.toArray(new Element[originatingElements.size()]));
try (Writer writer = filerSourceFile.openWriter()) {
writeTo(writer);
} catch (Exception e) {
try {
filerSourceFile.delete();
} catch (Exception ignored) {
}
throw e;
}
}
private void emit(CodeWriter codeWriter) throws IOException {
codeWriter.pushPackage(packageName);
if (!fileComment.isEmpty()) {
codeWriter.emitComment(fileComment);
}
if (!packageName.isEmpty()) {
codeWriter.emit("package $L;\n", packageName);
codeWriter.emit("\n");
}
if (!staticImports.isEmpty()) {
for (String signature : staticImports) {
codeWriter.emit("import static $L;\n", signature);
}
codeWriter.emit("\n");
}
int importedTypesCount = 0;
for (ClassName className : new TreeSet<>(codeWriter.importedTypes().values())) {
if (skipJavaLangImports && className.packageName().equals("java.lang")) continue;
codeWriter.emit("import $L;\n", className.withoutAnnotations());
importedTypesCount++;
}
if (importedTypesCount > 0) {
codeWriter.emit("\n");
}
typeSpec.emit(codeWriter, null, Collections.emptySet());
codeWriter.popPackage();
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (getClass() != o.getClass()) return false;
return toString().equals(o.toString());
}
@Override public int hashCode() {
return toString().hashCode();
}
@Override public String toString() {
try {
StringBuilder result = new StringBuilder();
writeTo(result);
return result.toString();
} catch (IOException e) {
throw new AssertionError();
}
}
public JavaFileObject toJavaFileObject() {
URI uri = URI.create((packageName.isEmpty()
? typeSpec.name
: packageName.replace('.', '/') + '/' + typeSpec.name)
+ Kind.SOURCE.extension);
return new SimpleJavaFileObject(uri, Kind.SOURCE) {
private final long lastModified = System.currentTimeMillis();
@Override public String getCharContent(boolean ignoreEncodingErrors) {
return JavaFile.this.toString();
}
@Override public InputStream openInputStream() throws IOException {
return new ByteArrayInputStream(getCharContent(true).getBytes(UTF_8));
}
@Override public long getLastModified() {
return lastModified;
}
};
}
public static Builder builder(String packageName, TypeSpec typeSpec) {
checkNotNull(packageName, "packageName == null");
checkNotNull(typeSpec, "typeSpec == null");
return new Builder(packageName, typeSpec);
}
public Builder toBuilder() {
Builder builder = new Builder(packageName, typeSpec);
builder.fileComment.add(fileComment);
builder.skipJavaLangImports = skipJavaLangImports;
builder.indent = indent;
return builder;
}
public static final class Builder {
private final String packageName;
private final TypeSpec typeSpec;
private final CodeBlock.Builder fileComment = CodeBlock.builder();
private final Set staticImports = new TreeSet<>();
private boolean skipJavaLangImports;
private String indent = " ";
private Builder(String packageName, TypeSpec typeSpec) {
this.packageName = packageName;
this.typeSpec = typeSpec;
}
public Builder addFileComment(String format, Object... args) {
this.fileComment.add(format, args);
return this;
}
public Builder addStaticImport(Enum> constant) {
return addStaticImport(ClassName.get(constant.getDeclaringClass()), constant.name());
}
public Builder addStaticImport(Class> clazz, String... names) {
return addStaticImport(ClassName.get(clazz), names);
}
public Builder addStaticImport(ClassName className, String... names) {
checkArgument(className != null, "className == null");
checkArgument(names != null, "names == null");
checkArgument(names.length > 0, "names array is empty");
for (String name : names) {
checkArgument(name != null, "null entry in names array: %s", Arrays.toString(names));
staticImports.add(className.canonicalName + "." + name);
}
return this;
}
/**
* Call this to omit imports for classes in {@code java.lang}, such as {@code java.lang.String}.
*
* By default, JavaPoet explicitly imports types in {@code java.lang} to defend against
* naming conflicts. Suppose an (ill-advised) class is named {@code com.example.String}. When
* {@code java.lang} imports are skipped, generated code in {@code com.example} that references
* {@code java.lang.String} will get {@code com.example.String} instead.
*/
public Builder skipJavaLangImports(boolean skipJavaLangImports) {
this.skipJavaLangImports = skipJavaLangImports;
return this;
}
public Builder indent(String indent) {
this.indent = indent;
return this;
}
public JavaFile build() {
return new JavaFile(this);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy