Search code examples
springspring-mvcgetget-mapping

@PathVariable of GetMapping in Spring throws an error when the input is #


I have made an autosuggest input field that automatically searches the database on every keypress. It works fine when i insert regular characters like letters and numbers but it gets spooky when you try start the search request with the character #. Doing that throws the error org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'long'; nested exception is java.lang.NumberFormatException: For input string: "get"

When i add some letters before the # (for example des#) it will throw an 404 page not found error and if i use the % character it will throw an 400 'unauthorized' error.

This strange behavior has probably something to do that i'm expecting a GetRequest instead of a PostRequest. If i turn it into a PostMapping i'm sure the errors will dissapear. But my question is; why is this happening? Does # have a special meaning? Why does spring seemingly try to convert # to a long value even though the pathvariable is typed as String? And why has the input string become "get" according to the error? I know that in an url # has a special meaning in that it signifies an href anchor but why should it be a special character for spring?

Heres the code of my getMapping

@GetMapping("/get/varietynames/{searchString}/{languageCode}")
public List<CropVarietyNameSelectionDTO> getCropVarietySelectionDTOBySearchString(@PathVariable("searchString") @NotBlank @Pattern(regexp = "^[A-Za-z0-9]+$", message = "Search input only allows for letters and numbers")
                                                                                      @Size(min = 1, max = 40, message = "Search input cannot exceed 40 characters") String searchString, @PathVariable("languageCode") String languageCode){
    return seedService.getCropVarietySelectionDTOBySearchString(searchString,languageCode);
}

Edit

Request on the frontend side is:

  private basePath:string = this.apiUrl + "/seed";
  getCropVarietySelectionDTOBySearchString(searchString: string):Observable<CropVarietyNameSelectionDTO[]>{
    return (searchString && (searchString.trim().length > 0))  ? this.http.post<CropVarietyNameSelectionDTO[]>(this.basePath + "/get/varietynames/" + this.languageService.getCodeOfPreferredLanguage(), searchString) : Observable.of([]);
  }

this.apiUrl = localhost:4200


Solution

  • That is not the correct way or option to use @PathVariable annotation which indicates that a method parameter should be bound to a URI template variable. You need to use @RequestParam annotation which indicates that a method parameter should be bound to a web request parameter. You can see this answer that is a @RequestParam vs @PathVariable

    @GetMapping("/get/varietynames")
    public List<CropXXXDTO> getXXXXXhString(@RequestParam @NotBlank 
           @Pattern(regexp = "^xx+$", message = "xxxxx")                                                                                  
           @Size(min = 1, max = 40, message = "xxxxx") String searchString, 
           @RequestParam(required = false, defaultValue = "EN") String languageCode){
        return seedService.getXXXXtring(searchString, languageCode);
    }
    

    Then you can check the URL by following way:

    /get/varietynames?searchString=XXXXX&languageCode=EN