Skip to content

Commit

Permalink
Add support for Nullable on Optional property builders
Browse files Browse the repository at this point in the history
  • Loading branch information
octylFractal committed Mar 8, 2017
1 parent 66d0be1 commit 6a9bfe5
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
Expand Down Expand Up @@ -310,12 +311,14 @@ public class PropertySetter {
private final String parameterTypeString;
private final boolean primitiveParameter;
private final String copyOf;
private final String nullableAnnotation;

public PropertySetter(
ExecutableElement setter, TypeMirror propertyType, TypeSimplifier typeSimplifier) {
this.access = AutoValueProcessor.access(setter);
this.name = setter.getSimpleName().toString();
TypeMirror parameterType = Iterables.getOnlyElement(setter.getParameters()).asType();
VariableElement parameterElement = Iterables.getOnlyElement(setter.getParameters());
TypeMirror parameterType = parameterElement.asType();
primitiveParameter = parameterType.getKind().isPrimitive();
String simplifiedParameterType = typeSimplifier.simplify(parameterType);
if (setter.isVarArgs()) {
Expand All @@ -327,10 +330,30 @@ public PropertySetter(
boolean sameType = typeUtils.isSameType(typeUtils.erasure(parameterType), erasedPropertyType);
if (sameType) {
this.copyOf = null;
this.nullableAnnotation = "";
} else {
String rawTarget = typeSimplifier.simplifyRaw(erasedPropertyType);
String of = Optionalish.isOptional(propertyType) ? "of" : "copyOf";
Optionalish optional = Optionalish.createIfOptional(propertyType, rawTarget);
String nullableAnnotation = "";
String of = null;
if (optional != null) {
for (AnnotationMirror annotationMirror : parameterElement.getAnnotationMirrors()) {
AnnotationOutput annotationOutput = new AnnotationOutput(typeSimplifier);
String annotationName = annotationOutput.sourceFormForAnnotation(annotationMirror);
if (annotationName.equals("@Nullable") || annotationName.endsWith(".Nullable")) {
of = optional.getNullable();
nullableAnnotation = annotationName + " ";
break;
}
}
if (of == null) {
of = "of";
}
} else {
of = "copyOf";
}
this.copyOf = rawTarget + "." + of + "(%s)";
this.nullableAnnotation = nullableAnnotation;
}
}

Expand All @@ -350,6 +373,10 @@ public boolean getPrimitiveParameter() {
return primitiveParameter;
}

public String getNullableAnnotation() {
return nullableAnnotation;
}

public String copy(AutoValueProcessor.Property property) {
if (copyOf == null) {
return property.toString();
Expand All @@ -358,7 +385,7 @@ public String copy(AutoValueProcessor.Property property) {
String copy = String.format(copyOf, property);

// Add a null guard only in cases where we are using copyOf and the property is @Nullable.
if (property.isNullable()) {
if (property.isNullable() || nullableAnnotation != null) {
copy = String.format("(%s == null ? null : %s)", property, copy);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,24 @@ public String getEmpty() {
return rawTypeSpelling + empty;
}

/**
* Returns a string representing the method call to obtain the nullable version of this Optional.
* This will be something like {@code "fromNullable()"} or possibly {@code "ofNullable()"}. It does not have a final semicolon.
*
* <p>This method is public so that it can be referenced as {@code p.optional.nullable} from
* templates.
*/
public String getNullable() {
if (optionalType.getTypeArguments().isEmpty()) {
// No typeArguments means a primitive wrapper -- it has no nullable input
return "of";
}
TypeElement typeElement = MoreElements.asType(optionalType.asElement());
return typeElement.getQualifiedName().toString().startsWith("java.util.")
? "ofNullable"
: "fromNullable";
}

TypeMirror getContainedType(Types typeUtils) {
List<? extends TypeMirror> typeArguments = optionalType.getTypeArguments();
switch (typeArguments.size()) {
Expand Down
10 changes: 8 additions & 2 deletions value/src/main/java/com/google/auto/value/processor/autovalue.vm
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,17 @@ $a

#foreach ($setter in $builderSetters[$p.name])

#if ($p.nullable)
#set ($nullableAnnotation = $p.nullableAnnotation)
#else
#set ($nullableAnnotation = $setter.nullableAnnotation)
#end

@Override
${setter.access}${builderTypeName}${builderActualTypes} ##
${setter.name}(${p.nullableAnnotation}$setter.parameterType $p) {
${setter.name}(${nullableAnnotation}$setter.parameterType $p) {

#if (!$setter.primitiveParameter && !$p.nullable)
#if (!$setter.primitiveParameter && !$nullableAnnotation)

if ($p == null) {
throw new NullPointerException("Null $p.name");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ public void correctBuilder() throws Exception {
" public abstract ImmutableList<T> anImmutableList();",
" public abstract Optional<String> anOptionalString();",
" public abstract NestedAutoValue<T> aNestedAutoValue();",
" public abstract Optional<Object> anOptionalObject();",
"",
" public abstract Builder<T> toBuilder();",
"",
Expand All @@ -616,6 +617,7 @@ public void correctBuilder() throws Exception {
" public abstract Builder<T> anOptionalString(Optional<String> s);",
" public abstract Builder<T> anOptionalString(String s);",
" public abstract NestedAutoValue.Builder<T> aNestedAutoValueBuilder();",
" public abstract Builder<T> anOptionalObject(@Nullable Object s);",
"",
" public Builder<T> aList(ArrayList<T> x) {",
// ArrayList should not be imported in the generated class.
Expand Down Expand Up @@ -675,6 +677,7 @@ public void correctBuilder() throws Exception {
" private final ImmutableList<T> anImmutableList;",
" private final Optional<String> anOptionalString;",
" private final NestedAutoValue<T> aNestedAutoValue;",
" private final Optional<Object> anOptionalObject;",
"",
" private AutoValue_Baz(",
" int anInt,",
Expand All @@ -683,14 +686,16 @@ public void correctBuilder() throws Exception {
" List<T> aList,",
" ImmutableList<T> anImmutableList,",
" Optional<String> anOptionalString,",
" NestedAutoValue<T> aNestedAutoValue) {",
" NestedAutoValue<T> aNestedAutoValue,",
" Optional<Object> anOptionalObject) {",
" this.anInt = anInt;",
" this.aByteArray = aByteArray;",
" this.aNullableIntArray = aNullableIntArray;",
" this.aList = aList;",
" this.anImmutableList = anImmutableList;",
" this.anOptionalString = anOptionalString;",
" this.aNestedAutoValue = aNestedAutoValue;",
" this.anOptionalObject = anOptionalObject;",
" }",
"",
" @Override public int anInt() {",
Expand Down Expand Up @@ -724,6 +729,10 @@ public void correctBuilder() throws Exception {
" return aNestedAutoValue;",
" }",
"",
" @Override public Optional<Object> anOptionalObject() {",
" return anOptionalObject;",
" }",
"",
" @Override public String toString() {",
" return \"Baz{\"",
" + \"anInt=\" + anInt + \", \"",
Expand All @@ -732,7 +741,8 @@ public void correctBuilder() throws Exception {
" + \"aList=\" + aList + \", \"",
" + \"anImmutableList=\" + anImmutableList + \", \"",
" + \"anOptionalString=\" + anOptionalString + \", \"",
" + \"aNestedAutoValue=\" + aNestedAutoValue",
" + \"aNestedAutoValue=\" + aNestedAutoValue + \", \"",
" + \"anOptionalObject=\" + anOptionalObject",
" + \"}\";",
" }",
"",
Expand All @@ -752,7 +762,8 @@ public void correctBuilder() throws Exception {
" && (this.aList.equals(that.aList()))",
" && (this.anImmutableList.equals(that.anImmutableList()))",
" && (this.anOptionalString.equals(that.anOptionalString()))",
" && (this.aNestedAutoValue.equals(that.aNestedAutoValue()));",
" && (this.aNestedAutoValue.equals(that.aNestedAutoValue()))",
" && (this.anOptionalObject.equals(that.anOptionalObject()));",
" }",
" return false;",
" }",
Expand All @@ -773,6 +784,8 @@ public void correctBuilder() throws Exception {
" h ^= this.anOptionalString.hashCode();",
" h *= 1000003;",
" h ^= this.aNestedAutoValue.hashCode();",
" h *= 1000003;",
" h ^= this.anOptionalObject.hashCode();",
" return h;",
" }",
"",
Expand All @@ -790,6 +803,7 @@ public void correctBuilder() throws Exception {
" private Optional<String> anOptionalString = Optional.absent();",
" private NestedAutoValue.Builder<T> aNestedAutoValueBuilder$;",
" private NestedAutoValue<T> aNestedAutoValue;",
" private Optional<Object> anOptionalObject = Optional.absent();",
"",
" Builder() {",
" }",
Expand All @@ -802,6 +816,7 @@ public void correctBuilder() throws Exception {
" this.anImmutableList = source.anImmutableList();",
" this.anOptionalString = source.anOptionalString();",
" this.aNestedAutoValue = source.aNestedAutoValue();",
" this.anOptionalObject = source.anOptionalObject();",
" }",
"",
" @Override",
Expand Down Expand Up @@ -921,6 +936,12 @@ public void correctBuilder() throws Exception {
" }",
"",
" @Override",
" public Baz.Builder<T> anOptionalObject(@Nullable Object anOptionalObject) {",
" this.anOptionalObject = Optional.fromNullable(anOptionalObject);",
" return this;",
" }",
"",
" @Override",
" public Baz<T> build() {",
" if (anImmutableListBuilder$ != null) {",
" this.anImmutableList = anImmutableListBuilder$.build();",
Expand Down Expand Up @@ -953,7 +974,8 @@ public void correctBuilder() throws Exception {
" this.aList,",
" this.anImmutableList,",
" this.anOptionalString,",
" this.aNestedAutoValue);",
" this.aNestedAutoValue,",
" this.anOptionalObject);",
" }",
" }",
"}");
Expand Down

0 comments on commit 6a9bfe5

Please sign in to comment.