Went to upgrade to Retrofit 2.0 and running into this weird problem.
I have a method to log a user in
public interface ApiInterface { @Multipart @POST("user/login/") Call<SessionToken> userLogin(@Part("username") String username, @Part("password") String password); }
When I look at the key value POST params on the server side they print like this
username : "brian" password : "password"
The same method using retrofit 1.9 the K:V pairs look like
username : brian password : password
It's adding literal quotes to the POST variables
If I use any other rest client the variables print like the second way without the quotes.
Here is how I build the Retrofit instance with an interceptor
OkHttpClient client = new OkHttpClient(); client.interceptors().add(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request original = chain.request(); // Customize the request Request request = original.newBuilder() .header("Accept", "application/json") .header("Authorization", myPrefs.accessToken().getOr("")) .method(original.method(), original.body()) .build(); Response response = chain.proceed(request); // Customize or return the response return response; } }); Ok2Curl.set(client); Retrofit retrofit = new Retrofit.Builder() .baseUrl(apiEndpoint) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build();
I imagine i'm doing something wrong with the converter but not sure what.
Has anyone else ran into this problem yet? I know its in beta but it's pretty widly used.
A multipart message is made up of several parts. One part consists of a header and a body. The body can be any type of media and can contain text or binary data. A multipart media type can be included in a part. Retrofit supports requests that are in parts.
A double-quoted string can have single quotes without escaping them, conversely, a single-quoted string can have double quotes within it without having to escape them. Double quotes ( \" ) must escape a double quote and vice versa single quotes ( \' ) must escape a single quote.
I have the same problem, and how it solved:
1) Add to build.gradle:
compile 'com.squareup.retrofit2:converter-scalars:2.1.0' // Remember to add the same version
2) Add one line here:
Retrofit retrofit = new Retrofit.Builder() .baseUrl(URL_BASE) .addConverterFactory(ScalarsConverterFactory.create()) // this line .addConverterFactory(GsonConverterFactory.create(gson)) .client(getUnsafeOkHttpClient()) .build();
This is because it's running through the JSON converter.
Solution1: use RequestBody
instead of String
public interface ApiInterface { @Multipart @POST("user/login/") Call<SessionToken> userLogin(@Part("username") RequestBody username, @Part("password") RequestBody password); }
Build RequestBody:
RequestBody usernameBody = RequestBody.create(MediaType.parse("text/plain"), usernameStr); RequestBody passwordBody = RequestBody.create(MediaType.parse("text/plain"), passwordStr);
Launch network operation:
retrofit.create(ApiInterface.class).userLogin(usernameBody , passwordBody).enqueue()....
Solution2: Create a custom ConverterFactory to dispose String part value.
For: Retrofit2 final release not beta. (com.squareup.retrofit2:retrofit:2.0.0)
Create your StringConverterFactory:
public class StringConverterFactory extends Converter.Factory { private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain"); public static StringConverterFactory create() { return new StringConverterFactory(); } @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { if (String.class.equals(type)) { return new Converter<ResponseBody, String>() { @Override public String convert(ResponseBody value) throws IOException { return value.string(); } }; } return null; } @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { if(String.class.equals(type)) { return new Converter<String, RequestBody>() { @Override public RequestBody convert(String value) throws IOException { return RequestBody.create(MEDIA_TYPE, value); } }; } return null; } }
Add to your retrofit instance:
retrofit = new Retrofit.Builder() .baseUrl(SERVER_URL) .client(client) .addConverterFactory(StringConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();
Attention: StringConverterFactory
should add before GsonConverterFactory
!
then you can use String
as part value directly.
You can find more information about this issue in https://github.com/square/retrofit/issues/1210
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With