Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to add a value to a collection in Java AutoValue?

I have a Java AutoValue class with a List attribute. I'd like to allow the builder to append to the List rather than having to pass the entire constructed list.

Example:

import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Deck {
    public abstract List<Card> cards();
    public static Builder builder() {
        return new AutoValue_Card.Builder()
            .cards(new ArrayList<Card>());
    }
    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder cards(List<Card> cards);
        /**
         * Append card to cards in the constructed Deck.
         */
        public Builder addCard(Card card) {
            // Is it possible to write this function?
        }
    }
}

What's the best solution for writing the addCard function? Does AutoValue somehow support this already? The intermediate cards property in the constructed class not visible to the Builder so I can't access it directly. I could try to bypass the Builder directly by keeping my own copy of cards in the Builder, is that the only option here?

like image 781
user3170530 Avatar asked Dec 11 '15 22:12

user3170530


People also ask

What is AutoValue in Java?

1. Overview AutoValue is a source code generator for Java, and more specifically it's a library for generating source code for value objects or value-typed objects. In order to generate a value-type object all you have to do is to annotate an abstract class with the @AutoValue annotation and compile your class.

How do you add an element to a collection in Java?

The add () method of Java Collection Interface inserts the specified element in this Collection. It returns a Boolean value 'true', if it succeeds to insert the element in the specified collection else it returns 'false'. The parameter 'e' represents the element to be added in the Collection.

How to use AutoValue in a Maven project?

To use AutoValue in a Maven projects, you need to include the following dependency in the pom.xml: The latest version can be found by following this link. 3. Value-Typed Objects

How to generate a value-type object from an abstract class?

In order to generate a value-type object all you have to do is to annotate an abstract class with the @AutoValue annotation and compile your class. What is generated is a value object with accessor methods, parameterized constructor, properly overridden toString (), equals (Object) and hashCode () methods.


2 Answers

AutoValue has a few special features that come into play when you use Guava's immutable collections, since these collections all have their own associated builder types. (And, of course, you certainly want the properties of your value classes to be immutable!)

One feature is you can define an abstract cardsBuilder() method, which will start a new builder of the appropriate collection type and return it to the caller. This is super flexible, but the one sad thing about it is that it "breaks the chain". The caller is now making calls on an ImmutableList.Builder and can't get back to the Deck.Builder to call build.

But you can address that by adding your own addCard method, just as you've shown it above, and just implement it to call cardsBuilder().add(card) and then return this instead of the builder. Problem solved!

I believe all this should be functional in 1.1 but please let us know if you have trouble!

P.S. I apologize -- we have a lot of new material for the AutoValue user guide, including this topic, that has been held up in getting pushed out to the public site due to a few technical difficulties.

like image 170
Kevin Bourrillion Avatar answered Oct 20 '22 07:10

Kevin Bourrillion


In case someone finds it useful - here is the actual code of what I assume Kevin suggested. It was not obvious when I first stumbled upon his reply, so here you go:

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;

@AutoValue
public abstract class Hand {
  public static Builder builder() {
    return new AutoValue_Hand.Builder();
  }

  public abstract Builder toBuilder();

  public abstract String name();

  public abstract ImmutableList<String> cards();

  @AutoValue.Builder
  public static abstract class Builder {

    public abstract Builder name(String name);

    protected abstract ImmutableList.Builder<String> cardsBuilder();

    public Builder addCard(String card) {
      cardsBuilder().add(card);
      return this;
    }

    public abstract Hand build();
  }
}

Usage:

Hand fullHouseHand = Hand.builder()
    .name("Full House")
    .addCard("King")
    .addCard("King")
    .addCard("King")
    .addCard("10")
    .addCard("10")
    .build();
System.out.print(fullHouseHand);

Output:

Hand{name=Full House, cards=[King, King, King, 10, 10]}
like image 45
Andrey Mormysh Avatar answered Oct 20 '22 07:10

Andrey Mormysh