Close

Spring MVC - Automatic Parameter Names Discovery (Removed in Spring 6.1)

[Last Updated: Mar 11, 2026]

If we want Spring to match query parameter names with @RequestParam (or similarly with @PathVariable or @RequestHeader) automatically without explicitly specifying the name i.e. without specifying value in @RequestParam("myRequestParamName") then our code should be compiled with debugging information or with the -parameters compiler flag.

Note: Before Spring MVC 6.1, it was possible to use features like @RequestMapping without explicitly adding -parameters to your Maven compiler configuration, because LocalVariableTableParameterNameDiscoverer could infer parameter names from debug symbols included in bytecode by default. This meant that many projects worked out of the box without any special compiler flags, as the default Maven build included enough debug information for Spring to resolve parameter names automatically. From 6.1 onwards, this fallback was removed, making the -parameters flag mandatory for parameter name resolution to work correctly.

Example

Let's create a Spring MVC project without explicitly compiling with debugging info or with -parameter flag. We are using Spring MVC version older than 6.

A Controller

@Controller
public class MyController {

    @ResponseBody
    @RequestMapping("/user")
    public String test(String name) {
        return "test response for name: " + name;
    }
}

Let's make a request to our controller

To try examples, run embedded Jetty (configured in pom.xml of example project below):

mvn jetty:run
$ curl -s http://localhost:8080/user?name=joe
test response for name: joe

We didn't explicitly compile our code with -g option or with -parameter flag, but it still works.

After some debugging I found Spring uses implementations of interface ParameterNameDiscoverer to find parameter names. By default spring uses DefaultParameterNameDiscoverer which first delegates to StandardReflectionParameterNameDiscoverer (which relies on -parameter flag), if it returns null name then ASM-based LocalVariableTableParameterNameDiscoverer is attempted (which relies on -g:vars option).
In our case LocalVariableTableParameterNameDiscoverer returned the real parameter name.

These resolvers can also be used outside of Spring container. Let's try LocalVariableTableParameterNameDiscoverer:

package com.logicbig.example;

import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

public class Test {
    public void testMethod(String myParamName) {
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Method m = Test.class.getDeclaredMethod("testMethod", String.class);
        System.out.println("-- using Parameter#getName() --");
        for (Parameter parameter : m.getParameters()) {
            System.out.println(parameter.getName());
        }

        System.out.println(
                "-- using LocalVariableTableParameterNameDiscoverer#getParameterNames --");
        LocalVariableTableParameterNameDiscoverer d =
                new LocalVariableTableParameterNameDiscoverer();
        String[] pNames = d.getParameterNames(m);
        System.out.println(Arrays.toString(pNames));
    }
}

Output

-- using Parameter#getName() --
arg0
-- using LocalVariableTableParameterNameDiscoverer#getParameterNames --
[myParamName]

I'm not specifying any -g option when compiling. So how LocalVariableTableParameterNameDiscoverer still works?. Let's see what is in our Test class via javap command.

D:\auto-handler-method-param-name-matching\target\classes>javap -l com.logicbig.example.Test
Compiled from "Test.java"
public class com.logicbig.example.Test {
public com.logicbig.example.Test();
LineNumberTable:
line 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/logicbig/example/Test;

public void testMethod(java.lang.String);
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this Lcom/logicbig/example/Test;
0 1 1 myParamName Ljava/lang/String;

public static void main(java.lang.String[]) throws java.lang.NoSuchMethodException;
LineNumberTable:
line 14: 0
line 15: 17
line 16: 40
line 15: 51
line 19: 57
line 21: 65
line 22: 71
line 24: 81
LocalVariableTable:
Start Length Slot Name Signature
40 11 5 parameter Ljava/lang/reflect/Parameter;
0 82 0 args [Ljava/lang/String;
17 65 1 m Ljava/lang/reflect/Method;
65 17 2 d Lorg/springframework/core/LocalVariableTableParameterNameDiscoverer;
71 11 3 pNames [Ljava/lang/String;
}

That confirms that code is complied with -g vars option as local variable names are included in the class file. By default javac includes only line number and source file information (see here).
After some investigation, it turned out that the maven's Java compiler plugin, by default, adds all debug information via 'debug' option. I turned that option off and then it stopped working with following exception while hitting our example Spring controller:

java.lang.IllegalArgumentException: Name for argument type [java.lang.String] not available, and parameter name information not found in class file either.
	org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.updateNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:171)
	org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.getNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:148)
	org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:97)
	org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124)
	org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
	org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131)

Conclusion

Spring MVC can only match the http request parameters to our handler method parameters if the source code is either compiled with -g:vars or -parameter option of javac.
If you are compiling your code via maven then maven by default includes all debug info via -g option.
If your application is relying on automatic parameter name discovery (which was only possible Spring MVC version prior to 6) and you want to be 100% sure that your code won't break at some point, you may like to add the -parameter or -g option yourself in maven compiler plugin (check out this and this).

With -parameters enabled, StandardReflectionParameterNameDiscoverer handles everything that LocalVariableTableParameterNameDiscoverer used to, more reliably and without bytecode parsing hacks. If you're seeing errors after upgrading to Spring 6.1, the fix is almost always just enabling the -parameters compiler flag in your build configuration.

Example Project

Dependencies and Technologies Used:

  • spring-webmvc 5.0.5.RELEASE (Spring Web MVC)
     Version Compatibility: 3.2.9.RELEASE - 5.3.39Version List
    ×

    Version compatibilities of spring-webmvc with this example:

      javax.servlet-api:3.x
    • 3.2.9.RELEASE
    • 3.2.10.RELEASE
    • 3.2.11.RELEASE
    • 3.2.12.RELEASE
    • 3.2.13.RELEASE
    • 3.2.14.RELEASE
    • 3.2.15.RELEASE
    • 3.2.16.RELEASE
    • 3.2.17.RELEASE
    • 3.2.18.RELEASE
    • 4.0.0.RELEASE
    • 4.0.1.RELEASE
    • 4.0.2.RELEASE
    • 4.0.3.RELEASE
    • 4.0.4.RELEASE
    • 4.0.5.RELEASE
    • 4.0.6.RELEASE
    • 4.0.7.RELEASE
    • 4.0.8.RELEASE
    • 4.0.9.RELEASE
    • 4.1.0.RELEASE
    • 4.1.1.RELEASE
    • 4.1.2.RELEASE
    • 4.1.3.RELEASE
    • 4.1.4.RELEASE
    • 4.1.5.RELEASE
    • 4.1.6.RELEASE
    • 4.1.7.RELEASE
    • 4.1.8.RELEASE
    • 4.1.9.RELEASE
    • 4.2.0.RELEASE
    • 4.2.1.RELEASE
    • 4.2.2.RELEASE
    • 4.2.3.RELEASE
    • 4.2.4.RELEASE
    • 4.2.5.RELEASE
    • 4.2.6.RELEASE
    • 4.2.7.RELEASE
    • 4.2.8.RELEASE
    • 4.2.9.RELEASE
    • 4.3.0.RELEASE
    • 4.3.1.RELEASE
    • 4.3.2.RELEASE
    • 4.3.3.RELEASE
    • 4.3.4.RELEASE
    • 4.3.5.RELEASE
    • 4.3.6.RELEASE
    • 4.3.7.RELEASE
    • 4.3.8.RELEASE
    • 4.3.9.RELEASE
    • 4.3.10.RELEASE
    • 4.3.11.RELEASE
    • 4.3.12.RELEASE
    • 4.3.13.RELEASE
    • 4.3.14.RELEASE
    • 4.3.15.RELEASE
    • 4.3.16.RELEASE
    • 4.3.17.RELEASE
    • 4.3.18.RELEASE
    • 4.3.19.RELEASE
    • 4.3.20.RELEASE
    • 4.3.21.RELEASE
    • 4.3.22.RELEASE
    • 4.3.23.RELEASE
    • 4.3.24.RELEASE
    • 4.3.25.RELEASE
    • 4.3.26.RELEASE
    • 4.3.27.RELEASE
    • 4.3.28.RELEASE
    • 4.3.29.RELEASE
    • 4.3.30.RELEASE
    • 5.0.0.RELEASE
    • 5.0.1.RELEASE
    • 5.0.2.RELEASE
    • 5.0.3.RELEASE
    • 5.0.4.RELEASE
    • 5.0.5.RELEASE
    • 5.0.6.RELEASE
    • 5.0.7.RELEASE
    • 5.0.8.RELEASE
    • 5.0.9.RELEASE
    • 5.0.10.RELEASE
    • 5.0.11.RELEASE
    • 5.0.12.RELEASE
    • 5.0.13.RELEASE
    • 5.0.14.RELEASE
    • 5.0.15.RELEASE
    • 5.0.16.RELEASE
    • 5.0.17.RELEASE
    • 5.0.18.RELEASE
    • 5.0.19.RELEASE
    • 5.0.20.RELEASE
    • 5.1.0.RELEASE
    • 5.1.1.RELEASE
    • 5.1.2.RELEASE
    • 5.1.3.RELEASE
    • 5.1.4.RELEASE
    • 5.1.5.RELEASE
    • 5.1.6.RELEASE
    • 5.1.7.RELEASE
    • 5.1.8.RELEASE
    • 5.1.9.RELEASE
    • 5.1.10.RELEASE
    • 5.1.11.RELEASE
    • 5.1.12.RELEASE
    • 5.1.13.RELEASE
    • 5.1.14.RELEASE
    • 5.1.15.RELEASE
    • 5.1.16.RELEASE
    • 5.1.17.RELEASE
    • 5.1.18.RELEASE
    • 5.1.19.RELEASE
    • 5.1.20.RELEASE
    • 5.2.0.RELEASE
    • 5.2.1.RELEASE
    • 5.2.2.RELEASE
    • 5.2.3.RELEASE
    • 5.2.4.RELEASE
    • 5.2.5.RELEASE
    • 5.2.6.RELEASE
    • 5.2.7.RELEASE
    • 5.2.8.RELEASE
    • 5.2.9.RELEASE
    • 5.2.10.RELEASE
    • 5.2.11.RELEASE
    • 5.2.12.RELEASE
    • 5.2.13.RELEASE
    • 5.2.14.RELEASE
    • 5.2.15.RELEASE
    • 5.2.16.RELEASE
    • 5.2.17.RELEASE
    • 5.2.18.RELEASE
    • 5.2.19.RELEASE
    • 5.2.20.RELEASE
    • 5.2.21.RELEASE
    • 5.2.22.RELEASE
    • 5.2.23.RELEASE
    • 5.2.24.RELEASE
    • 5.2.25.RELEASE
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.3.3
    • 5.3.4
    • javax.servlet-api:4.x
    • 5.3.5
    • 5.3.6
    • 5.3.7
    • 5.3.8
    • 5.3.9
    • 5.3.10
    • 5.3.11
    • 5.3.12
    • 5.3.13
    • 5.3.14
    • 5.3.15
    • 5.3.16
    • 5.3.17
    • 5.3.18
    • 5.3.19
    • 5.3.20
    • 5.3.21
    • 5.3.22
    • 5.3.23
    • 5.3.24
    • 5.3.25
    • 5.3.26
    • 5.3.27
    • 5.3.28
    • 5.3.29
    • 5.3.30
    • 5.3.31
    • 5.3.32
    • 5.3.33
    • 5.3.34
    • 5.3.35
    • 5.3.36
    • 5.3.37
    • 5.3.38
    • 5.3.39

    Versions in green have been tested.

  • javax.servlet-api 3.0.1 (Java Servlet API)
  • JDK 1.8
  • Maven 3.9.11

Spring MVC - Parameter Names Discovery Select All Download
  • auto-handler-method-param-name-matching
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • Test.java

    See Also

    Join