2016-09-22 38 views
1

我有一個Retrofit接口,我與RxJava結合。我所有的翻新電話都會返回Observable。那些「SomePojo」類,我使用Schema2Pojo網站在線生成它們。Gson + AutoValue錯誤,試圖實現自己的解串器

我做以下API調用時的一個問題: https://developers.themoviedb.org/3/search/2Y9y2LReFZdHFHbFA

正如你所看到的,這是兩種不同類型的對象的數組,我所謂的「媒體」和「信用」。

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

和:我生成使用谷歌的autovalue如下這兩個類

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

} 

要解決由陣列兩種不同類型的對象所產生的問題,我做了這個調用POJO回報實現自己的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; 
       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; 
     } 
    } 
} 

此JSON解串器背後的主要思想是:「使用默認類型的適配器這個類,然後設置信貸對象全光照克這種JsonDeserializer」

然而,出於某種原因,我得到以下錯誤,而反序列化:

了java.lang.RuntimeException:無法用無參數 ... 所致調用公共媒體(): java.lang.InstantiationException:不能實例化抽象類媒體 在java.lang.reflect.Constructor.newInstance(本地方法)

它不應嘗試實例化抽象超類,但使用AutoValue生成的類型適配器。

這是我建立了我的改裝實例:

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

你能幫助我理解我做錯了什麼?

回答

2

嗯,我在發佈問題後5分鐘找到了解決方案,但是因爲我認爲其他人也可能會爲此而苦惱。我將分享解決方案:

基本上,在我的JsonDeserializer中,我使用了一個Gson對象的新實例,實際上,這是一個錯誤。

我在創建改造實例時註冊的typeadapterfactory是所有其他TypeAdapter存在的地方。

因此,調用

Gson gson = new Gson(); 

不提供我需要反序列化對象的其餘類型的適配器。

我希望它有幫助。

+0

錯過了也......有時我們是馬虎不得。 – box

0

您需要在創建Gson實例時註冊TypeAdapterFactory。對我來說,我在下面的匕首2模塊中做過這個。

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

希望這有助於。