java - Gson + AutoValue error while trying to implement own deserializer -
i have retrofit interface combine rxjava. retrofit calls return observable. "somepojo" classes, generate them online using schema2pojo sites.
i have problem when making following api call: https://developers.themoviedb.org/3/search/2y9y2lrefzdhfhbfa
as can see, array 2 different types of objects, called "media" , "credit". these 2 classes generated using google's autovalue follows:
@autovalue public abstract class media implements parcelable { @serializedname(value = "title", alternate = {"name"}) public abstract string title(); @nullable @serializedname("vote_average") public abstract string voteaverage(); @nullable @serializedname("backdrop_path") public abstract string backdroppath(); @nullable public abstract string adult(); public abstract string id(); @nullable public abstract string overview(); @nullable @serializedname("original_language") public abstract string originallanguage(); @nullable @serializedname("genre_ids") public abstract list<string> genreids(); @nullable @serializedname(value = "release_date", alternate = {"first_air_date"}) public abstract string releasedate(); @nullable @serializedname(value = "original_title", alternate = {"original_name"}) public abstract string originaltitle(); @nullable @serializedname("vote_count") public abstract string votecount(); @nullable @serializedname("poster_path") public abstract string posterpath(); @nullable public abstract string video(); @nullable @serializedname("media_type") public abstract string mediatype(); @nullable public abstract string popularity(); @nullable @serializedname("origin_country") public abstract list<string> originalcountry(); public static media create(string title, string voteaverage, string backdroppath, string adult, string id, string overview, string originallanguage, list<string> genreids, string releasedate, string originaltitle, string votecount, string posterpath, string video, string mediatype, string popularity, list<string> originalcountry) { return new autovalue_media(title, voteaverage, backdroppath, adult, id, overview, originallanguage, genreids, releasedate, originaltitle, votecount, posterpath, video, mediatype, popularity, originalcountry); } public static typeadapter<media> typeadapter(gson gson) { return new autovalue_media.gsontypeadapter(gson); } }
and:
@autovalue public abstract class credit implements parcelable { public abstract string id(); @serializedname("credit_id") public abstract string creditid(); @nullable public abstract string department(); public abstract string name(); @nullable @serializedname(value = "job", alternate = {"character"}) public abstract string job(); @nullable @serializedname("profile_path") public abstract string profilepath(); @nullable public abstract string order(); @nullable @serializedname("cast_id") public abstract string castid(); public static credit create(string id, string creditid, string department, string name, string job, string profilepath, string order, string castid) { return new autovalue_credit(id, creditid, department, name, job, profilepath, order, castid); } public static typeadapter<credit> typeadapter(gson gson) { return new autovalue_credit.gsontypeadapter(gson); } }
to resolve problem created array 2 different kind of objects, made pojo return call implement own jsondeserializer:
public class medialistpojo { @serializedname("results") private list<media> movies; private list<credit> credits; private dates dates; private string page; private string total_pages; private string total_results; public list<media> getmedia() { return movies; } public void setmovies(list<media> movies) { this.movies = movies; } public list<credit> getcredits() {return credits;} public void setcredits(list<credit> credits) {this.credits = credits;} public dates getdates() { return dates; } public void setdates(dates dates) { this.dates = dates; } public string getpage() { return page; } public void setpage(string page) { this.page = page; } public string gettotal_pages() { return total_pages; } public void settotal_pages(string total_pages) { this.total_pages = total_pages; } public string gettotal_results() { return total_results; } public void settotal_results(string total_results) { this.total_results = total_results; } @override public string tostring() { return "medialistpojo{" + "movies=" + movies + ", credits=" + credits + ", dates=" + dates + ", page='" + page + '\'' + ", total_pages='" + total_pages + '\'' + ", total_results='" + total_results + '\'' + '}'; } public static class medialistpojodeserializer implements jsondeserializer<medialistpojo> { @override public medialistpojo deserialize(jsonelement json, type typeoft, jsondeserializationcontext context) throws jsonparseexception { medialistpojo medialistpojo = new gson().fromjson(json, medialistpojo.class); jsonobject jsonobject = json.getasjsonobject(); if (jsonobject.has("results")) { jsonarray jsonarray = jsonobject.getasjsonarray("results"); list<credit> credits = new arraylist<>(); credit credit; (jsonelement element : jsonarray) { jsonobject current = element.getasjsonobject(); if (current.get("media_type").getasstring().equals("person")) { credit = new gson().fromjson(current, credit.class); credits.add(credit); } } medialistpojo.setcredits(credits); } return medialistpojo; } } }
the main idea behind json deserializer is: "use default type adapter class , set credit objects using jsondeserializer"
however, reason, following error while deserializing:
java.lang.runtimeexception: failed invoke public media() no args ... caused by: java.lang.instantiationexception: can't instantiate abstract class media @ java.lang.reflect.constructor.newinstance(native method)
it shouldn't try instantiate abstract superclass, use autovalue's generated type adapter.
this how built retrofit instance:
class creator { public static movieservice newmovieservice() { gson gson = new gsonbuilder() .registertypeadapterfactory(new autovaluegson_myadapterfactory()) .registertypeadapter(medialistpojo.class, new medialistpojo.medialistpojodeserializer()) .setdateformat("yyyy-mm-dd't'hh:mm:ss.sss'z'") .create(); okhttpclient client = new okhttpclient.builder() .addinterceptor(networkutil.makequeryinterceptor("api_key", buildconfig.my_api_key)) .build(); retrofit retrofit = new retrofit.builder() .client(client) .baseurl(movieservice.endpoint) .addconverterfactory(gsonconverterfactory.create(gson)) .addcalladapterfactory(rxjavacalladapterfactory.create()) .build(); return retrofit.create(movieservice.class);
can me understand did wrong?
well, found solution 5 minutes after posting question, since think other people might struggle well. i'll share solution:
basically, inside of jsondeserializer, using new instance of gson object when, in fact, mistake.
the typeadapterfactory registered while creating retrofit instance of other typeadapters live.
therefore, calling
gson gson = new gson();
doesn't supply type adapters needed deserialize rest of object.
i hope helps.
Comments
Post a Comment