Reputation: 1075
I have this base abstract class that looks like this.
public abstract class Species implements Parcelable {
public Species() {
}
public abstract String name();
}
And then my Human class looks like this.
@AutoValue
public abstract class Human extends Species implements Parcelable {
public static Human create(String humanVariable) {
return new AutoValue_Human(humanVariable);
}
public static Human create(String name, String humanVariable) {
return new AutoValue_Human(name, humanVariable);
}
public static TypeAdapter<Human> typeAdapter(Gson gson) {
return new AutoValue_Human.GsonTypeAdapter(gson);
}
@SerializedName("name")
public abstract String name();
@Nullable
@SerializedName("human_variable")
public abstract String humanVariable();
}
E/com.service.androidbrain.util.networking.RetrofitCallback.onFailure: Failed to invoke public com.service.example.models.Species() with no args
For some reason however I'm getting this error and I don't understand what is going on, any idea?
Upvotes: 1
Views: 2201
Reputation: 1
I solved this problem by removing from my class the word abstract
Ej Before
public abstract class Post {
private int userId;
private int id;
private String title;
}
after
public class Post {
private int userId;
private int id;
private String title;
}
Upvotes: -1
Reputation: 21105
I'm sure you just don't have the GsonConverterFactory
instantiated correctly. From my answer to your previous question:
@GsonTypeAdapterFactory
abstract class HumanAdapterFactory
implements TypeAdapterFactory {
public static TypeAdapterFactory create() {
return new AutoValueGson_HumanAdapterFactory();
}
}
Therefore the following is unnecessary:
public static TypeAdapter<Human> typeAdapter(Gson gson) {
return new AutoValue_Human.GsonTypeAdapter(gson);
}
So you just have to instantiate Gson
:
new GsonBuilder()
...
.registerTypeAdapterFactory(HumanAdapterFactory.create())
.create();
And configure the Retrofit instance like this:
new Retrofit.Builder()
...
.addConverterFactory(GsonConverterFactory.create(gson)) // THIS is necessary
.build();
And make sure your service interface operates on Human
, not Species
:
interface IService {
@GET("/") // This is probably what you really want
Call<Human> getHuman();
@GET("/") // How can you know WHAT the Species is here?
Call<Species> getSpecies();
}
If you really want to go with getSpecies()
, you MUST know what is the real type of the Species
interface for a particular object: so you either have to use InstanceCreator
or detect the real type on some information. Both of the approaches are described in my answer. In order to make it work:
final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(HumanAdapterFactory.create())
.registerTypeAdapterFactory(new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// ... that big type adapter here from that answer OR InstanceCreator by it's not useful here
}
})
.create();
final Retrofit retrofit = new Retrofit.Builder()
...
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
final IService service = retrofit.create(IService.class);
final Species species = service.getSpecies()
.execute()
.body();
System.out.println(species.getClass());
System.out.println(species.name());
That's all you need, but Call<Human> getHuman();
is the best choice here.
Upvotes: 2
Reputation: 39843
auto-value-gson
doesn't support the behavior you're trying to achieve.
I assume you declared your retrofit service to return Call<Species>
, while only Human.typeAdapter(Gson)
is registered to Gson. This concludes in Gson not knowing of how to acutally create an instance of Species
.
To make this work, you'd have to (create and) install another type adapter for Species
which knows how to identify the actual subtype of the species and delegates all model creation to the specific type adapter.
Upvotes: 2
Reputation: 62189
You should prefer composition over inheritance, because at least currently it is not available to do that in AutoValue
.
See this issue at github.
Upvotes: 0