2017-02-12 64 views
1

我正在使用GSON和RxJava進行改造以執行網絡請求。我試圖找出如何獲得響應時,Gson庫無法轉換它。處理改造2 GSON轉換錯誤

這發生在服務器發生錯誤並且響應與Gson庫試圖將響應轉換爲的類不匹配時發生。

解決方法是在嘗試轉換它之前創建一個攔截器並緩存響應。但是這只是糟糕的編程,因爲一旦我們開始做併發請求,問題就變得難以管理。

服務定義如下:響應類只包含狀態碼和稱爲數據的泛型。

Retrofit getService() { 
    return new Retrofit.Builder() 
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .baseUrl(url) 
      .client(clientBuilder.build()) 
      .build(); 
} 
public Observable<Response<String>> userLogin(String username, String password) { 

    return getService().create(Account.class) 
      .login(username, password) 
      .subscribeOn(Schedulers.newThread()) 
      .observeOn(AndroidSchedulers.mainThread()); 
} 

別的地方在代碼中創建了一個請求

getService().userLogin(email, password) 
     .subscribeOn(Schedulers.newThread()) 
     .observeOn(AndroidSchedulers.mainThread()) 
     .subscribe(onSuccess(), onError()); 

protected Action1<Response<String>> onSuccess(){ 

    return new Action1<Response<String>>() { 
     @Override 
     public void call(Response<String> response) { 
      // Process the response 
     } 
    }; 
} 
protected Action1<Throwable> onError(){ 
    return new Action1<Throwable>() { 
     @Override 
     public void call(Throwable throwable) { 

      if (throwable instanceof HttpException) { 
       ResponseBody body = ((HttpException) throwable).response().errorBody(); 
       // Handle the error 
      } 
     } 
    }; 

當服務器返回字符串以外的東西出現問題。例如對象或數組。這裏GsonConverterFactory會拋出一個錯誤,這個錯誤會被onError方法捕獲。我想知道如何得到迴應。

返回的throwable類型爲JsonSyntaxException,可悲的是它不包含GSON庫試圖轉換的原始響應體。

回答

0

昨天我給一個類似的問題建議similar solution,但是你似乎需要稍微修改答案。答案還包含一些關於效率和內存消耗問題的評論。如果您想使用該解決方案,您可以創建一個能創建一個特殊的例外,拿着一些故障信息的特殊故障處理程序:

final class BadPayloadExceptionConversionThrowableConsumer 
     implements IConversionThrowableConsumer { 

    private static final int MAX_STREAM_BUFFER_LENGTH = 8 * 1024; 

    private static final IConversionThrowableConsumer badPayloadExceptionConversionThrowableConsumer = new BadPayloadExceptionConversionThrowableConsumer(); 

    private BadPayloadExceptionConversionThrowableConsumer() { 
    } 

    static IConversionThrowableConsumer getBadPayloadExceptionConversionThrowableConsumer() { 
     return badPayloadExceptionConversionThrowableConsumer; 
    } 

    @Override 
    public void accept(final MediaType contentType, final long contentLength, final InputStream inputStream, final Throwable ex) 
      throws IOException { 
     final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(MAX_STREAM_BUFFER_LENGTH); 
     copy(limit(inputStream, MAX_STREAM_BUFFER_LENGTH), byteArrayOutputStream); 
     final ByteArrayInputStream bufferedInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); 
     throw new BadPayloadException(ex, contentType, contentLength, bufferedInputStream); 
    } 

    static final class BadPayloadException 
      extends IOException { 

     private final MediaType contentType; 
     private final long contentLength; 
     private final InputStream inputStream; 

     private BadPayloadException(final Throwable cause, final MediaType contentType, final long contentLength, final InputStream inputStream) { 
      super(null, cause); 
      this.contentType = contentType; 
      this.contentLength = contentLength; 
      this.inputStream = inputStream; 
     } 

     MediaType getContentType() { 
      return contentType; 
     } 

     long getContentLength() { 
      return contentLength; 
     } 

     InputStream getInputStream() { 
      return inputStream; 
     } 

    } 

} 

而不用註銷,只拋出一個特殊的私有構造函數的異常,可能是instanceof版在呼叫現場。由於在相關問題中也被註釋的原因,輸入流必須被緩衝到一定的限制(特別是爲什麼原始的InputStream被委託而不是ResponseBody)。現在可以使用的方法:

service.getFooBar() 
     .subscribe(
       out::println, 
       t -> { 
        if (t instanceof BadPayloadException) { 
         try { 
          final BadPayloadException badPayloadException = (BadPayloadException) t; 
          err.println("Content type = " + badPayloadException.getContentType()); 
          err.println("Content length = " + badPayloadException.getContentLength()); 
          err.print("Content  = "); 
          copy(badPayloadException.getInputStream(), err); 
         } catch (final IOException ex) { 
          throw new RuntimeException(ex); 
         } 
        } else { 
         err.println(t.getClass()); 
        } 
       } 
     ); 

注意,copylimit方法是從谷歌番石榴ByteStreams靜態導入。 outerr分別是System.outSystem.err的靜態進口。

輸出示例:

Content type = application/json 
Content length = -1 
Content  = {#"foo":1,"bar":2}