Skip to content

AutoValue: Allow using a Comparator for fluent building #1910

Description

@GeenDutchman

Hello!
I am using AutoValue 1.11.0 (and Java 21) and I'm trying to use an ImmutableSortedSet in an AutoValue, and that has an AutoValue.Builder. I'd like to pass in a Comparator so that I can decide how the set gets ordered.

I'm also really fond of the fluent builder style, and I've been using what is described here in the builders how-to.

However, that breaks when I'm trying to use a Comparator. The generated code (rightly) does not let me call ImmutableSortedSet.Builder<Element> elementsBuilder(Comparator comparator) more than once. The pattern given in the how-to, however, would have me do that. I've tried having it also generate a ImmutableSortedSet.Builder<Element> elementsBuilder(), but if both are present, it only generates the no-arg method.

I can see some workarounds, and I'm probably going to try them in the meantime.

  • Caching the elementsBuilder in the abstract class
  • I'm the one writing the Element class in this case, so I could implement Comparable<Element> (could get messy with inheritances though)
  • Having my "fluent" accumulator accept some Consumer<ImmutableSortedSet.Builder<Element>> argument?
  • "Break the chain" and just let whoever is using the builder have to hold their own references

I can see trying to generate both the one-arg and the no-arg methods getting messy because it wouldn't be possible to really enforce which gets called first/which to initialize the sub-builder with. I'm not sure about other possible generated solutions.

Is there an official recommendation for how to do this, or documentation that I missed reading? I've read through 984 and friends, but I haven't found anything mixing the one-arg constructor and the fluent builder.

Thank you for your help!

Activity

  1. cpovirk commented on Mar 31, 2025

    @cpovirk
    Member

    Hi, I found an internal thread (bug 209951563, about 3.5 years ago) in which @eamonnmcmanus discussed this with another user. There, he suggested your first option, which he illustrated as follows:

      @AutoValue.Builder
      public abstract static class Builder {
        private final ImmutableSortedSet.Builder<SomeProto> someSetBuilder = someSetBuilder(COMPARATOR);
    
        abstract ImmutableSortedSet.Builder<SomeProto> someSetBuilder(
            Comparator<SomeProto> comparator);
    
        public final Builder addSome(SomeProto value) {
          someSetBuilder.add(value);
          return this;
        }
    
        public abstract MyClass build();
      }

    He'll probably have better judgment than I would as to whether it's time to document this. In the meantime, it is at least good that we have this external issue about it, so thanks for filing.

  2. eamonnmcmanus commented on Mar 31, 2025

    @eamonnmcmanus
    Member

    I think the right solution here is to allow extra calls to someSetBuilder(comparator) provided that the comparator is the same in each case. As @cpovirk notes, that is already tracked in internal bug 209951563. (Comparator instances will typically only ever be equal if they are identical, but I think we can use equals anyway.)

  3. hiSandog commented on Jul 8, 2026

    @hiSandog

    This looks like a good regression-test candidate around AutoValue: Allow using a Comparator for fluent building. A focused test that reproduces the failing path and asserts the expected output/error would make future triage much easier than relying on the broader job failure alone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions