Skip to content

Commit

Permalink
Make property builders a bit more flexible.
Browse files Browse the repository at this point in the history
Allow a property of type `List<T>` to be built by a property builder whose `build()` method returns `List<? extends T>`. This can show up in various `@AutoBuilder` scenarios with Kotlin, for example.

RELNOTES=A property of type `List<T>` can be built by a property builder whose `build()` method returns `List<? extends T>`.
PiperOrigin-RevId: 508665647
  • Loading branch information
eamonnmcmanus authored and Google Java Core Libraries committed Feb 10, 2023
1 parent 162ae8f commit 8ba4531
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.OptionalDouble;
Expand Down Expand Up @@ -922,4 +923,45 @@ public void nestedOptionalGetter() {
assertThat(foo.bar()).isNotNull();
assertThat(foo.baz()).isEqualTo(0.0);
}

// Test that we can build a property of type List<? extends Foo> using a property builder whose
// build() method returns List<Foo>. The main motivation for this is Kotlin, where you can
// easily run into this situation with "in" types.
// This is a "Java 8" test because the generated code uses List.of (which is actually Java 9).
// If we really are on Java 8 then the generated code will use `new ListBuilder<T>().build()`
// instead.
@AutoValue
public abstract static class PropertyBuilderWildcard<T> {
public abstract List<? extends T> list();

public static <T>PropertyBuilderWildcard.Builder<T> builder() {
return new AutoValue_AutoValueJava8Test_PropertyBuilderWildcard.Builder<>();
}

@AutoValue.Builder
public interface Builder<T> {
ListBuilder<T> listBuilder();

PropertyBuilderWildcard<T> build();
}

public static class ListBuilder<T> {
private final List<T> list = new ArrayList<>();

public void add(T value) {
list.add(value);
}

public List<T> build() {
return list;
}
}
}

@Test
public void propertyBuilderWildcard() {
PropertyBuilderWildcard.Builder<CharSequence> builder = PropertyBuilderWildcard.builder();
builder.listBuilder().add("foo");
assertThat(builder.build().list()).containsExactly("foo");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,9 @@ Optional<PropertyBuilder> makePropertyBuilder(ExecutableElement method, String p

// We've determined that `BarBuilder` has a method `build()` or `buildOrThrow(). But it must
// return `Bar`. And if the type of `bar()` is Bar<String> then `BarBuilder.build()` must return
// Bar<String>.
// something that can be assigned to Bar<String>.
TypeMirror buildType = eclipseHack.methodReturnType(build, barBuilderDeclaredType);
if (!MoreTypes.equivalence().equivalent(barTypeMirror, buildType)) {
if (!typeUtils.isAssignable(buildType, barTypeMirror)) {
errorReporter.reportError(
method,
"[AutoValueBuilderWrongType] Property builder for %s has type %s whose %s() method"
Expand Down

0 comments on commit 8ba4531

Please sign in to comment.