1
votes

I am new to spring boot recently i am trying to do HTTP POST request from one android application through retrofit2 rest API library with application/x-www-form-url encoded but when i hit my spring boot POST service it shows me below error

"status":415,"error":"Unsupported Media Type","exception":"org.springframework.web.HttpMediaTypeNotSupportedException","message":"Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported","path":"/api/login"

enter image description here

Can anyone know how to solve it?

Here is my code Android Code example

ApiService.java

public interface ApiService {
    @FormUrlEncoded
    @POST("/api/login")
    Call<LoginData> postLogIn(
            @Field("username") String username,
            @Field("password") String password);
}

ApiHandler.java

    private static final String SERVER_URL = "http://192.168.0.12:8080/";
    private static final long CONNECTION_TIMEOUT = 30;
    public static Retrofit restAdapter;

    //public static final int CONNECTION_TIME_OUT = 120;
    private static Retrofit getRestAdapter() {
        if (restAdapter == null) {
            restAdapter = new Retrofit.Builder()
                    .baseUrl(SERVER_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(getClient()).build();
        }
        return restAdapter;
    }

    private static OkHttpClient getClient() {
        OkHttpClient.Builder okClientBuilder = new OkHttpClient.Builder();
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        okClientBuilder.addInterceptor(httpLoggingInterceptor);
        okClientBuilder.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS);
        okClientBuilder.readTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS);
        okClientBuilder.writeTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS);
        return okClientBuilder.build();
    }

PostHandler.java

@Override
    public void callAPI(final Context context, final ApiClientResponse callback, Object arg0) {
        this.callback = callback;
        apiService.postLogIn(Login.username, Login.password).enqueue(new Callback<LoginData>() {
            @Override
            public void onResponse(Call<LoginData> call, Response<LoginData> response) {
                if (response.isSuccessful()) {
                    LoginData loginData = response.body();
                    successLoginData = loginData;
                    successCallBack();
                } else {
                    ApiErrorHandler.handleError(context, response, errorResponse);
                }
            }

            @Override
            public void onFailure(Call<LoginData> call, Throwable t) {
                ApiErrorHandler.handleError(context, t, errorResponse);
            }

            RetrofitErrorResponse errorResponse = new RetrofitErrorResponse() {
                @Override
                public void errorMessage(String errorMessage) {
                    failureCallBack(errorMessage);
                }

                @Override
                public void tSyncError() {

                }

                @Override
                public void invalidTokenError() {

                }
            };

        });
    }

LoginData.java model class

@Generated("org.jsonschema2pojo")
public class LoginData {
    @SerializedName("access_token")
    @Expose
    private String accessToken;
    @SerializedName("token_type")
    @Expose
    private String tokenType;
    @SerializedName("refresh_token")
    @Expose
    private String refreshToken;
    @SerializedName("expires_in")
    @Expose
    private long expiresIn;
    @SerializedName("scope")
    @Expose
    private String scope;

    // getter setter 
}

Here is my Spring boot application code example

MainApplicationClass.java

@SpringBootApplication
public class MainApplicationClass {
    public static void main(String[] args) {
        SpringApplication.run(MainApplicationClass.class, args);
    }
}

Controller.java

@RestController
public class BlogController {
    @Autowired
    BlogRespository blogRespository;
    BlogMockedData blogMockedData = BlogMockedData.getInstance();

    @GetMapping("/blog")
    public List<Blog> index() {
        return blogMockedData.fetchBlogList();
    }

    @GetMapping("/blog/{id}")
    public Blog show(@PathVariable String id) {
        int blogId = Integer.parseInt(id);
        return blogMockedData.getBlogById(blogId);
    }

    @PostMapping(value = "/api/login",
            consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_FORM_URLENCODED_VALUE},
            produces = {MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_JSON_VALUE}
    )
    public LoginData postLogin(@RequestBody Map<String, String> body) {
        String userName = body.get("username");
        String password = body.get("password");
        return blogMockedData.getLoginToken(userName, password);
    }

NOTE: If I hit spring boot POST service from POSTMAN i get below result

enter image descriptiIn here

But if I hit the POST service from my android client side it gets me the error

"status":415,"error":"Unsupported Media Type","exception":"org.springframework.web.HttpMediaTypeNotSupportedException","message":"Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported","path":"/api/login"

3

3 Answers

1
votes

When using application/x-www-form-urlencoded, Spring doesn't understand it as a RequestBody. So, remove the @RequestBody annotation in the parameter list of your mapped data as I can see it there.

Please read this Spring doesn't understand application/x-www-form-urlencoded

0
votes

For Spring to correctly load form encoded data you need to define the endpoint parameter as:

public LoginData postLogin(@RequestBody MultiValueMap<String, String> body)

or

public LoginData postLogin(@RequestParam Map<String, String> body)
0
votes

To process a URL Encoded POST in Spring Boot ( Content-Type: application/x-www-form-urlencoded )

This does not work:

    public String processForm(@RequestBody RespFormDTO formDTO, 
HttpServletRequest request, HttpServletResponse response) {

This will work:

public String processForm(RespFormDTO formDTO,
       HttpServletRequest request, HttpServletResponse response) {