2016-08-22 2 views
0

오류 처리 :Retrofit2 : 나는 등 사용자, 고객, 기사의 목록 및 반환하는 XML API를 사용하고

<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, anway 보냅니다

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

여기서 오류를 올바르게 잡는 방법에 대해 궁금합니다. XmlObject에 선택적 필드 message을 추가 할 수는 있지만 이것은 오류시 예외를 방지하기 위해 각각의 모든 필드에 required=false으로 주석을 추가해야한다는 것을 의미합니다. 이 방법을 시도했지만 종속성 혼란으로 인해 롤백되었습니다 (모든 목록에는 여러 페이지 구성원이 있어야합니다). @Commit 메서드에서이를 확인할 수 있지만, 시행을 원하는 몇 가지 제약이 있습니다. SimpleXML 주석을 사용하는 것이 더 바람직합니다.

SimpleXML 변환기를 사용하여 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; 
    } 
}