diff options
author | emcmanus <emcmanus@google.com> | 2016-04-27 12:43:02 -0700 |
---|---|---|
committer | Éamonn McManus <eamonn@mcmanus.net> | 2016-05-10 08:35:15 -0700 |
commit | 8ef94fdb6edaabe08a09870ec4130b79872c474c (patch) | |
tree | 8abbba6e9fa39df8a2984cc9d3ee8d3845ccab95 | |
parent | 0379b013eb04b6c6d2c01183969317af115b18c8 (diff) | |
download | auto-8ef94fdb6edaabe08a09870ec4130b79872c474c.tar.gz |
In AutoValue builders, support setting a property of type Optional<T> via a setter with an argument of type T.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=120943277
5 files changed, 70 insertions, 12 deletions
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java index c17eb94c..4c5d4b43 100644 --- a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java +++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java @@ -1290,6 +1290,7 @@ public class AutoValueTest extends TestCase { @AutoValue.Builder public interface Builder { Builder setOptionalString(com.google.common.base.Optional<String> s); + Builder setOptionalString(String s); OptionalPropertyWithBuilder build(); } } @@ -1302,6 +1303,11 @@ public class AutoValueTest extends TestCase { .setOptionalString(com.google.common.base.Optional.of("foo")) .build(); assertThat(supplied.optionalString()).hasValue("foo"); + + OptionalPropertyWithBuilder suppliedDirectly = OptionalPropertyWithBuilder.builder() + .setOptionalString("foo") + .build(); + assertThat(suppliedDirectly.optionalString()).hasValue("foo"); } @AutoValue @@ -1332,6 +1338,33 @@ public class AutoValueTest extends TestCase { } @AutoValue + public abstract static class OptionalPropertyWithBuilderSimpleSetter { + public abstract com.google.common.base.Optional<String> optionalString(); + + public static Builder builder() { + return new AutoValue_AutoValueTest_OptionalPropertyWithBuilderSimpleSetter.Builder(); + } + + @AutoValue.Builder + public interface Builder { + Builder setOptionalString(String s); + OptionalPropertyWithBuilderSimpleSetter build(); + } + } + + public void testOptionalPropertySimpleSetter() { + OptionalPropertyWithBuilderSimpleSetter omitted = + OptionalPropertyWithBuilderSimpleSetter.builder().build(); + assertThat(omitted.optionalString()).isAbsent(); + + OptionalPropertyWithBuilderSimpleSetter supplied = + OptionalPropertyWithBuilderSimpleSetter.builder() + .setOptionalString("foo") + .build(); + assertThat(supplied.optionalString()).hasValue("foo"); + } + + @AutoValue public abstract static class GenericsWithBuilder<T extends Number & Comparable<T>, U extends T> { public abstract List<T> list(); public abstract U u(); diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java index 56148565..10afdee7 100644 --- a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java +++ b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java @@ -368,7 +368,7 @@ class BuilderMethodClassifier { /** * Checks that the given setter method has a parameter type that is compatible with the return * type of the given getter. Compatible means either that it is the same, or that it is a type - * that can be copied using a method like {@code ImmutableList.copyOf}. + * that can be copied using a method like {@code ImmutableList.copyOf} or {@code Optional.of}. * * @return true if the types correspond, false if an error has been reported. */ @@ -459,11 +459,12 @@ class BuilderMethodClassifier { if (!targetType.getKind().equals(TypeKind.DECLARED)) { return ImmutableList.of(); } + String copyOf = Optionalish.isOptional(targetType) ? "of" : "copyOf"; TypeElement immutableTargetType = MoreElements.asType(typeUtils.asElement(targetType)); ImmutableList.Builder<ExecutableElement> copyOfMethods = ImmutableList.builder(); for (ExecutableElement method : ElementFilter.methodsIn(immutableTargetType.getEnclosedElements())) { - if (method.getSimpleName().contentEquals("copyOf") + if (method.getSimpleName().contentEquals(copyOf) && method.getParameters().size() == 1 && method.getModifiers().contains(Modifier.STATIC)) { copyOfMethods.add(method); diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java b/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java index 9c5aec99..4db8552d 100644 --- a/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java +++ b/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java @@ -260,7 +260,8 @@ class BuilderSpec { * method {@code foo(T)} or {@code setFoo(T)} that returns the builder type. Additionally, it * can have a setter with a type that can be copied to {@code T} through a {@code copyOf} method; * for example a property {@code foo} of type {@code ImmutableSet<String>} can be set with a - * method {@code setFoo(Collection<String> foos)}. + * method {@code setFoo(Collection<String> foos)}. And, if {@code T} is {@code Optional}, + * it can have a setter with a type that can be copied to {@code T} through {@code Optional.of}. */ public class PropertySetter { private final String name; @@ -279,9 +280,13 @@ class BuilderSpec { Types typeUtils = processingEnv.getTypeUtils(); TypeMirror erasedPropertyType = typeUtils.erasure(propertyType); boolean sameType = typeUtils.isSameType(typeUtils.erasure(parameterType), erasedPropertyType); - this.copyOf = sameType - ? null - : typeSimplifier.simplifyRaw(erasedPropertyType) + ".copyOf(%s)"; + if (sameType) { + this.copyOf = null; + } else { + String rawTarget = typeSimplifier.simplifyRaw(erasedPropertyType); + String of = Optionalish.isOptional(propertyType) ? "of" : "copyOf"; + this.copyOf = rawTarget + "." + of + "(%s)"; + } } public String getName() { diff --git a/value/src/main/java/com/google/auto/value/processor/Optionalish.java b/value/src/main/java/com/google/auto/value/processor/Optionalish.java index b19f72d5..e4fbd283 100644 --- a/value/src/main/java/com/google/auto/value/processor/Optionalish.java +++ b/value/src/main/java/com/google/auto/value/processor/Optionalish.java @@ -2,6 +2,7 @@ package com.google.auto.value.processor; import com.google.auto.common.MoreElements; import com.google.auto.common.MoreTypes; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import javax.lang.model.element.TypeElement; @@ -41,22 +42,33 @@ public class Optionalish { * {@code OptionalInt}, etc. In cases of ambiguity it might be {@code java.util.Optional} etc. */ static Optionalish createIfOptional(TypeMirror type, String rawTypeSpelling) { + TypeElement optionalType = asOptionalTypeElement(type); + if (optionalType == null) { + return null; + } else { + return new Optionalish(optionalType, Preconditions.checkNotNull(rawTypeSpelling)); + } + } + + static boolean isOptional(TypeMirror type) { + return asOptionalTypeElement(type) != null; + } + + private static TypeElement asOptionalTypeElement(TypeMirror type) { if (type.getKind() != TypeKind.DECLARED) { return null; } DeclaredType declaredType = MoreTypes.asDeclared(type); TypeElement typeElement = MoreElements.asType(declaredType.asElement()); - if (OPTIONAL_CLASS_NAMES.contains(typeElement.getQualifiedName().toString())) { - return new Optionalish(typeElement, rawTypeSpelling); - } else { - return null; - } + return OPTIONAL_CLASS_NAMES.contains(typeElement.getQualifiedName().toString()) + ? typeElement + : null; } /** * Returns a string representing the method call to obtain the empty version of this Optional. * This will be something like {@code "Optional.empty()"} or possibly - * {@code java.util.Optional.empty()}. It does not have a final semicolon. + * {@code "java.util.Optional.empty()"}. It does not have a final semicolon. * * <p>This method is public so that it can be referenced as {@code p.optional.empty} from * templates. diff --git a/value/src/test/java/com/google/auto/value/processor/CompilationTest.java b/value/src/test/java/com/google/auto/value/processor/CompilationTest.java index 34947567..dc5323a8 100644 --- a/value/src/test/java/com/google/auto/value/processor/CompilationTest.java +++ b/value/src/test/java/com/google/auto/value/processor/CompilationTest.java @@ -615,6 +615,7 @@ public class CompilationTest { " Builder<T> anImmutableList(List<T> x);", " ImmutableList.Builder<T> anImmutableListBuilder();", " Builder<T> anOptionalString(Optional<String> s);", + " Builder<T> anOptionalString(String s);", "", " List<T> aList();", " ImmutableList<T> anImmutableList();", @@ -829,6 +830,12 @@ public class CompilationTest { " }", "", " @Override", + " public Baz.Builder<T> anOptionalString(String anOptionalString) {", + " this.anOptionalString = Optional.of(anOptionalString);", + " return this;", + " }", + "", + " @Override", " public Baz<T> build() {", " if (anImmutableListBuilder$ != null) {", " anImmutableList = anImmutableListBuilder$.build();", |