aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/squareup/javapoet
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/squareup/javapoet')
-rw-r--r--src/main/java/com/squareup/javapoet/AnnotationSpec.java60
-rw-r--r--src/main/java/com/squareup/javapoet/ClassName.java63
-rw-r--r--src/main/java/com/squareup/javapoet/CodeBlock.java8
-rw-r--r--src/main/java/com/squareup/javapoet/CodeWriter.java51
-rw-r--r--src/main/java/com/squareup/javapoet/FieldSpec.java16
-rw-r--r--src/main/java/com/squareup/javapoet/JavaFile.java10
-rw-r--r--src/main/java/com/squareup/javapoet/JavaPoet.java6
-rw-r--r--src/main/java/com/squareup/javapoet/MethodSpec.java34
-rw-r--r--src/main/java/com/squareup/javapoet/ParameterSpec.java15
-rw-r--r--src/main/java/com/squareup/javapoet/TypeSpec.java119
-rw-r--r--src/main/java/com/squareup/javapoet/Types.java44
-rw-r--r--src/main/java/com/squareup/javapoet/Util.java93
12 files changed, 288 insertions, 231 deletions
diff --git a/src/main/java/com/squareup/javapoet/AnnotationSpec.java b/src/main/java/com/squareup/javapoet/AnnotationSpec.java
index c70783b..721fce6 100644
--- a/src/main/java/com/squareup/javapoet/AnnotationSpec.java
+++ b/src/main/java/com/squareup/javapoet/AnnotationSpec.java
@@ -15,33 +15,25 @@
*/
package com.squareup.javapoet;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.TreeMap;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.squareup.javapoet.Util.checkNotNull;
/** A generated annotation on a declaration. */
public final class AnnotationSpec {
public final Type type;
- public final ImmutableMultimap<String, CodeBlock> members;
+ public final Map<String, List<CodeBlock>> members;
private AnnotationSpec(Builder builder) {
this.type = builder.type;
- this.members = ImmutableListMultimap.copyOf(builder.members);
+ this.members = Util.immutableMultimap(builder.members);
}
void emit(CodeWriter codeWriter, boolean inline) throws IOException {
@@ -50,10 +42,10 @@ public final class AnnotationSpec {
if (members.isEmpty()) {
// @Singleton
codeWriter.emit("@$T", type);
- } else if (members.keySet().equals(ImmutableSet.of("value"))) {
+ } else if (members.size() == 1 && members.containsKey("value")) {
// @Named("foo")
codeWriter.emit("@$T(", type);
- emitAnnotationValue(codeWriter, whitespace, memberSeparator, members.values());
+ emitAnnotationValues(codeWriter, whitespace, memberSeparator, members.get("value"));
codeWriter.emit(")");
} else {
// Inline:
@@ -66,11 +58,11 @@ public final class AnnotationSpec {
// )
codeWriter.emit("@$T(" + whitespace, type);
codeWriter.indent(2);
- for (Iterator<Map.Entry<String, Collection<CodeBlock>>> i
- = members.asMap().entrySet().iterator(); i.hasNext();) {
- Map.Entry<String, Collection<CodeBlock>> entry = i.next();
+ for (Iterator<Map.Entry<String, List<CodeBlock>>> i
+ = members.entrySet().iterator(); i.hasNext();) {
+ Map.Entry<String, List<CodeBlock>> entry = i.next();
codeWriter.emit("$L = ", entry.getKey());
- emitAnnotationValue(codeWriter, whitespace, memberSeparator, entry.getValue());
+ emitAnnotationValues(codeWriter, whitespace, memberSeparator, entry.getValue());
if (i.hasNext()) codeWriter.emit(memberSeparator);
}
codeWriter.unindent(2);
@@ -78,11 +70,11 @@ public final class AnnotationSpec {
}
}
- private void emitAnnotationValue(CodeWriter codeWriter, String whitespace, String memberSeparator,
- Collection<CodeBlock> value) throws IOException {
- if (value.size() == 1) {
+ private void emitAnnotationValues(CodeWriter codeWriter, String whitespace,
+ String memberSeparator, List<CodeBlock> values) throws IOException {
+ if (values.size() == 1) {
codeWriter.indent(2);
- codeWriter.emit(getOnlyElement(value));
+ codeWriter.emit(values.get(0));
codeWriter.unindent(2);
return;
}
@@ -90,7 +82,7 @@ public final class AnnotationSpec {
codeWriter.emit("{" + whitespace);
codeWriter.indent(2);
boolean first = true;
- for (CodeBlock codeBlock : value) {
+ for (CodeBlock codeBlock : values) {
if (!first) codeWriter.emit(memberSeparator);
codeWriter.emit(codeBlock);
first = false;
@@ -127,15 +119,23 @@ public final class AnnotationSpec {
public static final class Builder {
private final Type type;
- private final Multimap<String, CodeBlock> members = Multimaps.newListMultimap(
- new TreeMap<String, Collection<CodeBlock>>(), AnnotationSpec.<CodeBlock>listSupplier());
+ private final Map<String, List<CodeBlock>> members = new LinkedHashMap<>();
private Builder(Type type) {
this.type = type;
}
public Builder addMember(String name, String format, Object... args) {
- members.put(name, CodeBlock.builder().add(format, args).build());
+ return addMember(name, CodeBlock.builder().add(format, args).build());
+ }
+
+ public Builder addMember(String name, CodeBlock codeBlock) {
+ List<CodeBlock> values = members.get(name);
+ if (values == null) {
+ values = new ArrayList<>();
+ members.put(name, values);
+ }
+ values.add(codeBlock);
return this;
}
@@ -143,12 +143,4 @@ public final class AnnotationSpec {
return new AnnotationSpec(this);
}
}
-
- private static <T> Supplier<List<T>> listSupplier() {
- return new Supplier<List<T>>() {
- @Override public List<T> get() {
- return new ArrayList<>();
- }
- };
- }
}
diff --git a/src/main/java/com/squareup/javapoet/ClassName.java b/src/main/java/com/squareup/javapoet/ClassName.java
index 91dc3fa..310557d 100644
--- a/src/main/java/com/squareup/javapoet/ClassName.java
+++ b/src/main/java/com/squareup/javapoet/ClassName.java
@@ -15,13 +15,6 @@
*/
package com.squareup.javapoet;
-import com.google.common.base.Ascii;
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
@@ -30,12 +23,11 @@ import java.util.Map;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.NestingKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.Util.checkArgument;
+import static com.squareup.javapoet.Util.checkNotNull;
import static javax.lang.model.element.NestingKind.MEMBER;
import static javax.lang.model.element.NestingKind.TOP_LEVEL;
@@ -44,17 +36,17 @@ public final class ClassName implements Type, Comparable<ClassName> {
public static final ClassName OBJECT = ClassName.get(Object.class);
/** From top to bottom. This will be ["java.util", "Map", "Entry"] for {@link Map.Entry}. */
- final ImmutableList<String> names;
+ final List<String> names;
final String canonicalName;
private ClassName(List<String> names) {
for (int i = 1; i < names.size(); i++) {
checkArgument(SourceVersion.isName(names.get(i)), "part '%s' is keyword", names.get(i));
}
- this.names = ImmutableList.copyOf(names);
- this.canonicalName = Joiner.on(".").join(names.get(0).isEmpty()
- ? names.subList(1, names.size())
- : names);
+ this.names = Util.immutableList(names);
+ this.canonicalName = names.get(0).isEmpty()
+ ? Util.join(".", names.subList(1, names.size()))
+ : Util.join(".", names);
}
/** Returns the package name, like {@code "java.util"} for {@code Map.Entry}. */
@@ -77,13 +69,13 @@ public final class ClassName implements Type, Comparable<ClassName> {
*/
public ClassName nestedClass(String name) {
checkNotNull(name, "name == null");
- return new ClassName(new ImmutableList.Builder<String>()
- .addAll(names)
- .add(name)
- .build());
+ List<String> result = new ArrayList<>(names.size() + 1);
+ result.addAll(names);
+ result.add(name);
+ return new ClassName(result);
}
- public ImmutableList<String> simpleNames() {
+ public List<String> simpleNames() {
return names.subList(1, names.size());
}
@@ -93,15 +85,14 @@ public final class ClassName implements Type, Comparable<ClassName> {
* it is equivalent to {@code get(packageName(), name)}.
*/
public ClassName peerClass(String name) {
- return new ClassName(new ImmutableList.Builder<String>()
- .addAll(names.subList(0, names.size() - 1))
- .add(name)
- .build());
+ List<String> result = new ArrayList<>(names);
+ result.set(result.size() - 1, name);
+ return new ClassName(result);
}
/** Returns the simple name of this class, like {@code "Entry"} for {@link Map.Entry}. */
public String simpleName() {
- return Iterables.getLast(names);
+ return names.get(names.size() - 1);
}
public static ClassName get(Class<?> clazz) {
@@ -131,15 +122,15 @@ public final class ClassName implements Type, Comparable<ClassName> {
// Add the package name, like "java.util.concurrent", or "" for no package.
int p = 0;
- while (p < classNameString.length() && Ascii.isLowerCase(classNameString.charAt(p))) {
+ while (p < classNameString.length() && Util.isLowerCase(classNameString.charAt(p))) {
p = classNameString.indexOf('.', p) + 1;
checkArgument(p != 0, "couldn't make a guess for %s", classNameString);
}
names.add(p != 0 ? classNameString.substring(0, p - 1) : "");
// Add the class names, like "Map" and "Entry".
- for (String part : Splitter.on('.').split(classNameString.substring(p))) {
- checkArgument(!part.isEmpty() && Ascii.isUpperCase(part.charAt(0)),
+ for (String part : classNameString.substring(p).split("\\.", -1)) {
+ checkArgument(!part.isEmpty() && Util.isUpperCase(part.charAt(0)),
"couldn't make a guess for %s", classNameString);
names.add(part);
}
@@ -153,22 +144,20 @@ public final class ClassName implements Type, Comparable<ClassName> {
* {@code "java.util"} and simple names {@code "Map"}, {@code "Entry"} yields {@link Map.Entry}.
*/
public static ClassName get(String packageName, String simpleName, String... simpleNames) {
- return new ClassName(new ImmutableList.Builder<String>()
- .add(packageName)
- .add(simpleName)
- .add(simpleNames)
- .build());
+ List<String> result = new ArrayList<>();
+ result.add(packageName);
+ result.add(simpleName);
+ Collections.addAll(result, simpleNames);
+ return new ClassName(result);
}
- private static final ImmutableSet<NestingKind> ACCEPTABLE_NESTING_KINDS =
- Sets.immutableEnumSet(TOP_LEVEL, MEMBER);
-
/** Returns the class name for {@code element}. */
public static ClassName get(TypeElement element) {
checkNotNull(element, "element == null");
List<String> names = new ArrayList<>();
for (Element e = element; isClassOrInterface(e); e = e.getEnclosingElement()) {
- checkArgument(ACCEPTABLE_NESTING_KINDS.contains(element.getNestingKind()));
+ checkArgument(element.getNestingKind() == TOP_LEVEL || element.getNestingKind() == MEMBER,
+ "unexpected type testing");
names.add(e.getSimpleName().toString());
}
names.add(getPackage(element).getQualifiedName().toString());
diff --git a/src/main/java/com/squareup/javapoet/CodeBlock.java b/src/main/java/com/squareup/javapoet/CodeBlock.java
index 989ee58..997a35a 100644
--- a/src/main/java/com/squareup/javapoet/CodeBlock.java
+++ b/src/main/java/com/squareup/javapoet/CodeBlock.java
@@ -21,8 +21,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
+import static com.squareup.javapoet.Util.checkArgument;
+import static com.squareup.javapoet.Util.checkState;
/**
* A fragment of a .java file, potentially containing declarations, statements, and documentation.
@@ -60,8 +60,8 @@ public final class CodeBlock {
final List<Object> args;
private CodeBlock(Builder builder) {
- this.formatParts = Collections.unmodifiableList(new ArrayList<>(builder.formatParts));
- this.args = Collections.unmodifiableList(new ArrayList<>(builder.args));
+ this.formatParts = Util.immutableList(builder.formatParts);
+ this.args = Util.immutableList(builder.args);
}
public boolean isEmpty() {
diff --git a/src/main/java/com/squareup/javapoet/CodeWriter.java b/src/main/java/com/squareup/javapoet/CodeWriter.java
index d3d3ad7..62729ee 100644
--- a/src/main/java/com/squareup/javapoet/CodeWriter.java
+++ b/src/main/java/com/squareup/javapoet/CodeWriter.java
@@ -15,12 +15,6 @@
*/
package com.squareup.javapoet;
-import com.google.common.base.Ascii;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedMap;
import java.io.IOException;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
@@ -28,21 +22,24 @@ import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.EnumSet;
import java.util.Formatter;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.TreeMap;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.type.TypeMirror;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
+import static com.squareup.javapoet.Util.checkArgument;
+import static com.squareup.javapoet.Util.checkNotNull;
+import static com.squareup.javapoet.Util.checkState;
/**
* Converts a {@link JavaFile} to a string suitable to both human- and javac-consumption. This
@@ -57,7 +54,7 @@ final class CodeWriter {
private boolean comment = false;
private String packageName;
private final List<TypeSpec> typeSpecStack = new ArrayList<>();
- private final ImmutableMap<ClassName, String> importedTypes;
+ private final Map<ClassName, String> importedTypes;
private final Set<ClassName> importableTypes = new LinkedHashSet<>();
private boolean trailingNewline;
@@ -73,16 +70,16 @@ final class CodeWriter {
}
public CodeWriter(Appendable out, String indent) {
- this(out, indent, ImmutableMap.<ClassName, String>of());
+ this(out, indent, Collections.<ClassName, String>emptyMap());
}
- public CodeWriter(Appendable out, String indent, ImmutableMap<ClassName, String> importedTypes) {
+ public CodeWriter(Appendable out, String indent, Map<ClassName, String> importedTypes) {
this.out = checkNotNull(out, "out == null");
this.indent = checkNotNull(indent, "indent == null");
this.importedTypes = checkNotNull(importedTypes, "importedTypes == null");
}
- public ImmutableMap<ClassName, String> importedTypes() {
+ public Map<ClassName, String> importedTypes() {
return importedTypes;
}
@@ -151,8 +148,7 @@ final class CodeWriter {
emit(" */\n");
}
- public void emitAnnotations(ImmutableList<AnnotationSpec> annotations, boolean inline)
- throws IOException {
+ public void emitAnnotations(List<AnnotationSpec> annotations, boolean inline) throws IOException {
for (AnnotationSpec annotationSpec : annotations) {
annotationSpec.emit(this, inline);
emit(inline ? " " : "\n");
@@ -168,20 +164,20 @@ final class CodeWriter {
if (modifiers.isEmpty()) return;
for (Modifier modifier : EnumSet.copyOf(modifiers)) {
if (implicitModifiers.contains(modifier)) continue;
- emitAndIndent(Ascii.toLowerCase(modifier.name()));
+ emitAndIndent(modifier.name().toLowerCase(Locale.US));
emitAndIndent(" ");
}
}
- public void emitModifiers(ImmutableSet<Modifier> modifiers) throws IOException {
- emitModifiers(modifiers, ImmutableSet.<Modifier>of());
+ public void emitModifiers(Set<Modifier> modifiers) throws IOException {
+ emitModifiers(modifiers, Collections.<Modifier>emptySet());
}
/**
* Emit type variables with their bounds. This should only be used when declaring type variables;
* everywhere else bounds are omitted.
*/
- public void emitTypeVariables(ImmutableList<TypeVariable<?>> typeVariables) throws IOException {
+ public void emitTypeVariables(List<TypeVariable<?>> typeVariables) throws IOException {
if (typeVariables.isEmpty()) return;
emit("<");
@@ -264,7 +260,7 @@ final class CodeWriter {
private void emitLiteral(Object o) throws IOException {
if (o instanceof TypeSpec) {
TypeSpec typeSpec = (TypeSpec) o;
- typeSpec.emit(this, null, ImmutableSet.<Modifier>of());
+ typeSpec.emit(this, null, Collections.<Modifier>emptySet());
} else if (o instanceof AnnotationSpec) {
AnnotationSpec annotationSpec = (AnnotationSpec) o;
annotationSpec.emit(this, true);
@@ -305,7 +301,7 @@ final class CodeWriter {
if (superBounds.length == 1) {
return emit("? super $T", superBounds[0]);
}
- checkArgument(extendsBounds.length == 1);
+ checkArgument(extendsBounds.length == 1, "unexpected extends bounds: %s", type);
return isObject(extendsBounds[0])
? emit("?")
: emit("? extends $T", extendsBounds[0]);
@@ -358,13 +354,13 @@ final class CodeWriter {
}
// Look for the longest common prefix, which we can omit.
- ImmutableList<String> classNames = className.simpleNames();
+ List<String> classNames = className.simpleNames();
int prefixLength = commonPrefixLength(classNames);
if (prefixLength == classNames.size()) {
return className.simpleName(); // Special case: a class referring to itself!
}
- return Joiner.on('.').join(classNames.subList(prefixLength, classNames.size()));
+ return Util.join(".", classNames.subList(prefixLength, classNames.size()));
}
/**
@@ -387,7 +383,7 @@ final class CodeWriter {
* List}, 1 for {@code AbstractMap}, 1 for {@code AbstractMap.SimpleImmutableEntry}, and 2 for
* {@code AbstractMap.SimpleEntry} itself.
*/
- private int commonPrefixLength(ImmutableList<String> classNames) {
+ private int commonPrefixLength(List<String> classNames) {
int size = Math.min(classNames.size(), typeSpecStack.size());
for (int i = 0; i < size; i++) {
String a = classNames.get(i);
@@ -470,7 +466,7 @@ final class CodeWriter {
* Returns the types that should have been imported for this code. If there were any simple name
* collisions, that type's first use is imported.
*/
- ImmutableMap<ClassName, String> suggestedImports() {
+ Map<ClassName, String> suggestedImports() {
// Find the simple names that can be imported, and the classes that they target.
Map<String, ClassName> simpleNameToType = new LinkedHashMap<>();
for (Type type : importableTypes) {
@@ -481,8 +477,7 @@ final class CodeWriter {
}
// Invert the map.
- ImmutableSortedMap.Builder<ClassName, String> typeToSimpleName
- = ImmutableSortedMap.naturalOrder();
+ TreeMap<ClassName, String> typeToSimpleName = new TreeMap<>();
for (Map.Entry<String, ClassName> entry : simpleNameToType.entrySet()) {
typeToSimpleName.put(entry.getValue(), entry.getKey());
}
@@ -490,7 +485,7 @@ final class CodeWriter {
// TODO(jwilson): omit imports from java.lang, unless their simple names is also present in the
// current class's package. (Yuck.)
- return typeToSimpleName.build();
+ return typeToSimpleName;
}
/** Returns the string literal representing {@code data}, including wrapping quotes. */
diff --git a/src/main/java/com/squareup/javapoet/FieldSpec.java b/src/main/java/com/squareup/javapoet/FieldSpec.java
index 4bf1ef3..8158084 100644
--- a/src/main/java/com/squareup/javapoet/FieldSpec.java
+++ b/src/main/java/com/squareup/javapoet/FieldSpec.java
@@ -15,8 +15,6 @@
*/
package com.squareup.javapoet;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Type;
@@ -27,24 +25,24 @@ import java.util.Set;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Modifier;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.Util.checkArgument;
+import static com.squareup.javapoet.Util.checkNotNull;
/** A generated field declaration. */
public final class FieldSpec {
public final Type type;
public final String name;
public final CodeBlock javadoc;
- public final ImmutableList<AnnotationSpec> annotations;
- public final ImmutableSet<Modifier> modifiers;
+ public final List<AnnotationSpec> annotations;
+ public final Set<Modifier> modifiers;
public final CodeBlock initializer;
private FieldSpec(Builder builder) {
this.type = checkNotNull(builder.type, "type == null");
this.name = checkNotNull(builder.name, "name == null");
this.javadoc = builder.javadoc.build();
- this.annotations = ImmutableList.copyOf(builder.annotations);
- this.modifiers = ImmutableSet.copyOf(builder.modifiers);
+ this.annotations = Util.immutableList(builder.annotations);
+ this.modifiers = Util.immutableSet(builder.modifiers);
this.initializer = builder.initializer.build();
}
@@ -68,7 +66,7 @@ public final class FieldSpec {
StringWriter out = new StringWriter();
try {
CodeWriter codeWriter = new CodeWriter(out);
- emit(codeWriter, ImmutableSet.<Modifier>of());
+ emit(codeWriter, Collections.<Modifier>emptySet());
return out.toString();
} catch (IOException e) {
throw new AssertionError();
diff --git a/src/main/java/com/squareup/javapoet/JavaFile.java b/src/main/java/com/squareup/javapoet/JavaFile.java
index e7eebe4..ae588be 100644
--- a/src/main/java/com/squareup/javapoet/JavaFile.java
+++ b/src/main/java/com/squareup/javapoet/JavaFile.java
@@ -15,12 +15,12 @@
*/
package com.squareup.javapoet;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
import javax.lang.model.element.Modifier;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.Util.checkNotNull;
/** A Java file containing a single top level class. */
public final class JavaFile {
@@ -50,7 +50,7 @@ public final class JavaFile {
// First pass: emit the entire class, just to collect the types we'll need to import.
CodeWriter importsCollector = new CodeWriter(NULL_APPENDABLE, indent);
emit(importsCollector);
- ImmutableMap<ClassName, String> suggestedImports = importsCollector.suggestedImports();
+ Map<ClassName, String> suggestedImports = importsCollector.suggestedImports();
// Second pass: write the code, taking advantage of the imports.
CodeWriter codeWriter = new CodeWriter(out, indent, suggestedImports);
@@ -76,7 +76,7 @@ public final class JavaFile {
codeWriter.emit("\n");
}
- typeSpec.emit(codeWriter, null, ImmutableSet.<Modifier>of());
+ typeSpec.emit(codeWriter, null, Collections.<Modifier>emptySet());
codeWriter.popPackage();
}
diff --git a/src/main/java/com/squareup/javapoet/JavaPoet.java b/src/main/java/com/squareup/javapoet/JavaPoet.java
index 2754471..a61a31a 100644
--- a/src/main/java/com/squareup/javapoet/JavaPoet.java
+++ b/src/main/java/com/squareup/javapoet/JavaPoet.java
@@ -15,7 +15,6 @@
*/
package com.squareup.javapoet;
-import com.google.common.collect.Iterables;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
@@ -28,7 +27,7 @@ import javax.annotation.processing.Filer;
import javax.lang.model.element.Element;
import javax.tools.JavaFileObject;
-import static com.google.common.base.Preconditions.checkArgument;
+import static com.squareup.javapoet.Util.checkArgument;
/** Writes generated types to a filesystem using the standard directory structure. */
public final class JavaPoet {
@@ -79,8 +78,9 @@ public final class JavaPoet {
String fileName = javaFile.packageName.isEmpty()
? javaFile.typeSpec.name
: javaFile.packageName + "." + javaFile.typeSpec.name;
+ List<Element> originatingElements = javaFile.typeSpec.originatingElements;
JavaFileObject filerSourceFile = filer.createSourceFile(fileName,
- Iterables.toArray(javaFile.typeSpec.originatingElements, Element.class));
+ originatingElements.toArray(new Element[originatingElements.size()]));
try (Writer writer = filerSourceFile.openWriter()) {
javaFile.emit(writer, indent);
} catch (Exception e) {
diff --git a/src/main/java/com/squareup/javapoet/MethodSpec.java b/src/main/java/com/squareup/javapoet/MethodSpec.java
index 4741402..cd6b045 100644
--- a/src/main/java/com/squareup/javapoet/MethodSpec.java
+++ b/src/main/java/com/squareup/javapoet/MethodSpec.java
@@ -15,8 +15,6 @@
*/
package com.squareup.javapoet;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Type;
@@ -29,10 +27,9 @@ import java.util.Set;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Modifier;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.getLast;
+import static com.squareup.javapoet.Util.checkArgument;
+import static com.squareup.javapoet.Util.checkNotNull;
+import static com.squareup.javapoet.Util.checkState;
/** A generated constructor or method declaration. */
public final class MethodSpec {
@@ -40,13 +37,13 @@ public final class MethodSpec {
public final String name;
public final CodeBlock javadoc;
- public final ImmutableList<AnnotationSpec> annotations;
- public final ImmutableSet<Modifier> modifiers;
- public final ImmutableList<TypeVariable<?>> typeVariables;
+ public final List<AnnotationSpec> annotations;
+ public final Set<Modifier> modifiers;
+ public final List<TypeVariable<?>> typeVariables;
public final Type returnType;
- public final ImmutableList<ParameterSpec> parameters;
+ public final List<ParameterSpec> parameters;
public final boolean varargs;
- public final ImmutableList<Type> exceptions;
+ public final List<Type> exceptions;
public final CodeBlock code;
private MethodSpec(Builder builder) {
@@ -58,18 +55,19 @@ public final class MethodSpec {
this.name = checkNotNull(builder.name, "name == null");
this.javadoc = builder.javadoc.build();
- this.annotations = ImmutableList.copyOf(builder.annotations);
- this.modifiers = ImmutableSet.copyOf(builder.modifiers);
- this.typeVariables = ImmutableList.copyOf(builder.typeVariables);
+ this.annotations = Util.immutableList(builder.annotations);
+ this.modifiers = Util.immutableSet(builder.modifiers);
+ this.typeVariables = Util.immutableList(builder.typeVariables);
this.returnType = builder.returnType;
- this.parameters = ImmutableList.copyOf(builder.parameters);
+ this.parameters = Util.immutableList(builder.parameters);
this.varargs = builder.varargs;
- this.exceptions = ImmutableList.copyOf(builder.exceptions);
+ this.exceptions = Util.immutableList(builder.exceptions);
this.code = code;
}
private boolean lastParameterIsArray(List<ParameterSpec> parameters) {
- return !parameters.isEmpty() && Types.arrayComponent(getLast(parameters).type) != null;
+ return !parameters.isEmpty()
+ && Types.arrayComponent(parameters.get(parameters.size() - 1).type) != null;
}
void emit(CodeWriter codeWriter, String enclosingName, Set<Modifier> implicitModifiers)
@@ -137,7 +135,7 @@ public final class MethodSpec {
StringWriter out = new StringWriter();
try {
CodeWriter codeWriter = new CodeWriter(out);
- emit(codeWriter, "Constructor", ImmutableSet.<Modifier>of());
+ emit(codeWriter, "Constructor", Collections.<Modifier>emptySet());
return out.toString();
} catch (IOException e) {
throw new AssertionError();
diff --git a/src/main/java/com/squareup/javapoet/ParameterSpec.java b/src/main/java/com/squareup/javapoet/ParameterSpec.java
index eaeece0..8686790 100644
--- a/src/main/java/com/squareup/javapoet/ParameterSpec.java
+++ b/src/main/java/com/squareup/javapoet/ParameterSpec.java
@@ -15,31 +15,30 @@
*/
package com.squareup.javapoet;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Modifier;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.Util.checkArgument;
+import static com.squareup.javapoet.Util.checkNotNull;
/** A generated parameter declaration. */
public final class ParameterSpec {
public final String name;
- public final ImmutableList<AnnotationSpec> annotations;
- public final ImmutableSet<Modifier> modifiers;
+ public final List<AnnotationSpec> annotations;
+ public final Set<Modifier> modifiers;
public final Type type;
private ParameterSpec(Builder builder) {
this.name = checkNotNull(builder.name, "name == null");
- this.annotations = ImmutableList.copyOf(builder.annotations);
- this.modifiers = ImmutableSet.copyOf(builder.modifiers);
+ this.annotations = Util.immutableList(builder.annotations);
+ this.modifiers = Util.immutableSet(builder.modifiers);
this.type = checkNotNull(builder.type, "type == null");
}
diff --git a/src/main/java/com/squareup/javapoet/TypeSpec.java b/src/main/java/com/squareup/javapoet/TypeSpec.java
index ada52d0..715946e 100644
--- a/src/main/java/com/squareup/javapoet/TypeSpec.java
+++ b/src/main/java/com/squareup/javapoet/TypeSpec.java
@@ -15,30 +15,26 @@
*/
package com.squareup.javapoet;
-import com.google.common.base.Ascii;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.squareup.javapoet.Util.checkArgument;
+import static com.squareup.javapoet.Util.checkNotNull;
+import static com.squareup.javapoet.Util.checkState;
/** A generated class, interface, or enum declaration. */
public final class TypeSpec {
@@ -46,38 +42,38 @@ public final class TypeSpec {
public final String name;
public final CodeBlock anonymousTypeArguments;
public final CodeBlock javadoc;
- public final ImmutableList<AnnotationSpec> annotations;
- public final ImmutableSet<Modifier> modifiers;
- public final ImmutableList<TypeVariable<?>> typeVariables;
+ public final List<AnnotationSpec> annotations;
+ public final Set<Modifier> modifiers;
+ public final List<TypeVariable<?>> typeVariables;
public final Type superclass;
- public final ImmutableList<Type> superinterfaces;
- public final ImmutableMap<String, TypeSpec> enumConstants;
- public final ImmutableList<FieldSpec> fieldSpecs;
- public final ImmutableList<MethodSpec> methodSpecs;
- public final ImmutableList<TypeSpec> typeSpecs;
- public final ImmutableList<Element> originatingElements;
+ public final List<Type> superinterfaces;
+ public final Map<String, TypeSpec> enumConstants;
+ public final List<FieldSpec> fieldSpecs;
+ public final List<MethodSpec> methodSpecs;
+ public final List<TypeSpec> typeSpecs;
+ public final List<Element> originatingElements;
private TypeSpec(Builder builder) {
this.kind = builder.kind;
this.name = builder.name;
this.anonymousTypeArguments = builder.anonymousTypeArguments;
this.javadoc = builder.javadoc.build();
- this.annotations = ImmutableList.copyOf(builder.annotations);
- this.modifiers = ImmutableSet.copyOf(builder.modifiers);
- this.typeVariables = ImmutableList.copyOf(builder.typeVariables);
+ this.annotations = Util.immutableList(builder.annotations);
+ this.modifiers = Util.immutableSet(builder.modifiers);
+ this.typeVariables = Util.immutableList(builder.typeVariables);
this.superclass = builder.superclass;
- this.superinterfaces = ImmutableList.copyOf(builder.superinterfaces);
- this.enumConstants = ImmutableMap.copyOf(builder.enumConstants);
- this.fieldSpecs = ImmutableList.copyOf(builder.fieldSpecs);
- this.methodSpecs = ImmutableList.copyOf(builder.methodSpecs);
- this.typeSpecs = ImmutableList.copyOf(builder.typeSpecs);
-
- ImmutableList.Builder<Element> originatingElementsBuilder = ImmutableList.builder();
- originatingElementsBuilder.addAll(builder.originatingElements);
+ this.superinterfaces = Util.immutableList(builder.superinterfaces);
+ this.enumConstants = Util.immutableMap(builder.enumConstants);
+ this.fieldSpecs = Util.immutableList(builder.fieldSpecs);
+ this.methodSpecs = Util.immutableList(builder.methodSpecs);
+ this.typeSpecs = Util.immutableList(builder.typeSpecs);
+
+ List<Element> originatingElementsMutable = new ArrayList<>();
+ originatingElementsMutable.addAll(builder.originatingElements);
for (TypeSpec typeSpec : builder.typeSpecs) {
- originatingElementsBuilder.addAll(typeSpec.originatingElements);
+ originatingElementsMutable.addAll(typeSpec.originatingElements);
}
- this.originatingElements = originatingElementsBuilder.build();
+ this.originatingElements = Util.immutableList(originatingElementsMutable);
}
public boolean hasModifier(Modifier modifier) {
@@ -122,25 +118,26 @@ public final class TypeSpec {
}
codeWriter.emit(" {\n");
} else if (anonymousTypeArguments != null) {
- codeWriter.emit("new $T(", getOnlyElement(superinterfaces, superclass));
+ Type supertype = !superinterfaces.isEmpty() ? superinterfaces.get(0) : superclass;
+ codeWriter.emit("new $T(", supertype);
codeWriter.emit(anonymousTypeArguments);
codeWriter.emit(") {\n");
} else {
codeWriter.emitJavadoc(javadoc);
codeWriter.emitAnnotations(annotations, false);
- codeWriter.emitModifiers(modifiers, Sets.union(implicitModifiers, kind.asMemberModifiers));
- codeWriter.emit("$L $L", Ascii.toLowerCase(kind.name()), name);
+ codeWriter.emitModifiers(modifiers, Util.union(implicitModifiers, kind.asMemberModifiers));
+ codeWriter.emit("$L $L", kind.name().toLowerCase(Locale.US), name);
codeWriter.emitTypeVariables(typeVariables);
List<Type> extendsTypes;
List<Type> implementsTypes;
if (kind == Kind.INTERFACE) {
extendsTypes = superinterfaces;
- implementsTypes = ImmutableList.of();
+ implementsTypes = Collections.emptyList();
} else {
extendsTypes = superclass.equals(ClassName.OBJECT)
- ? ImmutableList.<Type>of()
- : ImmutableList.of(superclass);
+ ? Collections.<Type>emptyList()
+ : Collections.singletonList(superclass);
implementsTypes = superinterfaces;
}
@@ -175,7 +172,7 @@ public final class TypeSpec {
Map.Entry<String, TypeSpec> enumConstant = i.next();
if (!firstMember) codeWriter.emit("\n");
enumConstant.getValue()
- .emit(codeWriter, enumConstant.getKey(), ImmutableSet.<Modifier>of());
+ .emit(codeWriter, enumConstant.getKey(), Collections.<Modifier>emptySet());
firstMember = false;
if (i.hasNext()) {
codeWriter.emit(",\n");
@@ -241,7 +238,7 @@ public final class TypeSpec {
StringWriter out = new StringWriter();
try {
CodeWriter codeWriter = new CodeWriter(out);
- emit(codeWriter, null, ImmutableSet.<Modifier>of());
+ emit(codeWriter, null, Collections.<Modifier>emptySet());
return out.toString();
} catch (IOException e) {
throw new AssertionError();
@@ -250,32 +247,32 @@ public final class TypeSpec {
private enum Kind {
CLASS(
- ImmutableSet.<Modifier>of(),
- ImmutableSet.<Modifier>of(),
- ImmutableSet.<Modifier>of(),
- ImmutableSet.<Modifier>of()),
+ Collections.<Modifier>emptySet(),
+ Collections.<Modifier>emptySet(),
+ Collections.<Modifier>emptySet(),
+ Collections.<Modifier>emptySet()),
INTERFACE(
- ImmutableSet.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL),
- ImmutableSet.of(Modifier.PUBLIC, Modifier.ABSTRACT),
- ImmutableSet.of(Modifier.PUBLIC, Modifier.STATIC),
- ImmutableSet.of(Modifier.STATIC)),
+ Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)),
+ Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.ABSTRACT)),
+ Util.immutableSet(Arrays.asList(Modifier.PUBLIC, Modifier.STATIC)),
+ Util.immutableSet(Arrays.asList(Modifier.STATIC))),
ENUM(
- ImmutableSet.<Modifier>of(),
- ImmutableSet.<Modifier>of(),
- ImmutableSet.<Modifier>of(),
- ImmutableSet.of(Modifier.STATIC));
-
- private final ImmutableSet<Modifier> implicitFieldModifiers;
- private final ImmutableSet<Modifier> implicitMethodModifiers;
- private final ImmutableSet<Modifier> implicitTypeModifiers;
- private final ImmutableSet<Modifier> asMemberModifiers;
-
- private Kind(ImmutableSet<Modifier> implicitFieldModifiers,
- ImmutableSet<Modifier> implicitMethodModifiers,
- ImmutableSet<Modifier> implicitTypeModifiers,
- ImmutableSet<Modifier> asMemberModifiers) {
+ Collections.<Modifier>emptySet(),
+ Collections.<Modifier>emptySet(),
+ Collections.<Modifier>emptySet(),
+ Collections.singleton(Modifier.STATIC));
+
+ private final Set<Modifier> implicitFieldModifiers;
+ private final Set<Modifier> implicitMethodModifiers;
+ private final Set<Modifier> implicitTypeModifiers;
+ private final Set<Modifier> asMemberModifiers;
+
+ private Kind(Set<Modifier> implicitFieldModifiers,
+ Set<Modifier> implicitMethodModifiers,
+ Set<Modifier> implicitTypeModifiers,
+ Set<Modifier> asMemberModifiers) {
this.implicitFieldModifiers = implicitFieldModifiers;
this.implicitMethodModifiers = implicitMethodModifiers;
this.implicitTypeModifiers = implicitTypeModifiers;
diff --git a/src/main/java/com/squareup/javapoet/Types.java b/src/main/java/com/squareup/javapoet/Types.java
index 84f3d05..275313e 100644
--- a/src/main/java/com/squareup/javapoet/Types.java
+++ b/src/main/java/com/squareup/javapoet/Types.java
@@ -15,10 +15,6 @@
*/
package com.squareup.javapoet;
-import com.google.common.base.Function;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
import java.io.IOException;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationHandler;
@@ -30,6 +26,8 @@ import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -44,21 +42,14 @@ import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleTypeVisitor6;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.Util.checkArgument;
+import static com.squareup.javapoet.Util.checkNotNull;
/** Static methods for working with types. */
// Forked from a similar class in Gson.
public final class Types {
private static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
- private static final Function<TypeMirror, Type> FOR_TYPE_MIRROR =
- new Function<TypeMirror, Type>() {
- @Override public Type apply(TypeMirror input) {
- return get(input);
- }
- };
-
static final Type NULL = new Type() {
@Override public String toString() {
return "null";
@@ -89,8 +80,8 @@ public final class Types {
* Returns a new parameterized type, applying {@code typeArguments} to {@code rawType} and
* with no enclosing owner type.
*/
- public static ParameterizedType parameterizedType(Type rawType, Iterable<Type> typeArguments) {
- return parameterizedType(rawType, Iterables.toArray(typeArguments, Type.class));
+ public static ParameterizedType parameterizedType(Type rawType, Collection<Type> typeArguments) {
+ return parameterizedType(rawType, typeArguments.toArray(new Type[typeArguments.size()]));
}
/** Returns an array type whose elements are all instances of {@code componentType}. */
@@ -182,10 +173,15 @@ public final class Types {
}
private static Type get(DeclaredType t) {
- return t.getTypeArguments().isEmpty()
- ? ClassName.get((TypeElement) t.asElement())
- : parameterizedType(ClassName.get((TypeElement) t.asElement()),
- FluentIterable.from(t.getTypeArguments()).transform(FOR_TYPE_MIRROR));
+ List<? extends TypeMirror> typeArguments = t.getTypeArguments();
+ if (typeArguments.isEmpty()) {
+ return ClassName.get((TypeElement) t.asElement());
+ }
+ List<Type> typeParameters = new ArrayList<>();
+ for (TypeMirror typeMirror : typeArguments) {
+ typeParameters.add(get(typeMirror));
+ }
+ return parameterizedType(ClassName.get((TypeElement) t.asElement()), typeParameters);
}
private static TypeVariable<?> get(javax.lang.model.type.TypeVariable mirror) {
@@ -226,14 +222,14 @@ public final class Types {
if (upperBound.getKind() == TypeKind.DECLARED) {
TypeElement upperBoundElement = (TypeElement) ((DeclaredType) upperBound).asElement();
if (upperBoundElement.getNestingKind() == NestingKind.ANONYMOUS) {
- return ImmutableList.<TypeMirror>builder()
- .add(upperBoundElement.getSuperclass())
- .addAll(upperBoundElement.getInterfaces())
- .build();
+ List<TypeMirror> result = new ArrayList<>();
+ result.add(upperBoundElement.getSuperclass());
+ result.addAll(upperBoundElement.getInterfaces());
+ return result;
}
}
- return ImmutableList.of(upperBound);
+ return Collections.singletonList(upperBound);
}
private static Type get(javax.lang.model.type.WildcardType mirror) {
diff --git a/src/main/java/com/squareup/javapoet/Util.java b/src/main/java/com/squareup/javapoet/Util.java
new file mode 100644
index 0000000..d99501e
--- /dev/null
+++ b/src/main/java/com/squareup/javapoet/Util.java
@@ -0,0 +1,93 @@
+/*
+ * 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.squareup.javapoet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Like Guava, but worse and standalone. This makes it easier to mix JavaPoet with libraries that
+ * bring their own version of Guava.
+ */
+final class Util {
+ private Util() {
+ }
+
+ public static <K, V> Map<K, List<V>> immutableMultimap(Map<K, List<V>> multimap) {
+ LinkedHashMap<K, List<V>> result = new LinkedHashMap<>();
+ for (Map.Entry<K, List<V>> entry : multimap.entrySet()) {
+ if (entry.getValue().isEmpty()) continue;
+ result.put(entry.getKey(), immutableList(entry.getValue()));
+ }
+ return Collections.unmodifiableMap(result);
+ }
+
+ public static <K, V> Map<K, V> immutableMap(Map<K, V> map) {
+ return Collections.unmodifiableMap(new LinkedHashMap<>(map));
+ }
+
+ public static void checkArgument(boolean condition, String format, Object... args) {
+ if (!condition) throw new IllegalArgumentException(String.format(format, args));
+ }
+
+ public static <T> T checkNotNull(T reference, String format, Object... args) {
+ if (reference == null) throw new NullPointerException(String.format(format, args));
+ return reference;
+ }
+
+ public static void checkState(boolean condition, String format, Object... args) {
+ if (!condition) throw new IllegalStateException(String.format(format, args));
+ }
+
+ public static <T> List<T> immutableList(List<T> list) {
+ return Collections.unmodifiableList(new ArrayList<>(list));
+ }
+
+ public static <T> Set<T> immutableSet(Collection<T> set) {
+ return Collections.unmodifiableSet(new LinkedHashSet<>(set));
+ }
+
+ public static String join(String separator, List<String> parts) {
+ if (parts.isEmpty()) return "";
+ StringBuilder result = new StringBuilder();
+ result.append(parts.get(0));
+ for (int i = 1; i < parts.size(); i++) {
+ result.append(separator).append(parts.get(i));
+ }
+ return result.toString();
+ }
+
+ public static boolean isLowerCase(char c) {
+ return c >= 'a' && c <= 'z';
+ }
+
+ public static boolean isUpperCase(char c) {
+ return c >= 'A' && c <= 'Z';
+ }
+
+ public static <T> Set<T> union(Set<T> a, Set<T> b) {
+ Set<T> result = new LinkedHashSet<>();
+ result.addAll(a);
+ result.addAll(b);
+ return result;
+ }
+}