/* * 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(); } }