I have a server response in xml, that is not well formatted and have no root element:
<option value="stationAValue">stationADescription</option>
<option value="stationBValue">stationBDescription</option>
I trying to use SimpleXmlConverterFactory
like this:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Params.BASE_URL)
.client(okHttpClient)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
This is my class that represents a row:
public class Station {
@Element(name = "option")
private String mName;
@Attribute(required = false)
private String value;
}
But of course it can't be parsed without a root element,
Is there a way to manipulate the response before the SimpleXmlConverterFactory
is trying to parse it, and add a root element?
Or maybe another solution?
With Retrofit / OkHttp you have 2 options for intercepting those requests:
Both is somewhat a decorator pattern.
Modify the response as part of the http stack directly:
public class XmlInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
ResponseBody body = response.body();
String wrappedBody = "<root>" + body.string() + "</root>";
return response.newBuilder()
.body(ResponseBody.create(body.contentType(), wrappedBody))
.build();
}
}
And just add the interceptor to OkHttp
new OkHttpClient.Builder()
.addInterceptor(new XmlInterceptor())
.build();
Wrap the parser you want to use and again just modify the response. The nice thing here is, you could add a custom annotation for your wrapping. e.g. to pass in the name of the root element.
public class XmlParser extends Converter.Factory {
private Converter.Factory factory = SimpleXmlConverterFactory.create();
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
// here you can actually look at the annotations, type, etc.
return new WrappedResponseBodyConverter(factory.responseBodyConverter(type, annotations, retrofit));
}
private class WrappedResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private Converter<ResponseBody, T> responseBodyConverter;
public WrappedResponseBodyConverter(Converter<ResponseBody, T> responseBodyConverter) {
this.responseBodyConverter = responseBodyConverter;
}
@Override
public T convert(ResponseBody value) throws IOException {
String body = "<root>" + value.string() + "</root>";
ResponseBody wrapped = ResponseBody.create(value.contentType(), body);
return responseBodyConverter.convert(value);
}
}
}
And use this one instead.
new Retrofit.Builder()
.addConverterFactory(new XmlParser())
.build();
Choose whichever you prefer, as there is no right or wrong imho.
The code is not tested. It's just an example.