/*
* Copyright 2015 Google Inc. All rights reserved.
*
* 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 org.inferred.freebuilder.processor;
import static com.google.common.truth.Truth.assertThat;
import static org.inferred.freebuilder.processor.GenericTypeElementImpl.newTopLevelGenericType;
import static org.inferred.freebuilder.processor.util.ClassTypeImpl.newTopLevelClass;
import static org.inferred.freebuilder.processor.util.PrimitiveTypeImpl.INT;
import static org.inferred.freebuilder.processor.util.feature.SourceLevel.JAVA_7;
import static org.inferred.freebuilder.processor.util.feature.SourceLevel.JAVA_8;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import org.inferred.freebuilder.processor.GenericTypeElementImpl.GenericTypeMirrorImpl;
import org.inferred.freebuilder.processor.Metadata.Property;
import org.inferred.freebuilder.processor.util.ClassTypeImpl;
import org.inferred.freebuilder.processor.util.CompilationUnitBuilder;
import org.inferred.freebuilder.processor.util.QualifiedName;
import org.inferred.freebuilder.processor.util.SourceBuilder;
import org.inferred.freebuilder.processor.util.SourceStringBuilder;
import org.inferred.freebuilder.processor.util.feature.Feature;
import org.inferred.freebuilder.processor.util.feature.GuavaLibrary;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import javax.lang.model.type.TypeMirror;
@RunWith(JUnit4.class)
public class ListSourceTest {
@Test
public void test_guava_j6() {
Metadata metadata = createMetadata(true);
assertThat(generateSource(metadata, GuavaLibrary.AVAILABLE)).isEqualTo(Joiner.on('\n').join(
"/** Auto-generated superclass of {@link Person.Builder}, "
+ "derived from the API of {@link Person}. */",
"@Generated(\"org.inferred.freebuilder.processor.CodeGenerator\")",
"abstract class Person_Builder {",
"",
" /** Creates a new builder using {@code value} as a template. */",
" public static Person.Builder from(Person value) {",
" return new Person.Builder().mergeFrom(value);",
" }",
"",
" private static final Joiner COMMA_JOINER = Joiner.on(\", \").skipNulls();",
"",
" private List<String> name = ImmutableList.of();",
" private List<Integer> age = ImmutableList.of();",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code element} is null",
" */",
" public Person.Builder addName(String element) {",
" if (this.name instanceof ImmutableList) {",
" this.name = new ArrayList<String>(this.name);",
" }",
" this.name.add(Preconditions.checkNotNull(element));",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addName(String... elements) {",
" return addAllName(Arrays.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllName(Iterable<? extends String> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" if (elementsSize != 0) {",
" if (name instanceof ImmutableList) {",
" name = new ArrayList<String>(name);",
" }",
" ((ArrayList<?>) name).ensureCapacity(name.size() + elementsSize);",
" }",
" }",
" for (String element : elements) {",
" addName(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearName() {",
" if (name instanceof ImmutableList) {",
" name = ImmutableList.of();",
" } else {",
" name.clear();",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getName()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<String> getName() {",
" if (name instanceof ImmutableList) {",
" name = new ArrayList<String>(name);",
" }",
" return Collections.unmodifiableList(name);",
" }",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int element) {",
" if (this.age instanceof ImmutableList) {",
" this.age = new ArrayList<Integer>(this.age);",
" }",
" this.age.add(element);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int... elements) {",
" return addAllAge(Ints.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllAge(Iterable<? extends Integer> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" if (elementsSize != 0) {",
" if (age instanceof ImmutableList) {",
" age = new ArrayList<Integer>(age);",
" }",
" ((ArrayList<?>) age).ensureCapacity(age.size() + elementsSize);",
" }",
" }",
" for (int element : elements) {",
" addAge(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearAge() {",
" if (age instanceof ImmutableList) {",
" age = ImmutableList.of();",
" } else {",
" age.clear();",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getAge()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<Integer> getAge() {",
" if (age instanceof ImmutableList) {",
" age = new ArrayList<Integer>(age);",
" }",
" return Collections.unmodifiableList(age);",
" }",
"",
" /** Sets all property values using the given {@code Person} as a template. */",
" public Person.Builder mergeFrom(Person value) {",
" if (value instanceof Person_Builder.Value && name == ImmutableList.<String>of()) {",
" name = ImmutableList.copyOf(value.getName());",
" } else {",
" addAllName(value.getName());",
" }",
" if (value instanceof Person_Builder.Value && age == ImmutableList.<Integer>of()) {",
" age = ImmutableList.copyOf(value.getAge());",
" } else {",
" addAllAge(value.getAge());",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Copies values from the given {@code Builder}. "
+ "Does not affect any properties not set on the",
" * input.",
" */",
" public Person.Builder mergeFrom(Person.Builder template) {",
" // Upcast to access private fields; otherwise, oddly, we get an access violation.",
" Person_Builder base = (Person_Builder) template;",
" addAllName(base.name);",
" addAllAge(base.age);",
" return (Person.Builder) this;",
" }",
"",
" /** Resets the state of this builder. */",
" public Person.Builder clear() {",
" clearName();",
" clearAge();",
" return (Person.Builder) this;",
" }",
"",
" /** Returns a newly-created {@link Person} based on the contents of the "
+ "{@code Builder}. */",
" public Person build() {",
" return new Person_Builder.Value(this);",
" }",
"",
" /**",
" * Returns a newly-created partial {@link Person} for use in unit tests. "
+ "State checking will not",
" * be performed.",
" *",
" * <p>Partials should only ever be used in tests. "
+ "They permit writing robust test cases that won't",
" * fail if this type gains more application-level constraints "
+ "(e.g. new required fields) in",
" * future. If you require partially complete values in production code, "
+ "consider using a Builder.",
" */",
" @VisibleForTesting()",
" public Person buildPartial() {",
" return new Person_Builder.Partial(this);",
" }",
"",
" private static final class Value extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" private Value(Person_Builder builder) {",
" this.name = ImmutableList.copyOf(builder.name);",
" this.age = ImmutableList.copyOf(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Value)) {",
" return false;",
" }",
" Person_Builder.Value other = (Person_Builder.Value) obj;",
" if (!name.equals(other.name)) {",
" return false;",
" }",
" if (!age.equals(other.age)) {",
" return false;",
" }",
" return true;",
" }",
"",
" @Override",
" public int hashCode() {",
" return Arrays.hashCode(new Object[] {name, age});",
" }",
"",
" @Override",
" public String toString() {",
" return \"Person{\" + \"name=\" + name + \", \" + \"age=\" + age + \"}\";",
" }",
" }",
"",
" private static final class Partial extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" Partial(Person_Builder builder) {",
" this.name = ImmutableList.copyOf(builder.name);",
" this.age = ImmutableList.copyOf(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Partial)) {",
" return false;",
" }",
" Person_Builder.Partial other = (Person_Builder.Partial) obj;",
" if (!name.equals(other.name)) {",
" return false;",
" }",
" if (!age.equals(other.age)) {",
" return false;",
" }",
" return true;",
" }",
"",
" @Override",
" public int hashCode() {",
" return Arrays.hashCode(new Object[] {name, age});",
" }",
"",
" @Override",
" public String toString() {",
" return \"partial Person{\" + COMMA_JOINER.join(\"name=\" + name, \"age=\" + age) "
+ "+ \"}\";",
" }",
" }",
"}\n"));
}
@Test
public void test_guava_j7() {
Metadata metadata = createMetadata(true);
String source = generateSource(metadata, JAVA_7, GuavaLibrary.AVAILABLE);
assertThat(source).isEqualTo(Joiner.on('\n').join(
"/** Auto-generated superclass of {@link Person.Builder}, "
+ "derived from the API of {@link Person}. */",
"@Generated(\"org.inferred.freebuilder.processor.CodeGenerator\")",
"abstract class Person_Builder {",
"",
" /** Creates a new builder using {@code value} as a template. */",
" public static Person.Builder from(Person value) {",
" return new Person.Builder().mergeFrom(value);",
" }",
"",
" private static final Joiner COMMA_JOINER = Joiner.on(\", \").skipNulls();",
"",
" private List<String> name = ImmutableList.of();",
" private List<Integer> age = ImmutableList.of();",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code element} is null",
" */",
" public Person.Builder addName(String element) {",
" if (this.name instanceof ImmutableList) {",
" this.name = new ArrayList<>(this.name);",
" }",
" this.name.add(Preconditions.checkNotNull(element));",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addName(String... elements) {",
" return addAllName(Arrays.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllName(Iterable<? extends String> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" if (elementsSize != 0) {",
" if (name instanceof ImmutableList) {",
" name = new ArrayList<>(name);",
" }",
" ((ArrayList<?>) name).ensureCapacity(name.size() + elementsSize);",
" }",
" }",
" for (String element : elements) {",
" addName(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearName() {",
" if (name instanceof ImmutableList) {",
" name = ImmutableList.of();",
" } else {",
" name.clear();",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getName()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<String> getName() {",
" if (name instanceof ImmutableList) {",
" name = new ArrayList<>(name);",
" }",
" return Collections.unmodifiableList(name);",
" }",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int element) {",
" if (this.age instanceof ImmutableList) {",
" this.age = new ArrayList<>(this.age);",
" }",
" this.age.add(element);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int... elements) {",
" return addAllAge(Ints.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllAge(Iterable<? extends Integer> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" if (elementsSize != 0) {",
" if (age instanceof ImmutableList) {",
" age = new ArrayList<>(age);",
" }",
" ((ArrayList<?>) age).ensureCapacity(age.size() + elementsSize);",
" }",
" }",
" for (int element : elements) {",
" addAge(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearAge() {",
" if (age instanceof ImmutableList) {",
" age = ImmutableList.of();",
" } else {",
" age.clear();",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getAge()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<Integer> getAge() {",
" if (age instanceof ImmutableList) {",
" age = new ArrayList<>(age);",
" }",
" return Collections.unmodifiableList(age);",
" }",
"",
" /** Sets all property values using the given {@code Person} as a template. */",
" public Person.Builder mergeFrom(Person value) {",
" if (value instanceof Person_Builder.Value && name == ImmutableList.<String>of()) {",
" name = ImmutableList.copyOf(value.getName());",
" } else {",
" addAllName(value.getName());",
" }",
" if (value instanceof Person_Builder.Value && age == ImmutableList.<Integer>of()) {",
" age = ImmutableList.copyOf(value.getAge());",
" } else {",
" addAllAge(value.getAge());",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Copies values from the given {@code Builder}. "
+ "Does not affect any properties not set on the",
" * input.",
" */",
" public Person.Builder mergeFrom(Person.Builder template) {",
" // Upcast to access private fields; otherwise, oddly, we get an access violation.",
" Person_Builder base = (Person_Builder) template;",
" addAllName(base.name);",
" addAllAge(base.age);",
" return (Person.Builder) this;",
" }",
"",
" /** Resets the state of this builder. */",
" public Person.Builder clear() {",
" clearName();",
" clearAge();",
" return (Person.Builder) this;",
" }",
"",
" /** Returns a newly-created {@link Person} based on the contents of the "
+ "{@code Builder}. */",
" public Person build() {",
" return new Person_Builder.Value(this);",
" }",
"",
" /**",
" * Returns a newly-created partial {@link Person} for use in unit tests. "
+ "State checking will not",
" * be performed.",
" *",
" * <p>Partials should only ever be used in tests. "
+ "They permit writing robust test cases that won't",
" * fail if this type gains more application-level constraints "
+ "(e.g. new required fields) in",
" * future. If you require partially complete values in production code, "
+ "consider using a Builder.",
" */",
" @VisibleForTesting()",
" public Person buildPartial() {",
" return new Person_Builder.Partial(this);",
" }",
"",
" private static final class Value extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" private Value(Person_Builder builder) {",
" this.name = ImmutableList.copyOf(builder.name);",
" this.age = ImmutableList.copyOf(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Value)) {",
" return false;",
" }",
" Person_Builder.Value other = (Person_Builder.Value) obj;",
" return Objects.equals(name, other.name) && Objects.equals(age, other.age);",
" }",
"",
" @Override",
" public int hashCode() {",
" return Objects.hash(name, age);",
" }",
"",
" @Override",
" public String toString() {",
" return \"Person{\" + \"name=\" + name + \", \" + \"age=\" + age + \"}\";",
" }",
" }",
"",
" private static final class Partial extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" Partial(Person_Builder builder) {",
" this.name = ImmutableList.copyOf(builder.name);",
" this.age = ImmutableList.copyOf(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Partial)) {",
" return false;",
" }",
" Person_Builder.Partial other = (Person_Builder.Partial) obj;",
" return Objects.equals(name, other.name) && Objects.equals(age, other.age);",
" }",
"",
" @Override",
" public int hashCode() {",
" return Objects.hash(name, age);",
" }",
"",
" @Override",
" public String toString() {",
" return \"partial Person{\" + COMMA_JOINER.join(\"name=\" + name, \"age=\" + age) "
+ "+ \"}\";",
" }",
" }",
"}\n"));
}
@Test
public void test_guava_j8() {
Metadata metadata = createMetadata(true);
String source = generateSource(metadata, JAVA_8, GuavaLibrary.AVAILABLE);
assertThat(source).isEqualTo(Joiner.on('\n').join(
"/** Auto-generated superclass of {@link Person.Builder}, "
+ "derived from the API of {@link Person}. */",
"abstract class Person_Builder {",
"",
" /** Creates a new builder using {@code value} as a template. */",
" public static Person.Builder from(Person value) {",
" return new Person.Builder().mergeFrom(value);",
" }",
"",
" private static final Joiner COMMA_JOINER = Joiner.on(\", \").skipNulls();",
"",
" private List<String> name = ImmutableList.of();",
" private List<Integer> age = ImmutableList.of();",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code element} is null",
" */",
" public Person.Builder addName(String element) {",
" if (this.name instanceof ImmutableList) {",
" this.name = new ArrayList<>(this.name);",
" }",
" this.name.add(Preconditions.checkNotNull(element));",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addName(String... elements) {",
" return addAllName(Arrays.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllName(Spliterator<? extends String> elements) {",
" if ((elements.characteristics() & Spliterator.SIZED) != 0) {",
" long elementsSize = elements.estimateSize();",
" if (elementsSize > 0 && elementsSize <= Integer.MAX_VALUE) {",
" if (name instanceof ImmutableList) {",
" name = new ArrayList<>(name);",
" }",
" ((ArrayList<?>) name).ensureCapacity(name.size() + (int) elementsSize);",
" }",
" }",
" elements.forEachRemaining(this::addName);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllName(BaseStream<? extends String, ?> elements) {",
" return addAllName(elements.spliterator());",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllName(Iterable<? extends String> elements) {",
" return addAllName(elements.spliterator());",
" }",
"",
" /**",
" * Applies {@code mutator} to the list to be returned from {@link Person#getName()}.",
" *",
" * <p>This method mutates the list in-place. {@code mutator} is a void consumer, "
+ "so any value",
" * returned from a lambda will be ignored. Take care not to call pure functions, "
+ "like {@link",
" * Collection#stream()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code mutator} is null",
" */",
" public Person.Builder mutateName(Consumer<? super List<String>> mutator) {",
" if (this.name instanceof ImmutableList) {",
" this.name = new ArrayList<>(this.name);",
" }",
" // If addName is overridden, this method will be updated to delegate to it",
" mutator.accept(name);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearName() {",
" if (name instanceof ImmutableList) {",
" name = ImmutableList.of();",
" } else {",
" name.clear();",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getName()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<String> getName() {",
" if (name instanceof ImmutableList) {",
" name = new ArrayList<>(name);",
" }",
" return Collections.unmodifiableList(name);",
" }",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int element) {",
" if (this.age instanceof ImmutableList) {",
" this.age = new ArrayList<>(this.age);",
" }",
" this.age.add(element);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int... elements) {",
" return addAllAge(Ints.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllAge(Spliterator<? extends Integer> elements) {",
" if ((elements.characteristics() & Spliterator.SIZED) != 0) {",
" long elementsSize = elements.estimateSize();",
" if (elementsSize > 0 && elementsSize <= Integer.MAX_VALUE) {",
" if (age instanceof ImmutableList) {",
" age = new ArrayList<>(age);",
" }",
" ((ArrayList<?>) age).ensureCapacity(age.size() + (int) elementsSize);",
" }",
" }",
" elements.forEachRemaining(this::addAge);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllAge(BaseStream<? extends Integer, ?> elements) {",
" return addAllAge(elements.spliterator());",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllAge(Iterable<? extends Integer> elements) {",
" return addAllAge(elements.spliterator());",
" }",
"",
" /**",
" * Applies {@code mutator} to the list to be returned from {@link Person#getAge()}.",
" *",
" * <p>This method mutates the list in-place. {@code mutator} is a void consumer, "
+ "so any value",
" * returned from a lambda will be ignored. Take care not to call pure functions, "
+ "like {@link",
" * Collection#stream()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code mutator} is null",
" */",
" public Person.Builder mutateAge(Consumer<? super List<Integer>> mutator) {",
" if (this.age instanceof ImmutableList) {",
" this.age = new ArrayList<>(this.age);",
" }",
" // If addAge is overridden, this method will be updated to delegate to it",
" mutator.accept(age);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearAge() {",
" if (age instanceof ImmutableList) {",
" age = ImmutableList.of();",
" } else {",
" age.clear();",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getAge()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<Integer> getAge() {",
" if (age instanceof ImmutableList) {",
" age = new ArrayList<>(age);",
" }",
" return Collections.unmodifiableList(age);",
" }",
"",
" /** Sets all property values using the given {@code Person} as a template. */",
" public Person.Builder mergeFrom(Person value) {",
" if (value instanceof Person_Builder.Value && name == ImmutableList.<String>of()) {",
" name = ImmutableList.copyOf(value.getName());",
" } else {",
" addAllName(value.getName());",
" }",
" if (value instanceof Person_Builder.Value && age == ImmutableList.<Integer>of()) {",
" age = ImmutableList.copyOf(value.getAge());",
" } else {",
" addAllAge(value.getAge());",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Copies values from the given {@code Builder}. "
+ "Does not affect any properties not set on the",
" * input.",
" */",
" public Person.Builder mergeFrom(Person.Builder template) {",
" // Upcast to access private fields; otherwise, oddly, we get an access violation.",
" Person_Builder base = (Person_Builder) template;",
" addAllName(base.name);",
" addAllAge(base.age);",
" return (Person.Builder) this;",
" }",
"",
" /** Resets the state of this builder. */",
" public Person.Builder clear() {",
" clearName();",
" clearAge();",
" return (Person.Builder) this;",
" }",
"",
" /** Returns a newly-created {@link Person} based on the contents of the "
+ "{@code Builder}. */",
" public Person build() {",
" return new Person_Builder.Value(this);",
" }",
"",
" /**",
" * Returns a newly-created partial {@link Person} for use in unit tests. "
+ "State checking will not",
" * be performed.",
" *",
" * <p>Partials should only ever be used in tests. "
+ "They permit writing robust test cases that won't",
" * fail if this type gains more application-level constraints "
+ "(e.g. new required fields) in",
" * future. If you require partially complete values in production code, "
+ "consider using a Builder.",
" */",
" @VisibleForTesting()",
" public Person buildPartial() {",
" return new Person_Builder.Partial(this);",
" }",
"",
" private static final class Value extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" private Value(Person_Builder builder) {",
" this.name = ImmutableList.copyOf(builder.name);",
" this.age = ImmutableList.copyOf(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Value)) {",
" return false;",
" }",
" Person_Builder.Value other = (Person_Builder.Value) obj;",
" return Objects.equals(name, other.name) && Objects.equals(age, other.age);",
" }",
"",
" @Override",
" public int hashCode() {",
" return Objects.hash(name, age);",
" }",
"",
" @Override",
" public String toString() {",
" return \"Person{\" + \"name=\" + name + \", \" + \"age=\" + age + \"}\";",
" }",
" }",
"",
" private static final class Partial extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" Partial(Person_Builder builder) {",
" this.name = ImmutableList.copyOf(builder.name);",
" this.age = ImmutableList.copyOf(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Partial)) {",
" return false;",
" }",
" Person_Builder.Partial other = (Person_Builder.Partial) obj;",
" return Objects.equals(name, other.name) && Objects.equals(age, other.age);",
" }",
"",
" @Override",
" public int hashCode() {",
" return Objects.hash(name, age);",
" }",
"",
" @Override",
" public String toString() {",
" return \"partial Person{\" + COMMA_JOINER.join(\"name=\" + name, \"age=\" + age) "
+ "+ \"}\";",
" }",
" }",
"}\n"));
}
@Test
public void test_noGuava_j6() {
Metadata metadata = createMetadata(true);
assertThat(generateSource(metadata)).isEqualTo(Joiner.on('\n').join(
"/** Auto-generated superclass of {@link Person.Builder}, "
+ "derived from the API of {@link Person}. */",
"@Generated(\"org.inferred.freebuilder.processor.CodeGenerator\")",
"abstract class Person_Builder {",
"",
" /** Creates a new builder using {@code value} as a template. */",
" public static Person.Builder from(Person value) {",
" return new Person.Builder().mergeFrom(value);",
" }",
"",
" private final ArrayList<String> name = new ArrayList<String>();",
" private final ArrayList<Integer> age = new ArrayList<Integer>();",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code element} is null",
" */",
" public Person.Builder addName(String element) {",
" if (element == null) {",
" throw new NullPointerException();",
" }",
" this.name.add(element);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addName(String... elements) {",
" return addAllName(Arrays.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllName(Iterable<? extends String> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" name.ensureCapacity(name.size() + elementsSize);",
" }",
" for (String element : elements) {",
" addName(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearName() {",
" name.clear();",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getName()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<String> getName() {",
" return Collections.unmodifiableList(name);",
" }",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int element) {",
" this.age.add(element);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int... elements) {",
" age.ensureCapacity(age.size() + elements.length);",
" for (int element : elements) {",
" addAge(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllAge(Iterable<? extends Integer> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" age.ensureCapacity(age.size() + elementsSize);",
" }",
" for (int element : elements) {",
" addAge(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearAge() {",
" age.clear();",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getAge()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<Integer> getAge() {",
" return Collections.unmodifiableList(age);",
" }",
"",
" /** Sets all property values using the given {@code Person} as a template. */",
" public Person.Builder mergeFrom(Person value) {",
" addAllName(value.getName());",
" addAllAge(value.getAge());",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Copies values from the given {@code Builder}. "
+ "Does not affect any properties not set on the",
" * input.",
" */",
" public Person.Builder mergeFrom(Person.Builder template) {",
" // Upcast to access private fields; otherwise, oddly, we get an access violation.",
" Person_Builder base = (Person_Builder) template;",
" addAllName(base.name);",
" addAllAge(base.age);",
" return (Person.Builder) this;",
" }",
"",
" /** Resets the state of this builder. */",
" public Person.Builder clear() {",
" clearName();",
" clearAge();",
" return (Person.Builder) this;",
" }",
"",
" /** Returns a newly-created {@link Person} based on the contents of the "
+ "{@code Builder}. */",
" public Person build() {",
" return new Person_Builder.Value(this);",
" }",
"",
" /**",
" * Returns a newly-created partial {@link Person} for use in unit tests. "
+ "State checking will not",
" * be performed.",
" *",
" * <p>Partials should only ever be used in tests. "
+ "They permit writing robust test cases that won't",
" * fail if this type gains more application-level constraints "
+ "(e.g. new required fields) in",
" * future. If you require partially complete values in production code, "
+ "consider using a Builder.",
" */",
" public Person buildPartial() {",
" return new Person_Builder.Partial(this);",
" }",
"",
" private static final class Value extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" private Value(Person_Builder builder) {",
" this.name = immutableList(builder.name);",
" this.age = immutableList(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Value)) {",
" return false;",
" }",
" Person_Builder.Value other = (Person_Builder.Value) obj;",
" if (!name.equals(other.name)) {",
" return false;",
" }",
" if (!age.equals(other.age)) {",
" return false;",
" }",
" return true;",
" }",
"",
" @Override",
" public int hashCode() {",
" return Arrays.hashCode(new Object[] {name, age});",
" }",
"",
" @Override",
" public String toString() {",
" return \"Person{\" + \"name=\" + name + \", \" + \"age=\" + age + \"}\";",
" }",
" }",
"",
" private static final class Partial extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" Partial(Person_Builder builder) {",
" this.name = immutableList(builder.name);",
" this.age = immutableList(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Partial)) {",
" return false;",
" }",
" Person_Builder.Partial other = (Person_Builder.Partial) obj;",
" if (!name.equals(other.name)) {",
" return false;",
" }",
" if (!age.equals(other.age)) {",
" return false;",
" }",
" return true;",
" }",
"",
" @Override",
" public int hashCode() {",
" return Arrays.hashCode(new Object[] {name, age});",
" }",
"",
" @Override",
" public String toString() {",
" StringBuilder result = new StringBuilder(\"partial Person{\");",
" result.append(\"name=\").append(name);",
" result.append(\", \");",
" result.append(\"age=\").append(age);",
" result.append(\"}\");",
" return result.toString();",
" }",
" }",
"",
" @SuppressWarnings(\"unchecked\")",
" private static <E> List<E> immutableList(List<E> elements) {",
" switch (elements.size()) {",
" case 0:",
" return Collections.emptyList();",
" case 1:",
" return Collections.singletonList(elements.get(0));",
" default:",
" return (List<E>) (List<?>) Collections.unmodifiableList("
+ "Arrays.asList(elements.toArray()));",
" }",
" }",
"}\n"));
}
@Test
public void test_noGuava_j7() {
Metadata metadata = createMetadata(true);
assertThat(generateSource(metadata, JAVA_7)).isEqualTo(Joiner.on('\n').join(
"/** Auto-generated superclass of {@link Person.Builder}, "
+ "derived from the API of {@link Person}. */",
"@Generated(\"org.inferred.freebuilder.processor.CodeGenerator\")",
"abstract class Person_Builder {",
"",
" /** Creates a new builder using {@code value} as a template. */",
" public static Person.Builder from(Person value) {",
" return new Person.Builder().mergeFrom(value);",
" }",
"",
" private final ArrayList<String> name = new ArrayList<>();",
" private final ArrayList<Integer> age = new ArrayList<>();",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code element} is null",
" */",
" public Person.Builder addName(String element) {",
" this.name.add(Objects.requireNonNull(element));",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addName(String... elements) {",
" return addAllName(Arrays.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllName(Iterable<? extends String> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" name.ensureCapacity(name.size() + elementsSize);",
" }",
" for (String element : elements) {",
" addName(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getName()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearName() {",
" name.clear();",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getName()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<String> getName() {",
" return Collections.unmodifiableList(name);",
" }",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int element) {",
" this.age.add(element);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int... elements) {",
" age.ensureCapacity(age.size() + elements.length);",
" for (int element : elements) {",
" addAge(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllAge(Iterable<? extends Integer> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" age.ensureCapacity(age.size() + elementsSize);",
" }",
" for (int element : elements) {",
" addAge(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#getAge()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearAge() {",
" age.clear();",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#getAge()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<Integer> getAge() {",
" return Collections.unmodifiableList(age);",
" }",
"",
" /** Sets all property values using the given {@code Person} as a template. */",
" public Person.Builder mergeFrom(Person value) {",
" addAllName(value.getName());",
" addAllAge(value.getAge());",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Copies values from the given {@code Builder}. "
+ "Does not affect any properties not set on the",
" * input.",
" */",
" public Person.Builder mergeFrom(Person.Builder template) {",
" // Upcast to access private fields; otherwise, oddly, we get an access violation.",
" Person_Builder base = (Person_Builder) template;",
" addAllName(base.name);",
" addAllAge(base.age);",
" return (Person.Builder) this;",
" }",
"",
" /** Resets the state of this builder. */",
" public Person.Builder clear() {",
" clearName();",
" clearAge();",
" return (Person.Builder) this;",
" }",
"",
" /** Returns a newly-created {@link Person} based on the contents of the "
+ "{@code Builder}. */",
" public Person build() {",
" return new Person_Builder.Value(this);",
" }",
"",
" /**",
" * Returns a newly-created partial {@link Person} for use in unit tests. "
+ "State checking will not",
" * be performed.",
" *",
" * <p>Partials should only ever be used in tests. "
+ "They permit writing robust test cases that won't",
" * fail if this type gains more application-level constraints "
+ "(e.g. new required fields) in",
" * future. If you require partially complete values in production code, "
+ "consider using a Builder.",
" */",
" public Person buildPartial() {",
" return new Person_Builder.Partial(this);",
" }",
"",
" private static final class Value extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" private Value(Person_Builder builder) {",
" this.name = immutableList(builder.name);",
" this.age = immutableList(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Value)) {",
" return false;",
" }",
" Person_Builder.Value other = (Person_Builder.Value) obj;",
" return Objects.equals(name, other.name) && Objects.equals(age, other.age);",
" }",
"",
" @Override",
" public int hashCode() {",
" return Objects.hash(name, age);",
" }",
"",
" @Override",
" public String toString() {",
" return \"Person{\" + \"name=\" + name + \", \" + \"age=\" + age + \"}\";",
" }",
" }",
"",
" private static final class Partial extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" Partial(Person_Builder builder) {",
" this.name = immutableList(builder.name);",
" this.age = immutableList(builder.age);",
" }",
"",
" @Override",
" public List<String> getName() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> getAge() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Partial)) {",
" return false;",
" }",
" Person_Builder.Partial other = (Person_Builder.Partial) obj;",
" return Objects.equals(name, other.name) && Objects.equals(age, other.age);",
" }",
"",
" @Override",
" public int hashCode() {",
" return Objects.hash(name, age);",
" }",
"",
" @Override",
" public String toString() {",
" StringBuilder result = new StringBuilder(\"partial Person{\");",
" result.append(\"name=\").append(name);",
" result.append(\", \");",
" result.append(\"age=\").append(age);",
" result.append(\"}\");",
" return result.toString();",
" }",
" }",
"",
" @SuppressWarnings(\"unchecked\")",
" private static <E> List<E> immutableList(List<E> elements) {",
" switch (elements.size()) {",
" case 0:",
" return Collections.emptyList();",
" case 1:",
" return Collections.singletonList(elements.get(0));",
" default:",
" return (List<E>) (List<?>) Collections.unmodifiableList("
+ "Arrays.asList(elements.toArray()));",
" }",
" }",
"}\n"));
}
@Test
public void test_prefixless() {
Metadata metadata = createMetadata(false);
assertThat(generateSource(metadata, GuavaLibrary.AVAILABLE)).isEqualTo(Joiner.on('\n').join(
"/** Auto-generated superclass of {@link Person.Builder}, "
+ "derived from the API of {@link Person}. */",
"@Generated(\"org.inferred.freebuilder.processor.CodeGenerator\")",
"abstract class Person_Builder {",
"",
" /** Creates a new builder using {@code value} as a template. */",
" public static Person.Builder from(Person value) {",
" return new Person.Builder().mergeFrom(value);",
" }",
"",
" private static final Joiner COMMA_JOINER = Joiner.on(\", \").skipNulls();",
"",
" private List<String> name = ImmutableList.of();",
" private List<Integer> age = ImmutableList.of();",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#name()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code element} is null",
" */",
" public Person.Builder addName(String element) {",
" if (this.name instanceof ImmutableList) {",
" this.name = new ArrayList<String>(this.name);",
" }",
" this.name.add(Preconditions.checkNotNull(element));",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#name()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addName(String... elements) {",
" return addAllName(Arrays.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#name()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllName(Iterable<? extends String> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" if (elementsSize != 0) {",
" if (name instanceof ImmutableList) {",
" name = new ArrayList<String>(name);",
" }",
" ((ArrayList<?>) name).ensureCapacity(name.size() + elementsSize);",
" }",
" }",
" for (String element : elements) {",
" addName(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#name()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearName() {",
" if (name instanceof ImmutableList) {",
" name = ImmutableList.of();",
" } else {",
" name.clear();",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#name()}.",
" * Changes to this builder will be reflected in the view.",
" */",
" public List<String> name() {",
" if (name instanceof ImmutableList) {",
" name = new ArrayList<String>(name);",
" }",
" return Collections.unmodifiableList(name);",
" }",
"",
" /**",
" * Adds {@code element} to the list to be returned from {@link Person#age()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int element) {",
" if (this.age instanceof ImmutableList) {",
" this.age = new ArrayList<Integer>(this.age);",
" }",
" this.age.add(element);",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#age()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder addAge(int... elements) {",
" return addAllAge(Ints.asList(elements));",
" }",
"",
" /**",
" * Adds each element of {@code elements} to the list to be returned from "
+ "{@link Person#age()}.",
" *",
" * @return this {@code Builder} object",
" * @throws NullPointerException if {@code elements} is null or contains a null element",
" */",
" public Person.Builder addAllAge(Iterable<? extends Integer> elements) {",
" if (elements instanceof Collection) {",
" int elementsSize = ((Collection<?>) elements).size();",
" if (elementsSize != 0) {",
" if (age instanceof ImmutableList) {",
" age = new ArrayList<Integer>(age);",
" }",
" ((ArrayList<?>) age).ensureCapacity(age.size() + elementsSize);",
" }",
" }",
" for (int element : elements) {",
" addAge(element);",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Clears the list to be returned from {@link Person#age()}.",
" *",
" * @return this {@code Builder} object",
" */",
" public Person.Builder clearAge() {",
" if (age instanceof ImmutableList) {",
" age = ImmutableList.of();",
" } else {",
" age.clear();",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Returns an unmodifiable view of the list that will be returned by "
+ "{@link Person#age()}. Changes",
" * to this builder will be reflected in the view.",
" */",
" public List<Integer> age() {",
" if (age instanceof ImmutableList) {",
" age = new ArrayList<Integer>(age);",
" }",
" return Collections.unmodifiableList(age);",
" }",
"",
" /** Sets all property values using the given {@code Person} as a template. */",
" public Person.Builder mergeFrom(Person value) {",
" if (value instanceof Person_Builder.Value && name == ImmutableList.<String>of()) {",
" name = ImmutableList.copyOf(value.name());",
" } else {",
" addAllName(value.name());",
" }",
" if (value instanceof Person_Builder.Value && age == ImmutableList.<Integer>of()) {",
" age = ImmutableList.copyOf(value.age());",
" } else {",
" addAllAge(value.age());",
" }",
" return (Person.Builder) this;",
" }",
"",
" /**",
" * Copies values from the given {@code Builder}. "
+ "Does not affect any properties not set on the",
" * input.",
" */",
" public Person.Builder mergeFrom(Person.Builder template) {",
" // Upcast to access private fields; otherwise, oddly, we get an access violation.",
" Person_Builder base = (Person_Builder) template;",
" addAllName(base.name);",
" addAllAge(base.age);",
" return (Person.Builder) this;",
" }",
"",
" /** Resets the state of this builder. */",
" public Person.Builder clear() {",
" clearName();",
" clearAge();",
" return (Person.Builder) this;",
" }",
"",
" /** Returns a newly-created {@link Person} based on the contents of the "
+ "{@code Builder}. */",
" public Person build() {",
" return new Person_Builder.Value(this);",
" }",
"",
" /**",
" * Returns a newly-created partial {@link Person} for use in unit tests. "
+ "State checking will not",
" * be performed.",
" *",
" * <p>Partials should only ever be used in tests. "
+ "They permit writing robust test cases that won't",
" * fail if this type gains more application-level constraints "
+ "(e.g. new required fields) in",
" * future. If you require partially complete values in production code, "
+ "consider using a Builder.",
" */",
" @VisibleForTesting()",
" public Person buildPartial() {",
" return new Person_Builder.Partial(this);",
" }",
"",
" private static final class Value extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" private Value(Person_Builder builder) {",
" this.name = ImmutableList.copyOf(builder.name);",
" this.age = ImmutableList.copyOf(builder.age);",
" }",
"",
" @Override",
" public List<String> name() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> age() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Value)) {",
" return false;",
" }",
" Person_Builder.Value other = (Person_Builder.Value) obj;",
" if (!name.equals(other.name)) {",
" return false;",
" }",
" if (!age.equals(other.age)) {",
" return false;",
" }",
" return true;",
" }",
"",
" @Override",
" public int hashCode() {",
" return Arrays.hashCode(new Object[] {name, age});",
" }",
"",
" @Override",
" public String toString() {",
" return \"Person{\" + \"name=\" + name + \", \" + \"age=\" + age + \"}\";",
" }",
" }",
"",
" private static final class Partial extends Person {",
" private final List<String> name;",
" private final List<Integer> age;",
"",
" Partial(Person_Builder builder) {",
" this.name = ImmutableList.copyOf(builder.name);",
" this.age = ImmutableList.copyOf(builder.age);",
" }",
"",
" @Override",
" public List<String> name() {",
" return name;",
" }",
"",
" @Override",
" public List<Integer> age() {",
" return age;",
" }",
"",
" @Override",
" public boolean equals(Object obj) {",
" if (!(obj instanceof Person_Builder.Partial)) {",
" return false;",
" }",
" Person_Builder.Partial other = (Person_Builder.Partial) obj;",
" if (!name.equals(other.name)) {",
" return false;",
" }",
" if (!age.equals(other.age)) {",
" return false;",
" }",
" return true;",
" }",
"",
" @Override",
" public int hashCode() {",
" return Arrays.hashCode(new Object[] {name, age});",
" }",
"",
" @Override",
" public String toString() {",
" return \"partial Person{\" + COMMA_JOINER.join(\"name=\" + name, \"age=\" + age) "
+ "+ \"}\";",
" }",
" }",
"}\n"));
}
private static String generateSource(Metadata metadata, Feature<?>... features) {
SourceBuilder sourceBuilder = SourceStringBuilder.simple(features);
new CodeGenerator().writeBuilderSource(sourceBuilder, metadata);
return CompilationUnitBuilder.formatSource(sourceBuilder.toString());
}
/**
* Returns a {@link Metadata} instance for a FreeBuilder type with two properties: name, of
* type {@code List<String>}; and age, of type {@code List<Integer>}.
*/
private static Metadata createMetadata(boolean bean) {
GenericTypeElementImpl list = newTopLevelGenericType("java.util.List");
ClassTypeImpl integer = newTopLevelClass("java.lang.Integer");
GenericTypeMirrorImpl listInteger = list.newMirror(integer);
ClassTypeImpl string = newTopLevelClass("java.lang.String");
GenericTypeMirrorImpl listString = list.newMirror(string);
QualifiedName person = QualifiedName.of("com.example", "Person");
QualifiedName generatedBuilder = QualifiedName.of("com.example", "Person_Builder");
Property name = new Property.Builder()
.setAllCapsName("NAME")
.setBoxedType(listString)
.setCapitalizedName("Name")
.setFullyCheckedCast(true)
.setGetterName(bean ? "getName" : "name")
.setName("name")
.setType(listString)
.setUsingBeanConvention(bean)
.build();
Property age = new Property.Builder()
.setAllCapsName("AGE")
.setBoxedType(listInteger)
.setCapitalizedName("Age")
.setFullyCheckedCast(true)
.setGetterName(bean ? "getAge" : "age")
.setName("age")
.setType(listInteger)
.setUsingBeanConvention(bean)
.build();
Metadata metadata = new Metadata.Builder()
.setBuilder(person.nestedType("Builder").withParameters())
.setBuilderFactory(BuilderFactory.NO_ARGS_CONSTRUCTOR)
.setBuilderSerializable(false)
.setGeneratedBuilder(generatedBuilder.withParameters())
.setInterfaceType(false)
.setPartialType(generatedBuilder.nestedType("Partial").withParameters())
.addProperties(name, age)
.setPropertyEnum(generatedBuilder.nestedType("Property").withParameters())
.setType(person.withParameters())
.setValueType(generatedBuilder.nestedType("Value").withParameters())
.build();
return metadata.toBuilder()
.clearProperties()
.addProperties(name.toBuilder()
.setCodeGenerator(new ListPropertyFactory.CodeGenerator(
metadata, name, false, string, Optional.<TypeMirror>absent()))
.build())
.addProperties(age.toBuilder()
.setCodeGenerator(new ListPropertyFactory.CodeGenerator(
metadata, age, false, integer, Optional.<TypeMirror>of(INT)))
.build())
.build();
}
}