aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoremcmanus <emcmanus@google.com>2016-04-27 12:43:02 -0700
committerÉamonn McManus <eamonn@mcmanus.net>2016-05-10 08:35:15 -0700
commit8ef94fdb6edaabe08a09870ec4130b79872c474c (patch)
tree8abbba6e9fa39df8a2984cc9d3ee8d3845ccab95
parent0379b013eb04b6c6d2c01183969317af115b18c8 (diff)
downloadauto-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
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java33
-rw-r--r--value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java5
-rw-r--r--value/src/main/java/com/google/auto/value/processor/BuilderSpec.java13
-rw-r--r--value/src/main/java/com/google/auto/value/processor/Optionalish.java24
-rw-r--r--value/src/test/java/com/google/auto/value/processor/CompilationTest.java7
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();",