问题
My request was an application/json
type like this: {"able": true}
, but when I send the request like this {"able":12345}
, the field able
still can get a correct value true
. Why?
@PatchMapping("/{id}/path/{name}")
public ResponseEntity someMethod(
@Valid @RequestBody SomeRequest request) {
// do something
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SomeRequest {
@AssertTrue
@NotNull
private Boolean able;
}
回答1:
Because jackson.databind will parse int to bool when field type is bool.
Find code in NumberDeserializers.BooleanDeserializer
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
if (t == JsonToken.VALUE_FALSE) {
return Boolean.FALSE;
}
return _parseBoolean(p, ctxt);
_parseBoolean(p, ctxt)
will parse int to bool.
We can do it by ourselves not use default.
- Create our bool deser class.
public class MyDeser extends JsonDeserializer {
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
if (t == JsonToken.VALUE_FALSE) {
return Boolean.FALSE;
}
return null;
// not parse int to bool but null and it may work ok.
// if throw new IOException(), it will work fail. Maybe return null means use other deser to deal it. throw Exception means fail. I don't know it clearly.
}
}
- Create a configuration and inject a SimpleModule bean. I write in application
@SpringBootApplication
@Configuration
public class DemoApplication {
@Bean
public SimpleModule addDeser() {
return new SimpleModule().addDeserializer(Boolean.class, new MyDeser());
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
回答2:
Maybe because each non-zero integer value is true? What happens if you sent {"able":0}
?
回答3:
Each non zero value will be treated as true in boolean case. If you send zero then it will set value to false.
回答4:
Actually the answer posted by sunsunsun
is exactly. It works well. But my answer is re-code the setter method of SomeRequest
like this:
public void setAble(Object value) {
if (value instanceof Boolean) {
submitted = (Boolean) value;
}
if ("true".equals(value)) {
submitted = true;
}
}
Because Jackson is using the setter method to inject value.
And then I can just accept the value which is true or "true". And I don't want to affect others.
来源:https://stackoverflow.com/questions/59353379/springboot-atomically-convert-integer-to-boolean-with-requestbody-annotation-h