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?
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.
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.
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
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.
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.
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]}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With