Android 为未知根元素改型和SimpleXML?
我们目前正在为一个XML API进行改造,不幸的是,每个请求都会返回一个带有两个不同根元素之一的响应 通常,每个响应都是这样的(当然,Android 为未知根元素改型和SimpleXML?,android,xml,retrofit,simple-framework,Android,Xml,Retrofit,Simple Framework,我们目前正在为一个XML API进行改造,不幸的是,每个请求都会返回一个带有两个不同根元素之一的响应 通常,每个响应都是这样的(当然,标记中包含的实际元素随每个请求的不同而不同): 到目前为止,我们找到的以某种通用方式完成这项工作的唯一方法是: 公共接口Api{ @获取(“/api/sessionToken”) 可观察请求SessionToken(); @获取(“/api/pinStatus”) 可观察的状态(); } 公共类RestClient{ 公共RestClient(){ // ...
标记中包含的实际元素随每个请求的不同而不同):
到目前为止,我们找到的以某种通用方式完成这项工作的唯一方法是:
公共接口Api{
@获取(“/api/sessionToken”)
可观察请求SessionToken();
@获取(“/api/pinStatus”)
可观察的状态();
}
公共类RestClient{
公共RestClient(){
// ...
mApiService=reformation.create(Api.class);
}
公共可观察请求状态(){
返回mApiService.requestPinStatus()
.flatMap(foo(PinStatusResponse.class,PinStatusResponseData.class));
}
公共可观察请求SessionToken(){
返回mApiService.requestSessionToken()
.flatMap(foo(SessionTokenResponse.class,SessionTokenResponseData.class));
}
专用最终功能1 foo(最终类外部循环,最终类内部循环){
返回新的Func1(){
@凌驾
公共可观察呼叫(应答器应答器应答器){
试一试{
最后一个字符串xmlString=responseBody.String();
final XmlPullParser parser=Xml.newPullParser();
setFeature(XmlPullParser.FEATURE_进程_名称空间,false);
setInput(新的ByteArrayInputStream(xmlString.getBytes(Charset.forName(“UTF-8”)),null);
parser.nextTag();
最后一个字符串rootTag=parser.getName();
final Serializer Serializer=new Persister();
if(TextUtils.equals(rootTag,“error”)){
final MyError MyError=serializer.read(MyError.class,xmlString);
返回Observable.just((O)outerCls.getConstructor(MyError.class,innerCls.newInstance(MyError,null));
}else if(TextUtils.equals(rootTag,“response”)){
final I data=serializer.read(innerCls,xmlString);
返回Observable.just((T)outerCls.getConstructor(MyError.class,innerCls.newInstance(null,data));
}
}catch(XMLPullParseRexE){
返回可观测误差(e);
}捕获(IOE异常){
返回可观测误差(e);
}捕获(例外e){
返回可观测误差(e);
}
返回可观察的错误(新异常(“不应到达…”);
}
};
}
}
其中响应类如下所示:
公共抽象类MyResponse{
公共最终MyError错误;
公开最终数据;
受保护的MyResponse(MyError错误,T数据){
this.error=错误;
这个数据=数据;
}
}
以及:
公共最终类PinStatusResponse扩展了MyResponse{
公共PinStatusResponse(MyError错误,PinStatusResponseData数据){
超级(错误、数据);
}
}
所有的*数据类直接对应于(无错误)XML响应
现在,我的问题是:真的没有更简单的方法来解决这个问题吗?(如果是的话,这是一个糟糕的API设计的标志吗?这就是@ElementUnion
注释的目的。您可能可以使用纯改型+SimpleXML API,通过使用这样的注释对象来解决这个问题:
@Root
public class ResponseBody {
public interface IApiResponse {
}
@Root
public static class ValidResponse implements IApiResponse {
@Element(name="SomeInfo") String someInfo;
@Element(name="MoreInfo") String moreInfo;
}
@Root
public static class ErrorResponse implements IApiResponse {
@Element(name="code") int code;
@Element(name="message") String message;
}
@ElementUnion({
@Element(name="response", type=ValidResponse.class),
@Element(name="error", type=ErrorResponse.class)
})
IApiResponse apiResponse;
}
>“有效响应”和“错误响应”的具体结构必须根据实际的XML结构进行更改。您可能还希望考虑在<代码> @根 < < /P>中添加<代码>“严格= false”/代码>。
至于您的“Api”接口,则必须如下所示(请注意,我已经介绍了改型的调用类的用法):
公共接口Api{
@获取(“/api/sessionToken”)
调用requestSessionToken();
@获取(“/api/pinStatus”)
调用requestPinStatus();
}
最后,调用本身(例如requestPinStatus())应根据以下框架实现进行计算:
Call<ResponseBody> result = mApiService.requestPinStatus();
result.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
// ...
if (response.body().apiResponse instanceof ValidResponse) {
// ...
} else if (response.body().apiResponse instanceof ErrorResponse) {
// ...
}
}
@Override
public void onFailure(Throwable t) {
// ...
}
});
callresult=mApiService.requestPinStatus();
result.enqueue(新回调(){
@凌驾
公共响应(响应、改装){
// ...
if(response.body().apiResponse instanceof ValidResponse){
// ...
}else if(response.body().apirresponse instanceof ErrorResponse){
// ...
}
}
@凌驾
失效时的公共无效(可丢弃的t){
// ...
}
});
有关ElementUnion
和简单XML注释的更多信息,请参阅。好的,谢谢-我会尝试一下,然后在这里报告!
@Root
public class ResponseBody {
public interface IApiResponse {
}
@Root
public static class ValidResponse implements IApiResponse {
@Element(name="SomeInfo") String someInfo;
@Element(name="MoreInfo") String moreInfo;
}
@Root
public static class ErrorResponse implements IApiResponse {
@Element(name="code") int code;
@Element(name="message") String message;
}
@ElementUnion({
@Element(name="response", type=ValidResponse.class),
@Element(name="error", type=ErrorResponse.class)
})
IApiResponse apiResponse;
}
public interface Api {
@GET("/api/sessionToken")
Call<ResponseBody> requestSessionToken();
@GET("/api/pinStatus")
Call<ResponseBody> requestPinStatus();
}
Call<ResponseBody> result = mApiService.requestPinStatus();
result.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
// ...
if (response.body().apiResponse instanceof ValidResponse) {
// ...
} else if (response.body().apiResponse instanceof ErrorResponse) {
// ...
}
}
@Override
public void onFailure(Throwable t) {
// ...
}
});