Detailed Guide to Spring MVC JSON Parameter Handling and Common Pitfalls

Recently, I decided to stop using sessions and explore tokens for a more secure and robust approach, while also creating a unified interface for both browsers and mobile apps. I refactored a practice project's frontend to use Ajax entirely, keeping Spring MVC for view controller forwarding. This deepened my understanding of JSON data transmission, which I'd like to share and invite corrections.

Understanding JSON: Object vs. String

In JavaScript, we often define a JSON object like this:

var jsonObject = {
    "username": "admin",
    "password": 123
};

This is a JSON object. There is also a JSON string—a string enclosed in single or double quotes. Strings can be printed directly, but objects cannot. In JavaScript, we use two utility methods to convert between them:

  • JSON.parse(): Parses a JSON string into a JavaScript object.
  • JSON.stringify(): Converts a JavaScript value to a JSON string.

For example:

var jsonObject = {
    "username": "admin",
    "password": 123
};
alert(jsonObject); // Shows [object Object]
alert(JSON.stringify(jsonObject)); // Shows {"username":"admin","password":123}

Sending JSON Data via Ajax

When sending JSON to Spring MVC via Ajax, should we send a JSON object or a JSON string? Let's experiment with sending a JSON object first:

var username = $("#username").val();
var password = $("#password").val();
var json = {
    "username": username,
    "password": password
};

$.ajax({
    url: "jsontest",
    type: "POST",
    async: true,
    data: json,
    dataType: 'json',
    success: function(data) {
        if (data.userstatus === "success") {
            $("#errorMsg").remove();
        } else {
            if ($("#errorMsg").length <= 0) {
                $("form[name=loginForm]").append(errorMsg);
            }
        }
    }
});

Using @RequestParam

Spring MVC provides @RequestParam, similar to request.getParameter() in Servlets. Let's try receiving parameters with it:

@RequestMapping("/jsontest")
public void test(@RequestParam(value = "username", required = true) String username,
                 @RequestParam(value = "password", required = true) String password) {
    System.out.println("username: " + username);
    System.out.println("password: " + password);
}

The backend successfully prints the parameters! Even without @RequestParam, Spring MVC automatically binds the parameters:

@RequestMapping("/jsontest")
public void test(String username, String password) {
    System.out.println("username: " + username);
    System.out.println("password: " + password);
}

This works because jQuery's Ajax, by default, uses the Content-Type: application/x-www-form-urlencoded encoding. This encoding serializes the JSON object into a query string like username="admin"&password=123 and sends it in the request body (for POST) or URL (for GET). @RequestParam and request.getParameter() can handle this format.

Using @RequestBody for JSON Strings

Spring MVC also provides @RequestBody for handling requests with content types other than application/x-www-form-urlencoded, such as application/json or application/xml. To use it, the Ajax request must change its Content-Type to application/json and send a JSON string (not an object):

$.ajax({
    url: "jsontest",
    type: "POST",
    async: true,
    contentType: "application/json",
    data: JSON.stringify(json),
    dataType: 'json',
    success: function(data) {
        if (data.userstatus === "success") {
            $("#errorMsg").remove();
        } else {
            if ($("#errorMsg").length <= 0) {
                $("form[name=loginForm]").append(errorMsg);
            }
        }
    }
});

On the backend, we can receive the JSON string using @RequestBody with a Map:

@RequestMapping("/jsontest")
public void test(@RequestBody(required = true) Map<String, Object> map) {
    String username = map.get("username").toString();
    String password = map.get("password").toString();
    System.out.println("username: " + username);
    System.out.println("password: " + password);
}

If we omit @RequestBody, Spring MVC cannot parse the body, leading to a NullPointerException.

We can also bind directly to a POJO (Plain Old Java Object) using @RequestBody:

@RequestMapping("/jsontest")
public void test(@RequestBody User user) {
    String username = user.getUsername();
    String password = user.getPassword();
    System.out.println("username: " + username);
    System.out.println("password: " + password);
}

This works perfectly. However, for small data payloads like login credentials, I prefer extracting individual values from a Map rather than creating a dedicated User object if I don't need all fields.

Binding POJO with JSON Object

Can we bind a POJO when sending a JSON object (not a string)? Yes, but do not use @RequestParam. Without that annotation, Spring MVC can bind parameters directly to a POJO field:

@RequestMapping("/jsontest")
public void test(User user) {
    // user will have username and password populated
}

Common Errors and Summary

  • 415 Unsupported Media Type: Occurs if you use @RequestBody but the Ajax Content-Type is still application/x-www-form-urlencoded. Always set contentType: "application/json" when using @RequestBody.
  • Backend log: Without logging framework, Tomcat may not show errors. Ensure you have proper logging configured.

Key Takeaways

Frontend Content-Type Data Format Sent Backend Annotation
application/x-www-form-urlencoded (default) JSON object (key-value pairs) @RequestParam or no annotation for simple types; can bind to POJO without @RequestParam
application/json JSON string @RequestBody (for Map, POJO, etc.)

Quick Reference

  • JSON object@RequestParam (or Servlet getParameter) for simple fields.
  • JSON string@RequestBody for complex binding.

I hope this summary of my day-long experiments helps you! If there are any mistakes, please kindly point them out.

Tags: Spring MVC JSON Ajax RequestBody RequestParam

Posted on Thu, 07 May 2026 00:45:21 +0000 by Haktar