Reputation: 1238
We are working on an Android project with an XML API, using RxJava
, Retrofit
and SimpleXML
to handle requests and responses. The root of the responses can vary beteween two types:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<Element1>Integer</Element1>
<Element2>Integer</Element2>
...
</response>
or
<?xml version="1.0" encoding="UTF-8"?>
<error>
<Element1>String</Element1>
<Element2>Integer</Element2>
</error>
Therefore we use an XMLPullParse to parse the different kinds of responses to different models with their accompanying elements, which works fine.
MyResponse: The super class, which combines possible errors
and valid
responses:
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: Example for a response
class which extends MyResponse
public class SessionTokenResponse extends MyResponse<SessionTokenResponseData>{
public SessionTokenResponse(MyError mError, SessionTokenResponseData response) {
super(mError, response);
}
}
SessionTokenResponseData: An example class showing how we build the model
@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(): A method in our RestClient class to parse different kinds of responses. If it was successful, then the response will have <response>
as root element, if not the root element will be of type <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));
}
But we have problems with one type of response, which looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<response>
OK
</response>
Our question would be: How can we build a model for this kind of response if it has no elements? We still need to be able to differentiate between other responses with a <response>
root.
Upvotes: 2
Views: 925
Reputation: 1238
After a spontaneous idea, we found the answer by ourselves. The response will extend the super class and will not contain any additional model class like my example class SessionTokenResponseData, but only a String:
public class LoginResponse extends MyResponse<String>{
public LoginResponse(MyError mError, String response) {
super(mError, response);
}
}
So we don't need to modify our manual parsing in the RestClient class method and it works fine.
Upvotes: 1