Upgrade Retrofit 1.X to 2
I guess most of people alreay read the post Retrofit 2 — Upgrade Guide from 1.9, me too. It listed some points for upgrading. If you used Retrofit 1.x in production, you might get more problem than the guide in upgrading, at least I did. Just make a memo here for myself and other poor guy.
I had problems such as
- Primitive String was wrapped by double quotes
- Upload multipart-form by using RequestBody doesn’t work
Weeks ago Twitter SDK upgraded to v2.0 and its Retrofit dependency also migrate to 2.0. Congratulations! Since we are geek, using latest version is kind of curse in our gene, of course we want to use it.
Double quotes for primitive string
Reference: #1210 2.0-beta2 adding extra quotes to multipart string form values - a stackoverflow-liked issue
We usually define an API call interface like this
1 | // use Part annotation |
if we call postSomething(“hello”)
, we expect the post body should be
1 | title=hello |
Actually it will be
1 | title="hello" |
As the issue tracker mentioned, it due to the Gson converter regards the value as JSON object and convert it to String. Interesting thing is, sigod mentioned(#763) this int primitive is a valid JSON
1 | 244 |
Early versions of JSON (such as specified by RFC 4627) required that a valid JSON “document” must consist of only an object or an array type—though they could contain other types within them. This restriction was removed starting with RFC 7158, so that a JSON document may consist entirely of any possible JSON typed value.
No wonder Gson will regards the String primitive as a JSON. My way to deal with it is to create a ConverterFactory for String.
1 | public class PrimitiveStringConverterFactory extends Converter.Factory { |
I would like to add a customized annotation for this Converter to distinguish should it convert the String or not, but Retrofit only accepts its annotations so I quit.
Upload images by multipart form
Reference: #1063 How to Upload a File using Retrofit 2.0
One of the most change from Retrofit 2 is no more TypedFile (OkHttp3 drop it), instead to use RequestBody. It is not too hard to replace TypedFile by RequestBody by ‘program’.
1 | Observable<MyResponse> doPost( |
But I met a problem in run-time. As each comments mentioned in that issue, it seems the RequestBody doesn’t work in Multipart-form uploading.
After reading the thread and give some try, this code works for me. I use MultipartBody.Part instead.
1 | Observable<MyResponse> doPost( |
I am curious about the difference between two implementation. Use okhttp logger to inspect request body.
1 | # Use Map |
the field filename
is the only one obvious difference I found.(of course as well as content-type). Probably, probably our server side implementation is too strict that regards filename
as necessary field.
I tried read RFC 2388 and RFC 1867, it said
File inputs may also identify the file name. The file name may be
described using the ‘filename’ parameter of the “content-disposition”
header. This is not required, but is strongly recommended in any case
where the original filename is known. This is useful or necessary in
many applications.
I think it is not necessary field. But maybe I am wrong in some place. Just keep studying.