2016-09-22 2 views
1

Ich habe eine Retrofit-Schnittstelle, die ich mit RxJava kombinieren. Alle meine Retrofit-Anrufe kehren Observable zurück. Diese "SomePojo" -Klassen erzeuge ich online mithilfe von Schema2Pojo-Sites.Gson + AutoValue Fehler beim Versuch, eigene Deserializer zu implementieren

Ich habe ein Problem, wenn der folgenden api Anruf: https://developers.themoviedb.org/3/search/2Y9y2LReFZdHFHbFA

Wie Sie sehen, es ist ein Array mit zwei unterschiedlichen Typen von Objekten, die ich „Medien“ und „Credit“ genannt. Diese beiden Klassen I erzeugt mit Googles Autowert wie folgt:

@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); 
} 
} 

Und:

@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); 
} 

} 

das Problem durch die Anordnung mit zwei verschiedenen Arten von Objekten erstellt zu beheben, habe ich die POJO Rückkehr von diesem Aufruf seine eigenen JsonDeserializer implementieren:

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; 
       for (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; 
     } 
    } 
} 

die Grundidee hinter diesem json Deserializer ist: „für diese Klasse des Standardtyp Adapter verwenden und dann die Kredite Objekte festgelegt usin g dieses JsonDeserializer“

jedoch aus irgendeinem Grund bekomme ich folgende Fehler beim Deserialisieren:

java.lang.RuntimeException: Fehler mit den öffentlichen Medien() ohne args ... verursacht aufzurufen: java.lang.InstantiationException: Kann nicht abstrakte Klasse Medien bei java.lang.reflect.Constructor.newInstance (Mutter Methode)

instanziiert Es sollte nicht die abstrakte Superklasse zu instanziiert versuchen, aber der Autovalue generiert Typ Adapter verwenden. Diese

ist, wie ich meine Retrofit Instanz gebaut:

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); 

Können Sie mir helfen, zu verstehen, was ich falsch gemacht habe?

Antwort

2

Nun, ich fand die Lösung 5 Minuten nach dem Posten der Frage, aber da ich denke, andere Leute könnten damit auch kämpfen. Ich werde die Lösung teilen:

Grundsätzlich, innerhalb meines JsonDeserializer, ich habe eine neue Instanz eines Gson-Objekts verwendet, wenn dies tatsächlich ein Fehler ist.

Der Typadapterfactory, den ich beim Erstellen meiner Retrofit-Instanz registriert habe, ist der Ort, an dem alle anderen TypeAdapter leben.

Daher ruft

Gson gson = new Gson(); 

Hat die Art Adapter nicht liefern, dass ich den Rest des Objekts deserialisieren benötigt.

Ich hoffe es hilft.

+0

Verpasste auch ... manchmal sind wir schlampig. – box

0

Sie müssen Ihre TypeAdapterFactory wie beim Erstellen Ihrer Instanz von Gson registrieren. für mich habe ich das in meinem Dolch 2 Modul wie unten gemacht.

Gson gson = new GsonBuilder() 
      .registerTypeAdapterFactory(GsonAdapterFactory.create()) 
      .create(); 

hoffe das hilft.

Verwandte Themen