1

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

Maurice
  • 6,698
  • 9
  • 47
  • 104
  • How are you calling this URL? Show the calling code. In general a `#` is used for a client-side anchor and isn't send to the server at all. So unless you are encoding it properly you are calling the wrong URL. – M. Deinum Oct 28 '19 at 09:16
  • @M.Deinum see my edit – Maurice Oct 28 '19 at 20:35
  • 1
    The URL you are calling isn't the URL you are mapping. If I look at your javascript the `languageCode` comes first not the `searchString`. Also you should be encoding the `searchString` before sending it. When posting something with a `#` it is either client side anchor or interpreted as a html entity code (which is numeric by default). So you should really be escaping/encoding your search string before using it. – M. Deinum Oct 29 '19 at 08:17
  • @M.Deinum sorry I already turned it into a post request, the code used to look different. It used get instead of post and it had searchString as a path variable – Maurice Oct 29 '19 at 18:02

1 Answers1

1

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
Jonathan JOhx
  • 5,784
  • 2
  • 17
  • 33