Search code examples
spring-bootspring-mvcparametersgraalvmgraalvm-native-image

Spring MVC RequestParam without name does not work on native image


Spring Boot 3.1.3
graalvm-jdk-17.0.8+9.1
native-maven-plugin 0.9.5

Controller methods without name in RequestParam does not work (below exception):

@GetMapping(value="/test", produces=MediaType.TEXT_PLAIN_VALUE)
public String test(@RequestParam(required=false) String category)

Same with name to annotation works fine:

@GetMapping(value="/test", produces=MediaType.TEXT_PLAIN_VALUE)
public String test(@RequestParam(name = "category", required=false) String category)

Exception:

java.lang.IllegalArgumentException: Name for argument of type
[java.lang.String] not specified, and parameter name information notfound in class file either.
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.updateNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:177)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.getNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:154)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:99)

cannot use spring boot as parent pom so importing it:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>3.1.3</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

pom fragment for native image generation, following wiki (tip):

<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
    <configuration>
        <fallback>false</fallback>
        <verbose>true</verbose>
        <quickBuild>true</quickBuild>
        <metadataRepository>
            <enabled>true</enabled>
        </metadataRepository>       
        <jvmArgs>
            <jvmArg>-XX:+UseContainerSupport</jvmArg>
            <jvmArg>-XX:MaxRAMPercentage=70</jvmArg>                                
        </jvmArgs>                          
        <buildArgs>
            <arg>-H:+ReportExceptionStackTraces</arg>
            <!-- WA for https://github.com/oracle/graal/issues/4757 -->
            <arg>-H:-UseContainerSupport</arg>
            <!-- Custom reachability metadata for 3rd parties, not yet supported in: https://github.com/oracle/graalvm-reachability-metadata/tree/master/metadata --> 
            <arg>-H:ReflectionConfigurationResources=META-INF/native-image/reflect-config.json</arg>
        </buildArgs>                            
        <requiredVersion>22.3</requiredVersion>
    </configuration>
    <executions>
        <execution>
            <id>add-reachability-metadata</id>
            <goals>
                <goal>add-reachability-metadata</goal>
            </goals>
        </execution>
    </executions>
</plugin>   

When trying to add same method without name to Demo application it works perfect, so I understand something is wrong with my project but cannot find the root cause.

@GetMapping(value="/test", produces=MediaType.TEXT_PLAIN_VALUE)
public String test(@RequestParam(required=false) String category){
    System.out.println("category: " + category);
    return category;
}

Solution

  • Thanks to M.Deinum comments, found the root cause after inspecting Spring Boot parent pom. Need to add parameters=true in maven-compiler-plugin to retain methods parameters name in compiled classes. However, it is probably better to fix the code and add parameters names to spring annotations to not increase final native image size by retaining these parameters names in compiled classes.

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <parameters>true</parameters>
        </configuration>
    </plugin>