2016-08-22 145 views
0

我使用的XML API返回的用戶,客戶,物品清單等:Retrofit2:錯誤處理

<userlist access="ro"> 
<multipage> 
<!-- Info about nums of pages, elements per page etc. --> 
</multipage> 
<user access="ro"> 
<surname access="rw" type="string">Jon</surname> 
<lastname access="rw" type="string">Doe</lastname> 
<scannerpin access="ro" type="int">1234</scannerpin> 
</user> 
<user> 
<!-- ... --> 
</user> 
</userlist> 

目前,我的POJO看起來是這樣的:

@Root(name="userlist") 
public class User extends XmlObject { 
    @Element 
    private XmlElement surname; 

    @Element 
    private XmlElement lastname; 

    @Element 
    private XmlElement scannerpin; 
} 

@Root(strict=false) 
/* XXX no support for generics in SimpleXML. TODO Find better solution */ 
public class XmlUserList extends XmlList<User> { 

    /** 
    * Constructor for XmlUserList 
    * 
    * @param multipage 
    */ 
    public XmlUserList(@Element(name = "multipage") Multipage multipage) { 
     super(multipage); 
    } 
} 

public class XmlElement extends XmlNode { 
    protected static final String rcsid = "$Id: XmlElement.java 29660 2016-08-17 15:08:39Z jb $"; 

    /** 
    * The element's value 
    */ 
    @Text(required=false) 
    String value; 

    /** 
    * Default constructor for XmlElement 
    */ 
    public XmlElement() { 
    } 

    /** 
    * Getter for value 
    * @return this.value 
    */ 
    public String getValue() { 
     return this.value != null ? this.value : ""; 
    } 

    /** 
    * Setter for value 
    * @param value The new value 
    * @throws UnsupportedOperationException Iff this element is readOnly 
    */ 
    public void setValue(String value) throws UnsupportedOperationException { 
      this.value = value; 
    } 

    public void setValue(Integer value) { 
     this.value = String.valueOf(value); 
    } 
} 


public abstract class XmlList<T> extends XmlNode { 
    protected static final String rcsid = "$Id: XmlList.java 29660 2016-08-17 15:08:39Z jb $"; 

    /** 
    * List entries 
    */ 
    @ElementListUnion({ 
      @ElementList(inline = true, name = "user", type = User.class,required=false), 
      @ElementList(inline = true, name = "customer", type = Customer.class,required=false), 
      @ElementList(inline = true, name = "article", type = Article.class,required=false) 
    }) 
    private List<T> list; 

    /** 
    * Multipage object 
    */ 
    private Multipage multipage; 

    /** 
    * Constructor for XmlList 
    */ 
    public XmlList(@Element(name="multipage") Multipage multipage) { 
     this.multipage = multipage; 
    } 

    /** 
    * getter for list 
    * @return this.list 
    */ 
    public List<T> getList() { 
     return (this.list); 
    } 

    public void setList(List<T> list) { 
     this.list = list; 
    } 

    /** 
    * Getter for Multipage 
    * @return this.multipage 
    */ 
    @Element(name="multipage") 
    public Multipage getMultipage() { 
     return (this.multipage); 
    } 
} 

在錯誤(例如錯誤的登錄,停機時間),後端不返回一個列表,但一個錯誤消息,併發送HTTP 200,安韋:

<error> 
<message>Not logged in</message> 
<softver>2.4.0_231445</softver> 
</error> 

我想知道如何在這裏發現錯誤。我可以將可選字段message添加到XmlObject,但這意味着我必須使用required=false註釋每個字段,以防止出現錯誤時的異常。我嘗試了這種方法,但由於依賴混亂(例如,每個列表必須有一個多頁成員)而回滾。我可以在@Commit方法中檢查這一點,但有幾個約束我想強制執行,最好使用SimpleXML註釋。

如何在SimpleSML轉換器中處理Retrofit2中的後端錯誤?

+0

http://stackoverflow.com/questions/38336599/retrofit-get-reponse-if-response-issucessful/38337087#38337087 –

+0

在我的情況下,無論錯誤是由後臺提出反序列化失敗。而且,後端總是返回HTTP 200,即使出錯,所以''response.isSuccessful()''不起作用。 – Jeremy

回答

0

我找到了解決方案。問題是後端返回HTTP/1.1 200 OK錯誤。我編寫了一個攔截器,用於檢查響應是否可以解析爲ApiError對象,如果是,則將響應的HTTP狀態代碼覆蓋爲HTTP/1.1 400 Bad Request

final class ErrorInterceptor implements Interceptor { 

    @Override 
    public Response intercept(Chain chain) throws IOException { 
     Response originalResponse = chain.proceed(chain.request()); 
     Response.Builder responseBuilder = originalResponse.newBuilder(); 

     /* 
     * get body from response. caution! .string() cannot be called more 
     * than once, so a new response is built with the old response's body 
     */ 
     String bodyString = originalResponse.body().string(); 

     // if response is an error: override response code to 400 
     if (isError(bodyString)) { 
      responseBuilder.code(400); 
     } 

     // clone response into new one 
     responseBuilder.body(
      ResponseBody.create(originalResponse.body().contentType(),   
           bodyString)); 

     return responseBuilder.build(); 
    } 

    public boolean isError(String body) { 
     Serializer ser = new Persister(); 

     try { 
      return ser.validate(ErrorUtils.ApiError.class, body); 
      // ser.validate() will throw if body can't be read into ApiError.class 
     } catch (Exception e) { 
      return false; 
     } 
    } 
} 

@Root(name="error") 
public class ApiError { 

    @Element 
    private String message; 

    @Element 
    private String softver; 

    public ApiError(@Element(name="message") String message, @Element(name="softver") String softver) { 
     this.message = message; 
     this.softver = softver; 
    } 

    public String getMessage() { 
     return message; 
    } 

    public String getSoftver() { 
     return softver; 
    } 
}