Retrofit: Illegal Argument Exception - @Field parameters can only be used with form encoding

Created on 18 Dec 2014  ·  10Comments  ·  Source: square/retrofit

Hello again. So i created this interface

public interface ApiRestCalls {

    @POST("/read_all_users")
    void readAllUsersByName(
            @Field("name__regex") String user_name,
            Callback<ArrayList<UsersRead>> cb
    );

    @POST("/read_all_users")
    void readAllUsersByRegistration
            @Field("registration__regex") int user_registration,
            Callback<ArrayList<UsersRead>> cb
    );
}

and using them on a onEditorAction

editTextSearchValue.setOnEditorActionListener(
                new TextView.OnEditorActionListener() {
                    @Override
                    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                        if( actionId == EditorInfo.IME_ACTION_GO ){
                            debug.echo("Starting before-search statements");

                            String searchValue = v.getText().toString();
                            debug.echo("searching value -> " + searchValue );

                            if(!searchValue.equals("")) {

                                if( utils.isInteger(searchValue) ){// Searching by registration

                                    RestServiceFactory.create()
                                            .readAllUsersByRegistration(
                                                    Integer.parseInt(searchValue),
                                                    new Callback<ArrayList<UsersRead>>() {
                                                        @Override
                                                        public void success(ArrayList<UsersRead> usersReads, Response response) {
                                                            debug.echo("RestAPI have found "+usersReads.size()+" appearances <3");
                                                        }

                                                        @Override
                                                        public void failure(RetrofitError retrofitError) {

                                                        }
                                                    }
                                            );

                                }else{// Searching by name

                                    RestServiceFactory.create()
                                            .readAllUsersByName(
                                                    searchValue.trim(),
                                                    new Callback<ArrayList<UsersRead>>() {
                                                        @Override
                                                        public void success(ArrayList<UsersRead> usersReads, Response response) {
                                                            debug.echo("RestAPI have found "+usersReads.size()+" appearances <3");
                                                        }

                                                        @Override
                                                        public void failure(RetrofitError retrofitError) {

                                                        }
                                                    }
                                            );

                                }

                            }


                        }

                        return false;
                    }
                }
        );

when the code reaches the api call it raises the exceptio:

19374-19401/vyscond.infosae D/Retrofit﹕ ---- ERROR
12-18 10:35:41.462  19374-19401/vyscond.infosae D/Retrofit﹕ java.lang.IllegalArgumentException: InfosaeRestCalls.readAllUsersByName: @Field parameters can only be used with form encoding. (parameter #1)
            at retrofit.RestMethodInfo.methodError(RestMethodInfo.java:107)
            at retrofit.RestMethodInfo.parameterError(RestMethodInfo.java:111)
            at retrofit.RestMethodInfo.parseParameters(RestMethodInfo.java:356)
            at retrofit.RestMethodInfo.init(RestMethodInfo.java:118)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:294)
            at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
            at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
            at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at retrofit.Platform$Android$2$1.run(Platform.java:142)
            at java.lang.Thread.run(Thread.java:841)
12-18 10:35:41.462  19374-19401/vyscond.myproject D/Retrofit﹕ ---- END ERROR

What i want do achieve is send a json request like this:

  • readAllUsersByName
{ "name__regex" : "john doe" }
  • readAllUsersByRegistration
{ "registration__regex" : 12830918 }

So what's the mistake? I'm really lost here .-.

Most helpful comment

Should add @FormUrlEncoded

All 10 comments

As per @Field's docs:

Named pair for a form-encoded request.

And the exception:

@Field parameters can only be used with form encoding.

You want JSON yet your are instructing Retrofit to use form URL-encoding.

If you want to send JSON you can either use a Map<String, Object> which is gross but flexible, or define a Java object like this:

public class ReadUsersBody {
  public final String name__regex;

  public ReadUsersBody(String nameRegex) {
    name__regex = nameRegex;
  }
}

Then you can specify that as a @Body parameter on the service interface method.

I see. Thanks again for the answer! But i think that would be useful if we could be able to build JSON requests with the flexibility of @Field because, like in my case, i'm building the back-end to be based only on JSON response/request and some response are just that simple like that. Which brings me the ideia of writing an entire full class something very expensive in terms of maintaining code.

The serialization part of Retrofit is agnostic. Not all serialization formats are key=value or allow being built up incrementally (see: text, protocol buffers).

We have exactly the same issue! It would be very nice if we could intercept the request while being created and specify how we want the parameters to be handled. Maybe for V2?

Quite sure you can do this implementing a custom deserialization.

Should add @FormUrlEncoded

@FormUrlEncoded not works for GET type only for POST

@FormUrlEncoded also works for PUT.

add @FormUrlEncoded above the method,then clean your project and retry

public interface API_Interface {
@POST("/register_customer")
Call register(@Field("phone")String phone,@Field("pwd")String pwd);
}
private void initNet() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
API_Interface apiInterface = retrofit.create(API_Interface.class);
Call registerCall = apiInterface.register(mPhone,pwd);
registerCall.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
Log.e(TAG,response.body().toString());
}

        @Override
        public void onFailure(Call<String> call, Throwable t) {

        }
    });
}

Caused by: java.lang.IllegalArgumentException: @Field parameters can only be used with form encoding. (parameter #1)
for method API_Interface.register
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:751)
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:742)
at retrofit2.ServiceMethod$Builder.parameterError(ServiceMethod.java:760)
at retrofit2.ServiceMethod$Builder.parseParameterAnnotation(ServiceMethod.java:532)
at retrofit2.ServiceMethod$Builder.parseParameter(ServiceMethod.java:335)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:203)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:169)
at retrofit2.Retrofit$1.invoke(Retrofit.java:146)
at java.lang.reflect.Proxy.invoke(Proxy.java:393)
at $Proxy0.register(Unknown Source)
at cn.sxh.logisticsdemo.MainActivity.initNet(MainActivity.java:62)

Was this page helpful?
0 / 5 - 0 ratings