I am investigating auto-value and its extensions, namely auto-value-parcel and auto-value-parcel-adapter within my Android application.
I have these model classes:-
@AutoValue
public abstract class Xenarchaeota implements Parcelable {
    @ParcelAdapter(AmoebaTypeAdapter.class)
    public abstract Set<Amoeba> amoebas();
    public static Builder builder() {
        return new AutoValue_Xenarchaeota.Builder();
    }
    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder setAmoebas(Set<Amoeba> value);
        public abstract Xenarchaeota build();
    }
}
and
@AutoValue
public abstract class Amoeba implements Parcelable {
    public abstract String surname();
    public static Builder builder() {
        return new AutoValue_Amoeba.Builder();
    }
    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder surname(final String value);
        public abstract Amoeba build();
    }
}
My type adapter is where my issues arise
class AmoebaTypeAdapter implements TypeAdapter<Set<Amoeba>> {
    @Override
    public Set<Amoeba> fromParcel(Parcel in) {
        final ArrayList<Amoeba> arrayList = new ArrayList<>();
        in.readTypedList(arrayList, Amoeba.CREATOR); // How to access the CREATOR?
        return new TreeSet<>(arrayList);
    }
    @Override
    public void toParcel(Set<Amoeba> value, Parcel dest) {
        final ArrayList<Amoeba> arrayList = new ArrayList<>(value);
        dest.writeTypedList(arrayList);
    }
}
The CREATOR I need to pass to the readTypedArray is declared in AutoValue_Amoeba.
Where is my mistake? misunderstanding of auto-value-parcel?
AutoValue: Parcel extension can't handle sets, but if you convert the property to a List things will work out of the box without a custom adapter. If you want to treat it as a Set you could do this. Keep in mind you'll probably also want to cache the Set.
@AutoValue
public abstract class Xenarchaeota implements Parcelable {
    abstract List<Amoeba> amoebaList();
    public Set<Amoeba> amoebas() {
        return new TreeSet(amoebaList());
    }
    public static Builder builder() {
        return new AutoValue_Xenarchaeota.Builder();
    }
    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder setAmoebas(Set<Amoeba> value);
        public abstract Xenarchaeota build();
    }
}
I believe I have identified a solution as follows:-
Currently the auto-value-parcel class 
com.ryanharter.auto.value.parcel.AutoValueParcelExtension
has a method called generateCreator:-
FieldSpec generateCreator(ProcessingEnvironment env, TypeName autoValueType, List<Property> properties, TypeName type, Map<TypeMirror, FieldSpec> typeAdapters) {
        ClassName creator = ClassName.bestGuess("android.os.Parcelable.Creator");
        TypeName creatorOfClass = ParameterizedTypeName.get(creator, type);
        ...
        ...
This method generates a Parcelable CREATOR that resembles this
public static final Parcelable.Creator<AutoValue_Amoeba> CREATOR = new Parcelable.Creator<AutoValue_Amoeba>() {
    @Override
    public AutoValue_Amoeba createFromParcel(Parcel in) {
      return new AutoValue_Amoeba(
          in.readString()
      );
    }
    @Override
    public AutoValue_Amoeba[] newArray(int size) {
      return new AutoValue_Amoeba[size];
    }
  };
If the generateCreator method was changed as follows:-
FieldSpec generateCreator(ProcessingEnvironment env, TypeName autoValueType, List<Property> properties, TypeName type, Map<TypeMirror, FieldSpec> typeAdapters) {
        ClassName creator = ClassName.bestGuess("android.os.Parcelable.Creator");
        TypeName creatorOfClass = ParameterizedTypeName.get(creator, autoValueType);  // CHANGE MADE HERE!!! swap type with autoValueType
        ...
        ...
This method would then generate a Parcelable CREATOR that resembles this
public static final Parcelable.Creator<Amoeba> CREATOR = new Parcelable.Creator<Amoeba>() {
    @Override
    public AutoValue_Amoeba createFromParcel(Parcel in) {
      return new AutoValue_Amoeba(
          in.readString()
      );
    }
    @Override
    public AutoValue_Amoeba[] newArray(int size) {
      return new AutoValue_Amoeba[size];
    }
  };
This CREATOR now allows a TypeAdapter to employ the CREATOR as shown here
class AmoebaTypeAdapter implements TypeAdapter<Set<Amoeba>> {
    @Override
    public Set<Amoeba> fromParcel(Parcel in) {
        final List<Amoeba> arrayList = new ArrayList<>();
        in.readTypedList(arrayList, AutoValue_Amoeba.CREATOR);
        return new TreeSet<>(arrayList);
    }
    @Override
    public void toParcel(Set<Amoeba> value, Parcel dest) {
        final ArrayList<Amoeba> arrayList = new ArrayList<>(value);
        dest.writeTypedList(arrayList);
    }
}
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