diff --git a/src/main/java/org/inferred/freebuilder/processor/SetPropertyFactory.java b/src/main/java/org/inferred/freebuilder/processor/SetPropertyFactory.java index c55138ad9..ced58f448 100644 --- a/src/main/java/org/inferred/freebuilder/processor/SetPropertyFactory.java +++ b/src/main/java/org/inferred/freebuilder/processor/SetPropertyFactory.java @@ -105,8 +105,13 @@ static class CodeGenerator extends PropertyCodeGenerator { @Override public void addBuilderFieldDeclaration(SourceBuilder code) { - code.addLine("private final %1$s<%2$s> %3$s = new %1$s%4$s();", - LinkedHashSet.class, elementType, property.getName(), diamondOperator(elementType)); + if (code.feature(GUAVA).isAvailable()) { + code.addLine("private %s<%s> %s = %s.of();", + Set.class, elementType, property.getName(), ImmutableSet.class); + } else { + code.addLine("private final %1$s<%2$s> %3$s = new %1$s%4$s();", + LinkedHashSet.class, elementType, property.getName(), diamondOperator(elementType)); + } } @Override @@ -138,6 +143,12 @@ private void addAdd(SourceBuilder code, Metadata metadata) { metadata.getBuilder(), addMethod(property), unboxedType.or(elementType)); + if (code.feature(GUAVA).isAvailable()) { + code.addLine(" if (this.%s instanceof %s) {", property.getName(), ImmutableSet.class) + .addLine(" this.%1$s = new %2$s%3$s(this.%1$s);", + property.getName(), LinkedHashSet.class, diamondOperator(elementType)) + .addLine(" }"); + } if (unboxedType.isPresent()) { code.addLine(" this.%s.add(element);", property.getName()); } else { @@ -214,6 +225,12 @@ private void addRemove(SourceBuilder code, Metadata metadata) { metadata.getBuilder(), removeMethod(property), unboxedType.or(elementType)); + if (code.feature(GUAVA).isAvailable()) { + code.addLine(" if (this.%s instanceof %s) {", property.getName(), ImmutableSet.class) + .addLine(" this.%1$s = new %2$s%3$s(this.%1$s);", + property.getName(), LinkedHashSet.class, diamondOperator(elementType)) + .addLine(" }"); + } if (unboxedType.isPresent()) { code.addLine(" this.%s.remove(element);", property.getName()); } else { @@ -246,6 +263,12 @@ private void addMutator(SourceBuilder code, Metadata metadata) { consumer.get().getQualifiedName(), Set.class, elementType); + if (code.feature(GUAVA).isAvailable()) { + code.addLine(" if (%s instanceof %s) {", property.getName(), ImmutableSet.class) + .addLine(" %1$s = new %2$s%3$s(%1$s);", + property.getName(), LinkedHashSet.class, diamondOperator(elementType)) + .addLine(" }"); + } if (overridesAddMethod) { code.addLine(" mutator.accept(new CheckedSet<%s>(%s, this::%s));", elementType, property.getName(), addMethod(property)); @@ -267,9 +290,17 @@ private void addClear(SourceBuilder code, Metadata metadata) { .addLine(" *") .addLine(" * @return this {@code %s} object", metadata.getBuilder().getSimpleName()) .addLine(" */") - .addLine("public %s %s() {", metadata.getBuilder(), clearMethod(property)) - .addLine(" %s.clear();", property.getName()) - .addLine(" return (%s) this;", metadata.getBuilder()) + .addLine("public %s %s() {", metadata.getBuilder(), clearMethod(property)); + if (code.feature(GUAVA).isAvailable()) { + code.addLine("if (%s instanceof %s) {", property.getName(), ImmutableSet.class) + .addLine(" %s = %s.of();", property.getName(), ImmutableSet.class) + .addLine("} else {"); + } + code.addLine("%s.clear();", property.getName()); + if (code.feature(GUAVA).isAvailable()) { + code.addLine("}"); + } + code.addLine(" return (%s) this;", metadata.getBuilder()) .addLine("}"); } @@ -280,8 +311,14 @@ private void addGetter(SourceBuilder code, Metadata metadata) { .addLine(" * %s.", metadata.getType().javadocNoArgMethodLink(property.getGetterName())) .addLine(" * Changes to this builder will be reflected in the view.") .addLine(" */") - .addLine("public %s<%s> %s() {", Set.class, elementType, getter(property)) - .addLine(" return %s.unmodifiableSet(%s);", Collections.class, property.getName()) + .addLine("public %s<%s> %s() {", Set.class, elementType, getter(property)); + if (code.feature(GUAVA).isAvailable()) { + code.addLine(" if (%s instanceof %s) {", property.getName(), ImmutableSet.class) + .addLine(" %1$s = new %2$s%3$s(%1$s);", + property.getName(), LinkedHashSet.class, diamondOperator(elementType)) + .addLine(" }"); + } + code.addLine(" return %s.unmodifiableSet(%s);", Collections.class, property.getName()) .addLine("}"); } @@ -298,7 +335,16 @@ public void addFinalFieldAssignment(SourceBuilder code, String finalField, Strin @Override public void addMergeFromValue(Block code, String value) { + if (code.feature(GUAVA).isAvailable()) { + code.addLine("if (%s instanceof %s && %s == %s.<%s>of()) {", + value, metadata.getValueType(), property.getName(), ImmutableSet.class, elementType) + .addLine(" %s = %s.%s();", property.getName(), value, property.getGetterName()) + .addLine("} else {"); + } code.addLine("%s(%s.%s());", addAllMethod(property), value, property.getGetterName()); + if (code.feature(GUAVA).isAvailable()) { + code.addLine("}"); + } } @Override @@ -317,7 +363,7 @@ public void addSetFromResult(SourceBuilder code, String builder, String variable @Override public void addClearField(Block code) { - code.addLine("%s.clear();", property.getName()); + code.addLine("%s();", clearMethod(property)); } @Override diff --git a/src/test/java/org/inferred/freebuilder/processor/SetMutateMethodTest.java b/src/test/java/org/inferred/freebuilder/processor/SetMutateMethodTest.java index f980b9ba0..5bebb1393 100644 --- a/src/test/java/org/inferred/freebuilder/processor/SetMutateMethodTest.java +++ b/src/test/java/org/inferred/freebuilder/processor/SetMutateMethodTest.java @@ -15,6 +15,9 @@ */ package org.inferred.freebuilder.processor; +import static org.inferred.freebuilder.processor.util.feature.FunctionPackage.FUNCTION_PACKAGE; +import static org.junit.Assume.assumeTrue; + import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; @@ -204,4 +207,22 @@ public void mutateAndAddDelegatesToAddMethodForValidation() { .runTest(); } + @Test + public void modifyAndMutateModifiesUnderlyingProperty() { + assumeTrue(features.get(FUNCTION_PACKAGE).consumer().isPresent()); + behaviorTester + .with(new Processor(features)) + .with(CHECKED_SET_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType value = new DataType.Builder().addProperties(1, 2).build();") + .addLine("DataType copy = DataType.Builder") + .addLine(" .from(value)") + .addLine(" .mutateProperties(set -> set.remove(1))") + .addLine(" .build();") + .addLine("assertThat(copy.getProperties()).containsExactly(2);") + .build()) + .runTest(); + } + } diff --git a/src/test/java/org/inferred/freebuilder/processor/SetPropertyFactoryTest.java b/src/test/java/org/inferred/freebuilder/processor/SetPropertyFactoryTest.java index 5c7cc062d..025680806 100644 --- a/src/test/java/org/inferred/freebuilder/processor/SetPropertyFactoryTest.java +++ b/src/test/java/org/inferred/freebuilder/processor/SetPropertyFactoryTest.java @@ -18,6 +18,7 @@ import static org.inferred.freebuilder.processor.util.feature.GuavaLibrary.GUAVA; import static org.junit.Assume.assumeTrue; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.testing.EqualsTester; @@ -29,8 +30,8 @@ import org.inferred.freebuilder.processor.util.feature.FeatureSet; import org.inferred.freebuilder.processor.util.testing.BehaviorTestRunner.Shared; import org.inferred.freebuilder.processor.util.testing.BehaviorTester; -import org.inferred.freebuilder.processor.util.testing.ParameterizedBehaviorTestFactory; import org.inferred.freebuilder.processor.util.testing.CompilationException; +import org.inferred.freebuilder.processor.util.testing.ParameterizedBehaviorTestFactory; import org.inferred.freebuilder.processor.util.testing.SourceBuilder; import org.inferred.freebuilder.processor.util.testing.TestBuilder; import org.junit.Rule; @@ -84,6 +85,48 @@ public static List featureSets() { .addLine("}") .build(); + private static final String STRING_VALIDATION_ERROR_MESSAGE = "Cannot add empty string"; + + private static final JavaFileObject VALIDATED_STRINGS = new SourceBuilder() + .addLine("package com.example;") + .addLine("@%s", FreeBuilder.class) + .addLine("public abstract class DataType {") + .addLine(" public abstract %s<%s> getItems();", Set.class, String.class) + .addLine("") + .addLine(" public static class Builder extends DataType_Builder {") + .addLine(" @Override public Builder addItems(String unused) {") + .addLine(" %s.checkArgument(!unused.isEmpty(), \"%s\");", + Preconditions.class, STRING_VALIDATION_ERROR_MESSAGE) + .addLine(" return super.addItems(unused);") + .addLine(" }") + .addLine(" }") + .addLine(" public static Builder builder() {") + .addLine(" return new Builder();") + .addLine(" }") + .addLine("}") + .build(); + + private static final String INT_VALIDATION_ERROR_MESSAGE = "Items must be non-negative"; + + private static final JavaFileObject VALIDATED_INTS = new SourceBuilder() + .addLine("package com.example;") + .addLine("@%s", FreeBuilder.class) + .addLine("public abstract class DataType {") + .addLine(" public abstract %s getItems();", Set.class) + .addLine("") + .addLine(" public static class Builder extends DataType_Builder {") + .addLine(" @Override public Builder addItems(int element) {") + .addLine(" %s.checkArgument(element >= 0, \"%s\");", + Preconditions.class, INT_VALIDATION_ERROR_MESSAGE) + .addLine(" return super.addItems(element);") + .addLine(" }") + .addLine(" }") + .addLine(" public static Builder builder() {") + .addLine(" return new Builder();") + .addLine(" }") + .addLine("}") + .build(); + @Parameter public FeatureSet features; @Rule public final ExpectedException thrown = ExpectedException.none(); @@ -303,7 +346,22 @@ public void testRemove_missingElement() { } @Test - public void testClear() { + public void testClear_noElements() { + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addLine("com.example.DataType value = new com.example.DataType.Builder()") + .addLine(" .clearItems()") + .addLine(" .addItems(\"three\", \"four\")") + .addLine(" .build();") + .addLine("assertThat(value.getItems()).containsExactly(\"three\", \"four\").inOrder();") + .build()) + .runTest(); + } + + @Test + public void testClear_twoElements() { behaviorTester .with(new Processor(features)) .with(SET_PROPERTY_AUTO_BUILT_TYPE) @@ -623,63 +681,55 @@ public void testImmutableSetProperty() { } @Test - public void testOverridingAdd() { + public void testValidation_varargsAdd() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage(STRING_VALIDATION_ERROR_MESSAGE); behaviorTester .with(new Processor(features)) - .with(new SourceBuilder() - .addLine("package com.example;") - .addLine("@%s", FreeBuilder.class) - .addLine("public abstract class DataType {") - .addLine(" public abstract %s<%s> getItems();", Set.class, String.class) - .addLine("") - .addLine(" public static class Builder extends DataType_Builder {") - .addLine(" @Override public Builder addItems(String unused) {") - .addLine(" return this;") - .addLine(" }") - .addLine(" }") - .addLine(" public static Builder builder() {") - .addLine(" return new Builder();") - .addLine(" }") - .addLine("}") + .with(VALIDATED_STRINGS) + .with(new TestBuilder() + .addLine("new com.example.DataType.Builder().addItems(\"one\", \"\");") .build()) + .runTest(); + } + + @Test + public void testValidation_addAll() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage(STRING_VALIDATION_ERROR_MESSAGE); + behaviorTester + .with(new Processor(features)) + .with(VALIDATED_STRINGS) .with(new TestBuilder() - .addLine("com.example.DataType value = new com.example.DataType.Builder()") - .addLine(" .addItems(\"zero\")", ImmutableList.class) - .addLine(" .addItems(\"one\", \"two\")", ImmutableList.class) - .addLine(" .addAllItems(%s.of(\"three\", \"four\"))", ImmutableList.class) - .addLine(" .build();") - .addLine("assertThat(value.getItems()).isEmpty();") + .addLine("new com.example.DataType.Builder().addAllItems(%s.of(\"three\", \"\"));", + ImmutableList.class) .build()) .runTest(); } @Test - public void testOverridingAdd_primitive() { + public void testPrimitiveValidation_varargsAdd() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage(INT_VALIDATION_ERROR_MESSAGE); behaviorTester .with(new Processor(features)) - .with(new SourceBuilder() - .addLine("package com.example;") - .addLine("@%s", FreeBuilder.class) - .addLine("public abstract class DataType {") - .addLine(" public abstract %s getItems();", Set.class) - .addLine("") - .addLine(" public static class Builder extends DataType_Builder {") - .addLine(" @Override public Builder addItems(int unused) {") - .addLine(" return this;") - .addLine(" }") - .addLine(" }") - .addLine(" public static Builder builder() {") - .addLine(" return new Builder();") - .addLine(" }") - .addLine("}") + .with(VALIDATED_INTS) + .with(new TestBuilder() + .addLine("new com.example.DataType.Builder().addItems(1, -2);") .build()) + .runTest(); + } + + @Test + public void testPrimitiveValidation_addAll() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage(INT_VALIDATION_ERROR_MESSAGE); + behaviorTester + .with(new Processor(features)) + .with(VALIDATED_INTS) .with(new TestBuilder() - .addLine("com.example.DataType value = new com.example.DataType.Builder()") - .addLine(" .addItems(0)", ImmutableList.class) - .addLine(" .addItems(1, 2)", ImmutableList.class) - .addLine(" .addAllItems(%s.of(3, 4))", ImmutableList.class) - .addLine(" .build();") - .addLine("assertThat(value.getItems()).isEmpty();") + .addLine("new com.example.DataType.Builder().addAllItems(%s.of(3, -4));", + ImmutableList.class) .build()) .runTest(); } @@ -742,4 +792,187 @@ public void testJacksonInteroperability() { .build()) .runTest(); } + + @Test + public void testFromReusesImmutableSetInstance() { + assumeTrue(features.get(GUAVA).isAvailable()); + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType value = new DataType.Builder()") + .addLine(" .addItems(\"one\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType copy = DataType.Builder.from(value).build();") + .addLine("assertThat(copy.getItems()).isSameAs(value.getItems());") + .build()) + .runTest(); + } + + @Test + public void testMergeFromReusesImmutableSetInstance() { + assumeTrue(features.get(GUAVA).isAvailable()); + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType value = new DataType.Builder()") + .addLine(" .addItems(\"one\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType copy = new DataType.Builder().mergeFrom(value).build();") + .addLine("assertThat(copy.getItems()).isSameAs(value.getItems());") + .build()) + .runTest(); + } + + @Test + public void testMergeFromEmptySetDoesNotPreventReuseOfImmutableSetInstance() { + assumeTrue(features.get(GUAVA).isAvailable()); + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType value = new DataType.Builder()") + .addLine(" .addItems(\"one\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType copy = new DataType.Builder()") + .addLine(" .from(value)") + .addLine(" .mergeFrom(new DataType.Builder())") + .addLine(" .build();") + .addLine("assertThat(copy.getItems()).isSameAs(value.getItems());") + .build()) + .runTest(); + } + + @Test + public void testModifyAndAdd() { + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType value = new DataType.Builder()") + .addLine(" .addItems(\"one\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType copy = DataType.Builder") + .addLine(" .from(value)") + .addLine(" .addItems(\"three\")") + .addLine(" .build();") + .addLine("assertThat(copy.getItems())") + .addLine(" .containsExactly(\"one\", \"two\", \"three\")") + .addLine(" .inOrder();") + .build()) + .runTest(); + } + + @Test + public void testModifyAndRemove() { + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType value = new DataType.Builder()") + .addLine(" .addItems(\"one\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType copy = DataType.Builder") + .addLine(" .from(value)") + .addLine(" .removeItems(\"one\")") + .addLine(" .build();") + .addLine("assertThat(copy.getItems()).containsExactly(\"two\");") + .build()) + .runTest(); + } + + @Test + public void testModifyAndClear() { + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType value = new DataType.Builder()") + .addLine(" .addItems(\"one\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType copy = DataType.Builder") + .addLine(" .from(value)") + .addLine(" .clearItems()") + .addLine(" .build();") + .addLine("assertThat(copy.getItems()).isEmpty();") + .build()) + .runTest(); + } + + @Test + public void testModifyAndClearAll() { + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType value = new DataType.Builder()") + .addLine(" .addItems(\"one\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType copy = DataType.Builder") + .addLine(" .from(value)") + .addLine(" .clear()") + .addLine(" .build();") + .addLine("assertThat(copy.getItems()).isEmpty();") + .build()) + .runTest(); + } + + @Test + public void testMergeInvalidData() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage(STRING_VALIDATION_ERROR_MESSAGE); + behaviorTester + .with(new Processor(features)) + .with(VALIDATED_STRINGS) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addImport(Set.class) + .addImport(ImmutableSet.class) + .addLine("DataType value = new DataType() {") + .addLine(" @Override public Set getItems() {") + .addLine(" return ImmutableSet.of(\"foo\", \"\");") + .addLine(" }") + .addLine("};") + .addLine("DataType.Builder.from(value);") + .build()) + .runTest(); + } + + @Test + public void testMergeCombinesSets() { + behaviorTester + .with(new Processor(features)) + .with(SET_PROPERTY_AUTO_BUILT_TYPE) + .with(new TestBuilder() + .addImport("com.example.DataType") + .addLine("DataType data1 = new DataType.Builder()") + .addLine(" .addItems(\"one\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType data2 = new DataType.Builder()") + .addLine(" .addItems(\"three\")") + .addLine(" .addItems(\"two\")") + .addLine(" .build();") + .addLine("DataType copy = DataType.Builder.from(data2).mergeFrom(data1).build();") + .addLine("assertThat(copy.getItems())") + .addLine(" .containsExactly(\"three\", \"two\", \"one\")") + .addLine(" .inOrder();") + .build()) + .runTest(); + } } diff --git a/src/test/java/org/inferred/freebuilder/processor/SetSourceTest.java b/src/test/java/org/inferred/freebuilder/processor/SetSourceTest.java index ca1a6b48c..9703190c4 100644 --- a/src/test/java/org/inferred/freebuilder/processor/SetSourceTest.java +++ b/src/test/java/org/inferred/freebuilder/processor/SetSourceTest.java @@ -61,7 +61,7 @@ public void test_guava_j6() { " return new Person.Builder().mergeFrom(value);", " }", "", - " private final LinkedHashSet name = new LinkedHashSet();", + " private Set name = ImmutableSet.of();", "", " /**", " * Adds {@code element} to the set to be returned from {@link Person#getName()}.", @@ -72,6 +72,9 @@ public void test_guava_j6() { " * @throws NullPointerException if {@code element} is null", " */", " public Person.Builder addName(String element) {", + " if (this.name instanceof ImmutableSet) {", + " this.name = new LinkedHashSet(this.name);", + " }", " this.name.add(Preconditions.checkNotNull(element));", " return (Person.Builder) this;", " }", @@ -116,6 +119,9 @@ public void test_guava_j6() { " * @throws NullPointerException if {@code element} is null", " */", " public Person.Builder removeName(String element) {", + " if (this.name instanceof ImmutableSet) {", + " this.name = new LinkedHashSet(this.name);", + " }", " this.name.remove(Preconditions.checkNotNull(element));", " return (Person.Builder) this;", " }", @@ -126,7 +132,11 @@ public void test_guava_j6() { " * @return this {@code Builder} object", " */", " public Person.Builder clearName() {", - " name.clear();", + " if (name instanceof ImmutableSet) {", + " name = ImmutableSet.of();", + " } else {", + " name.clear();", + " }", " return (Person.Builder) this;", " }", "", @@ -136,6 +146,9 @@ public void test_guava_j6() { " * Changes to this builder will be reflected in the view.", " */", " public Set getName() {", + " if (name instanceof ImmutableSet) {", + " name = new LinkedHashSet(name);", + " }", " return Collections.unmodifiableSet(name);", " }", "", @@ -143,7 +156,11 @@ public void test_guava_j6() { " * Sets all property values using the given {@code Person} as a template.", " */", " public Person.Builder mergeFrom(Person value) {", - " addAllName(value.getName());", + " if (value instanceof Person_Builder.Value && name == ImmutableSet.of()) {", + " name = value.getName();", + " } else {", + " addAllName(value.getName());", + " }", " return (Person.Builder) this;", " }", "", @@ -160,7 +177,7 @@ public void test_guava_j6() { " * Resets the state of this builder.", " */", " public Person.Builder clear() {", - " name.clear();", + " clearName();", " return (Person.Builder) this;", " }", "", @@ -275,7 +292,7 @@ public void test_guava_j7() { " return new Person.Builder().mergeFrom(value);", " }", "", - " private final LinkedHashSet name = new LinkedHashSet<>();", + " private Set name = ImmutableSet.of();", "", " /**", " * Adds {@code element} to the set to be returned from {@link Person#getName()}.", @@ -286,6 +303,9 @@ public void test_guava_j7() { " * @throws NullPointerException if {@code element} is null", " */", " public Person.Builder addName(String element) {", + " if (this.name instanceof ImmutableSet) {", + " this.name = new LinkedHashSet<>(this.name);", + " }", " this.name.add(Preconditions.checkNotNull(element));", " return (Person.Builder) this;", " }", @@ -330,6 +350,9 @@ public void test_guava_j7() { " * @throws NullPointerException if {@code element} is null", " */", " public Person.Builder removeName(String element) {", + " if (this.name instanceof ImmutableSet) {", + " this.name = new LinkedHashSet<>(this.name);", + " }", " this.name.remove(Preconditions.checkNotNull(element));", " return (Person.Builder) this;", " }", @@ -340,7 +363,11 @@ public void test_guava_j7() { " * @return this {@code Builder} object", " */", " public Person.Builder clearName() {", - " name.clear();", + " if (name instanceof ImmutableSet) {", + " name = ImmutableSet.of();", + " } else {", + " name.clear();", + " }", " return (Person.Builder) this;", " }", "", @@ -350,6 +377,9 @@ public void test_guava_j7() { " * Changes to this builder will be reflected in the view.", " */", " public Set getName() {", + " if (name instanceof ImmutableSet) {", + " name = new LinkedHashSet<>(name);", + " }", " return Collections.unmodifiableSet(name);", " }", "", @@ -357,7 +387,11 @@ public void test_guava_j7() { " * Sets all property values using the given {@code Person} as a template.", " */", " public Person.Builder mergeFrom(Person value) {", - " addAllName(value.getName());", + " if (value instanceof Person_Builder.Value && name == ImmutableSet.of()) {", + " name = value.getName();", + " } else {", + " addAllName(value.getName());", + " }", " return (Person.Builder) this;", " }", "", @@ -374,7 +408,7 @@ public void test_guava_j7() { " * Resets the state of this builder.", " */", " public Person.Builder clear() {", - " name.clear();", + " clearName();", " return (Person.Builder) this;", " }", "", @@ -487,7 +521,7 @@ public void test_guava_j8() { " return new Person.Builder().mergeFrom(value);", " }", "", - " private final LinkedHashSet name = new LinkedHashSet<>();", + " private Set name = ImmutableSet.of();", "", " /**", " * Adds {@code element} to the set to be returned from {@link Person#getName()}.", @@ -498,6 +532,9 @@ public void test_guava_j8() { " * @throws NullPointerException if {@code element} is null", " */", " public Person.Builder addName(String element) {", + " if (this.name instanceof ImmutableSet) {", + " this.name = new LinkedHashSet<>(this.name);", + " }", " this.name.add(Preconditions.checkNotNull(element));", " return (Person.Builder) this;", " }", @@ -542,6 +579,9 @@ public void test_guava_j8() { " * @throws NullPointerException if {@code element} is null", " */", " public Person.Builder removeName(String element) {", + " if (this.name instanceof ImmutableSet) {", + " this.name = new LinkedHashSet<>(this.name);", + " }", " this.name.remove(Preconditions.checkNotNull(element));", " return (Person.Builder) this;", " }", @@ -557,6 +597,9 @@ public void test_guava_j8() { " * @throws NullPointerException if {@code mutator} is null", " */", " public Person.Builder mutateName(Consumer> mutator) {", + " if (name instanceof ImmutableSet) {", + " name = new LinkedHashSet<>(name);", + " }", " // If addName is overridden, this method will be updated to delegate to it", " mutator.accept(name);", " return (Person.Builder) this;", @@ -568,7 +611,11 @@ public void test_guava_j8() { " * @return this {@code Builder} object", " */", " public Person.Builder clearName() {", - " name.clear();", + " if (name instanceof ImmutableSet) {", + " name = ImmutableSet.of();", + " } else {", + " name.clear();", + " }", " return (Person.Builder) this;", " }", "", @@ -578,6 +625,9 @@ public void test_guava_j8() { " * Changes to this builder will be reflected in the view.", " */", " public Set getName() {", + " if (name instanceof ImmutableSet) {", + " name = new LinkedHashSet<>(name);", + " }", " return Collections.unmodifiableSet(name);", " }", "", @@ -585,7 +635,11 @@ public void test_guava_j8() { " * Sets all property values using the given {@code Person} as a template.", " */", " public Person.Builder mergeFrom(Person value) {", - " addAllName(value.getName());", + " if (value instanceof Person_Builder.Value && name == ImmutableSet.of()) {", + " name = value.getName();", + " } else {", + " addAllName(value.getName());", + " }", " return (Person.Builder) this;", " }", "", @@ -602,7 +656,7 @@ public void test_guava_j8() { " * Resets the state of this builder.", " */", " public Person.Builder clear() {", - " name.clear();", + " clearName();", " return (Person.Builder) this;", " }", "", @@ -815,7 +869,7 @@ public void test_noGuava_j6() { " * Resets the state of this builder.", " */", " public Person.Builder clear() {", - " name.clear();", + " clearName();", " return (Person.Builder) this;", " }", "", @@ -1038,7 +1092,7 @@ public void test_noGuava_j7() { " * Resets the state of this builder.", " */", " public Person.Builder clear() {", - " name.clear();", + " clearName();", " return (Person.Builder) this;", " }", "",