英文:
Cannot deserialize value of type `java.math.BigInteger` from String
问题
I have an API like the one below, which receives and processes a number provided by the user.
@RestController
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public class MainController {
@RequestMapping(value = "/test", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public String test(@Validated @RequestBody InputRequest input) throws Exception {
return "{\"num\":\"" + String.valueOf(input.getNum()) + "\"}";
}
}
@Getter
@Setter
public class InputRequest {
private BigInteger num;
}
When my tester sent a string of junk like "!@#$^!&*"
to the num
field, my API showed an HTTP 400 error, and an exception was raised:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.math.BigInteger` from String ""!@#$%^&*()_+<>?~!": not a valid representation; ...
Is there any way to block such junk input or handle this exception on my own without changing the data type of num
?
英文:
I have a API like below, it receive and process a number that is given by user
@RestController
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public class MainController {
@RequestMapping(value = "/test", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public String test(@Validated @RequestBody InputRequest input) throws Exception {
return "{\"num\":" + String.valueOf(input.getNum()) +"}";
}
}
@Getter
@Setter
public class InputRequest{
private BigInteger num;
}
And then my tester sent a string of junk like "!@#$^!&*"
to num
field, my API show Http 400 and a line of exception pop up
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.math.BigInteger` from String "!@#$%^&*()_+<>?~!": not a valid representation; ...
Is there any way to block such junk input or handle this exception by my own? Without change the data type of num
?
答案1
得分: 2
你可以创建自定义反序列化器来处理无效的值:
public class BigIntegerDeserializer extends StdDeserializer<BigInteger> {
protected BigIntegerDeserializer() {
super(BigInteger.class);
}
@Override
public BigInteger deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException, JacksonException {
final String input = jsonParser.getText();
try {
return BigInteger.valueOf(Long.parseLong(input));
} catch (final NumberFormatException e) {
throw new IllegalArgumentException("Value must be a number.");
}
}
}
然后将该反序列化器注解到你的字段上:
@Getter
@Setter
public class InputRequest {
@JsonDeserialize(using = BigIntegerDeserializer.class) // 这里
private BigInteger num;
}
如果你想返回消息 "Value must a number" 给测试者,你可以使用 ExceptionHandler 来处理异常:
@ExceptionHandler(HttpMessageNotReadableException.class)
public static ResponseEntity<String> handleHttpMessageNotReadableException(
@NonNull final HttpMessageNotReadableException exception
) {
// 由于 Jackson 在抛出异常之前包装了 IllegalArgumentException 异常,你需要在其中找到根本原因的异常。
Throwable rootCause = org.apache.commons.lang3.exception.ExceptionUtils.getRootCause(exception);
final String message = rootCause.getMessage(); // Value must be a number.
return ...;
}
英文:
You can create custom deserializer to handle invalid value:
public class BigIntegerDeserializer extends StdDeserializer<BigInteger> {
protected BigIntegerDeserializer() {
super(BigInteger.class);
}
@Override
public BigInteger deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException, JacksonException {
final String input = jsonParser.getText();
try {
return BigInteger.valueOf(Long.parseLong(input));
} catch (final NumberFormatException e) {
throw new IllegalArgumentException("Value must be a number.");
}
}
}
Then annotate that deserializer to your field:
@Getter
@Setter
public class InputRequest {
@JsonDeserialize(using = BigIntegerDeserializer.class) // Here
private BigInteger num;
}
In case you want to return the message "Value must a number" back to tester. You can handle the exception using ExceptionHandler:
@ExceptionHandler(HttpMessageNotReadableException.class)
public static ResponseEntity<String> handleHttpMessageNotReadableException(
@NonNull final HttpMessageNotReadableException exception
) {
// Since Jackson wrap your IllegalArgumentException exception before throwing. You have to find the cause exception inside it.
Throwable rootCause = org.apache.commons.lang3.exception.ExceptionUtils.getRootCause(exception);
final String message = rootCause.getMessage(); // Value must be a number.
return ...;
}
答案2
得分: 1
以下是已翻译的内容:
功能您看到的是预期的功能。
如果您想处理非数字值,
考虑将处理程序方法更改为接收一个字符串值,然后自行解析它。
这是一些示例代码:
import org.apache.commons.lang3.math.NumberUtils;
@RequestMapping(value = "/test", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public String test(@RequestBody String requestBody) throws Exception
{
String returnValue;
if (StringUtils.isNotEmpty(requestBody)))
{
final InputRequest inputRequest;
try
{
inputRequest = objectMapper.readValue(requestBody, InputRequest.class);
returnValue = "blam"; // 处理成功
}
catch (some exception type)
{
returnValue = "kapow"; // 处理解析错误。
// 在此处理解析异常。
}
}
else
{
returnValue = "blam"; // 处理无请求体的情况。
}
return returnValue;
}
// commons lang3的依赖项
// <dependency>
// <groupId>org.apache.commons</groupId>
// <artifactId>commons-lang3</artifactId>
// <version>3.5</version>
// </dependency>
英文:
The functionality you see is the expected functionality.
If you want to handle non-number values,
consider changing the handler method to receive a String value and then parse
it yourself.
Here is some sample code:
import org.apache.commons.lang3.math.NumberUtils;
@RequestMapping(value = "/test", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public String test(@RequestBody String requestBody) throws Exception
{
String returnValue;
if (StringUtils.isNotEmpty(requestBody)))
{
final InputRequest inputRequest;
try
{
inputRequest = objectMapper.readValue(requestBody, InputRequest.class);
returnValue = "blam"; // handle success
}
catch (some exception type)
{
returnValue = "kapow"; // handle parse error.
// handle parse exceptions here.
}
}
else
{
returnValue = "blam"; // handle no request body here.
}
return returnValue;
}
// The dependency for commons lang3
// <dependency>
// <groupId>org.apache.commons</groupId>
// <artifactId>commons-lang3</artifactId>
// <version>3.5</version>
// </dependency>
答案3
得分: 0
请求体的验证可以使用验证进行,例如 - https://blog.tericcabrel.com/validate-request-body-and-parameter-in-spring-boot/
英文:
Validation of request body can be done using Validation
For example - https://blog.tericcabrel.com/validate-request-body-and-parameter-in-spring-boot/
答案4
得分: 0
您可以在您的控制器中简单地定义一个带有 @ExceptionHandler 注释的方法:
@ExceptionHandler
ResponseEntity<String> handleMessageNotReadable(HttpMessageNotReadableException e) {
// 根据需求更改下面的状态
return new ResponseEntity<>(e.getMessage(), HttpStatus.NOT_ACCEPTABLE);
}
要全局处理异常,请使用 @ControllerAdvice,有关异常处理的更多详细信息,请查看博客文章。
英文:
You can simply define an @ExceptionHandler annotated method in your controller:
@ExceptionHandler
ResponseEntity<String> handleMessageNotReadable(HttpMessageNotReadableException e) {
// change the status below according to requirements
return new ResponseEntity<>(e.getMessage(), HttpStatus.NOT_ACCEPTABLE);
}
For handling exceptions globally use @ControllerAdvice, for more details about exception handling check the blog post.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论