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