NumberFormatException: For input string: "" in Swagger (Solved)
In my previous article about Documenting Spring Boot REST API with Swagger, I mentioned about following "error" while running the program and/or accessing api-docs (or swagger-ui):
2020-05-02 21:25:56.584 WARN 15140 --- [nio-8080-exec-1] i.s.m.p.AbstractSerializableParameter : Illegal DefaultValue null for parameter type integer java.lang.NumberFormatException: For input string: "" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_181] at java.lang.Long.parseLong(Long.java:601) ~[na:1.8.0_181] at java.lang.Long.valueOf(Long.java:803) ~[na:1.8.0_181] at io.swagger.models.parameters.AbstractSerializableParameter.getExample(AbstractSerializableParameter.java:412) ~[swagger-models-1.5.20.jar:1.5.20] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181] at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) [jackson-databind-2.10.2.jar:2.10.2] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:722) [jackson-databind-2.10.2.jar:2.10.2] at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) [jackson-databind-2.10.2.jar:2.10.2]
To be precise, this is not an error, its just a warning log message. And I already give one workaround in my article. But if you not happy with just a workaround, and want a solution, then you must fix your code.
First, you need to check any @ApiModelProperty
annotation. You must set an example value on any numeric type property and annotated with @ApiModelProperty
, like below:
@ApiModelProperty(notes = "Unique identifier of the Contact.", example = "1", required = true, position = 0) @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id;
But for my sample program, that's not enough. You also need to set example value for each parameter that uses the @ApiParam
annotation and has a field type of numeric type. You need to set it, as following:
public ResponseEntity<Contact> findContactById( @ApiParam(name = "contactId", value = "Id of the contact to be obtained. Cannot be empty.", example = "1", required = true) @PathVariable long contactId) { ... return ... }
So my ContactController
is changed from:
@Api(description = "Endpoints for Creating, Retrieving, Updating and Deleting of Contacts.",
tags = {"contact"})
@RestController
@RequestMapping("/api")
public class ContactController {
...
@ApiOperation(value = "Find Contacts by name", notes = "Name search by %name% format", tags = { "contact" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response=List.class ) })
@GetMapping(value = "/contacts")
public ResponseEntity<List<Contact>> findAll(
@ApiParam("Page number, default is 1") @RequestParam(value="page", defaultValue="1") int pageNumber,
@ApiParam("Name of the contact for search.") @RequestParam(required=false) String name) {
...
return ...
}
@ApiOperation(value = "Find contact by ID", notes = "Returns a single contact", tags = { "contact" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response=Contact.class),
@ApiResponse(code = 404, message = "Contact not found") })
@GetMapping(value = "/contacts/{contactId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Contact> findContactById(
@ApiParam("Id of the contact to be obtained. Cannot be empty.")
@PathVariable long contactId) {
...
return ...
}
@ApiOperation(value = "Add a new contact", tags = { "contact" })
@ApiResponses(value = {
@ApiResponse(code = 201, message = "Contact created"),
@ApiResponse(code = 400, message = "Invalid input"),
@ApiResponse(code = 409, message = "Contact already exists") })
@PostMapping(value = "/contacts")
public ResponseEntity<Contact> addContact(
@ApiParam("Contact to add. Cannot null or empty.")
@Valid @RequestBody Contact contact)
throws URISyntaxException {
...
return ...
}
@ApiOperation(value = "Update an existing contact", tags = { "contact" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation"),
@ApiResponse(code = 400, message = "Invalid ID supplied"),
@ApiResponse(code = 404, message = "Contact not found"),
@ApiResponse(code = 405, message = "Validation exception") })
@PutMapping(value = "/contacts/{contactId}")
public ResponseEntity<Contact> updateContact(
@ApiParam("Id of the contact to be update. Cannot be empty.")
@PathVariable long contactId,
@ApiParam("Contact to update. Cannot null or empty.")
@Valid @RequestBody Contact contact) {
...
return ...
}
@ApiOperation(value = "Update an existing contact's address", tags = { "contact" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation"),
@ApiResponse(code = 404, message = "Contact not found") })
@PatchMapping("/contacts/{contactId}")
public ResponseEntity<Void> updateAddress(
@ApiParam("Id of the contact to be update. Cannot be empty.")
@PathVariable long contactId,
@ApiParam("Contact's address to update.")
@RequestBody Address address) {
...
return ...
}
@ApiOperation(value = "Deletes a contact", tags = { "contact" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation"),
@ApiResponse(code = 404, message = "Contact not found") })
@DeleteMapping(path="/contacts/{contactId}")
public ResponseEntity<Void> deleteContactById(
@ApiParam("Id of the contact to be delete. Cannot be empty.")
@PathVariable long contactId) {
...
return ...
}
}
To:
@Api(description = "Endpoints for Creating, Retrieving, Updating and Deleting of Contacts.",
tags = {"contact"})
@RestController
@RequestMapping("/api")
public class ContactController {
...
@ApiOperation(value = "Find Contacts by name", notes = "Name search by %name% format", tags = {"contact"})
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response = List.class)})
@GetMapping(value = "/contacts")
public ResponseEntity<List<Contact>> findAll(
@ApiParam(name = "contactId",
value = "Page number, default is 1",
example = "1",
required = false) @RequestParam(value = "page", defaultValue = "1") int pageNumber,
@ApiParam("Name of the contact for search.") @RequestParam(required = false) String name) {
...
return ...
}
@ApiOperation(value = "Find contact by ID", notes = "Returns a single contact", tags = {"contact"})
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation", response = Contact.class),
@ApiResponse(code = 404, message = "Contact not found")})
@GetMapping(value = "/contacts/{contactId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Contact> findContactById(
@ApiParam(name = "contactId",
value = "Id of the contact to be obtained. Cannot be empty.",
example = "1",
required = true)
@PathVariable long contactId) {
...
return ...
}
@ApiOperation(value = "Add a new contact", tags = {"contact"})
@ApiResponses(value = {
@ApiResponse(code = 201, message = "Contact created"),
@ApiResponse(code = 400, message = "Invalid input"),
@ApiResponse(code = 409, message = "Contact already exists")})
@PostMapping(value = "/contacts")
public ResponseEntity<Contact> addContact(
@ApiParam("Contact to add. Cannot null or empty.")
@Valid @RequestBody Contact contact)
throws URISyntaxException {
...
return ...
}
@ApiOperation(value = "Update an existing contact", tags = {"contact"})
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation"),
@ApiResponse(code = 400, message = "Invalid ID supplied"),
@ApiResponse(code = 404, message = "Contact not found"),
@ApiResponse(code = 405, message = "Validation exception")})
@PutMapping(value = "/contacts/{contactId}")
public ResponseEntity<Contact> updateContact(
@ApiParam(name = "contactId",
value = "Id of the contact to be update. Cannot be empty.",
example = "1",
required = true)
@PathVariable long contactId,
@ApiParam("Contact to update. Cannot null or empty.")
@Valid @RequestBody Contact contact) {
...
return ...
}
@ApiOperation(value = "Update an existing contact's address", tags = {"contact"})
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation"),
@ApiResponse(code = 404, message = "Contact not found")})
@PatchMapping("/contacts/{contactId}")
public ResponseEntity<Void> updateAddress(
@ApiParam(name = "contactId",
value = "Id of the contact to be update. Cannot be empty.",
example = "1",
required = true)
@PathVariable long contactId,
@ApiParam("Contact's address to update.")
@RequestBody Address address) {
...
return ...
}
@ApiOperation(value = "Deletes a contact", tags = {"contact"})
@ApiResponses(value = {
@ApiResponse(code = 200, message = "successful operation"),
@ApiResponse(code = 404, message = "Contact not found")})
@DeleteMapping(path = "/contacts/{contactId}")
public ResponseEntity<Void> deleteContactById(
@ApiParam(name = "contactId",
value = "Id of the contact to be delete. Cannot be empty.",
example = "1",
required = true)
@PathVariable long contactId) {
...
return ...
}
}
Check all those @ApiParam
with example. Now, that warning gone...