2015-12-10 1 views
2

Мы работаем над проектом Android с XML API, используя RxJava, Retrofit и SimpleXML для обработки запросов и ответов. Корень из ответов может варьироваться beteween двух типов:SimpleXML and Retrofit: модель для ответа только с корневым элементом

<?xml version="1.0" encoding="UTF-8"?> 
<response> 
<Element1>Integer</Element1> 
<Element2>Integer</Element2> 
... 
</response> 

или

<?xml version="1.0" encoding="UTF-8"?> 
<error> 
<Element1>String</Element1> 
<Element2>Integer</Element2> 
</error> 

Поэтому мы используем XMLPullParse для анализа различных видов ответов на различные модели с сопровождающими их элементами, который работает отлично.

MyResponse: супер класс, который сочетает в себе возможно errors и valid ответы:

public abstract class MyResponse<T> { 
    public final MyError error; 
    public final T data; 

    protected MyResponse(MyError mError, T data) { 
     this.error = mError; 
     this.data = data; 
    } 

    public final boolean isError() { 
     return error != null; 
    } 

    @Override 
    public String toString() { 
     return "MyResponse{" + 
       "error=" + error + 
       ", data=" + data + 
       '}'; 
    } 

    public T getData() { 
     return data; 
    } 
} 

SessionTokenResponse: Пример для response класса, который простирается MyResponse

public class SessionTokenResponse extends MyResponse<SessionTokenResponseData>{ 
    public SessionTokenResponse(MyError mError, SessionTokenResponseData response) { 
     super(mError, response); 
} 
} 

SessionTokenResponseData: Экземпляр ле класс, показывающий, как мы построить модель

@Root(name = "data") 
public class SessionTokenResponseData { 

    @Element(name = "Session") 
    private String sessionInfo; 

    @Element(name = "Token") 
    private String tokenInfo; 

    public String getSessionInfo() { 
     return sessionInfo; 
    } 
    .... 
} 

RestClient - Foo(): метод в нашем классе RestClient разобрать различные виды ответов. Если она была успешной, то ответ будет <response> как корневой элемент, если не корневой элемент будет иметь тип <error>

private final <T extends MyResponse, I> Func1<ResponseBody, Observable<T>> foo(final Class<T> cls, final Class<I> innerCls) { 
    return new Func1<ResponseBody, Observable<T>>() { 
     @Override 
     public Observable<T> call(ResponseBody responseBody) { 
      try { 

       final String xmlString = responseBody.string(); 

       final XmlPullParser parser = Xml.newPullParser(); 
       parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); 
       parser.setInput(new ByteArrayInputStream(xmlString.getBytes(Charset.forName("UTF-8"))), null); 
       parser.nextTag(); 

       final String rootTag = parser.getName(); 

       final Serializer serializer = new Persister(); 

       if (TextUtils.equals(rootTag, "error")) { 
        final MyError myError = serializer.read(MyError.class, xmlString); 
        return Observable.just((T) cls.getConstructor(MyError.class, innerCls).newInstance(myError, null)); 
       } else if (TextUtils.equals(rootTag, "response")) { 
        final I data = serializer.read(innerCls, xmlString); 
        return Observable.just((T) cls.getConstructor(HuiError.class, innerCls).newInstance(null, data)); 
       } 

Но у нас есть проблемы с одним типом ответа, который выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?> 
<response> 
OK 
</response> 

Наш вопрос: Как мы можем построить модель для такого ответа, если у нее нет элементов? Нам по-прежнему необходимо различать другие ответы с помощью корня <response>.

ответ

1

После спонтанной идеи мы нашли ответ сами. Отклик продлит супер класс и не будет содержать дополнительный класс модели, как мой пример класса SessionTokenResponseData, но только строка:

public class LoginResponse extends MyResponse<String>{ 
    public LoginResponse(MyError mError, String response) { 
     super(mError, response); 
    } 
} 

Таким образом, мы не должны изменить наш ручной разбор в RestClient класс, и он отлично работает.