Cannot deserialize value of type `java.math.BigInteger` from String

huangapple go评论226阅读模式
英文:

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&lt;BigInteger&gt; {

    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(&quot;Value must be a number.&quot;);
        }
    }
}

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&lt;String&gt; 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 = &quot;/test&quot;, method = RequestMethod.POST, produces = &quot;application/json;charset=UTF-8&quot;)
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 = &quot;blam&quot;;  // handle success
		}
		catch (some exception type)
		{
			returnValue = &quot;kapow&quot;; // handle parse error.
			// handle parse exceptions here.
		}
	}
	else
	{
		returnValue = &quot;blam&quot;; // handle no request body here.
	}
	
	return returnValue;
}


// The dependency for commons lang3
//      &lt;dependency&gt;
//        &lt;groupId&gt;org.apache.commons&lt;/groupId&gt;
//        &lt;artifactId&gt;commons-lang3&lt;/artifactId&gt;
//        &lt;version&gt;3.5&lt;/version&gt;
//      &lt;/dependency&gt;

答案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&lt;String&gt; handleMessageNotReadable(HttpMessageNotReadableException e) {
  // change the status below according to requirements
  return new ResponseEntity&lt;&gt;(e.getMessage(), HttpStatus.NOT_ACCEPTABLE);
}

For handling exceptions globally use @ControllerAdvice, for more details about exception handling check the blog post.

huangapple
  • 本文由 发表于 2023年6月12日 21:50:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76457337.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定