问题
I have created my request POJO as follows
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Notification {
@NotNull
private String clientId;
private String userId;
@NotNull
private String requestingService;
@NotNull
private String message;
@NotNull
private String messageType;
when I send request body as follow, it is working fine.
{
"clientId":"9563",
"userId":"5855541",
"requestingService":"cm-dm-service",
"message":"Document Created",
"messageType":"user-msg"
}
But when I sent like below
{
"clientId":"9563",
"userId":true,
"requestingService":"cm-dm-service",
"message":"Document Created",
"messageType":"user-msg"
}
Here is my controller
public ResponseEntity<Status> createNotification(@RequestBody @Valid Notification notification,
BindingResult bindingResult, HttpServletRequest request) throws AppException {
Expected: throw some error
Actual: converting true value for userId to string by jackson.
please let me know is there a way to acheive the Expected behaviour
回答1:
The jackson NumberDeserializers.BooleanDeserializer
is programmed to convert boolean to String.
We can override the deserializer with ours and prevent the conversion and throw an exception instead.
I can give you an example, you try to implement it to your problem statement.
- Create a boolean deserialize class
public class MyDeser extends JsonDeserializer {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonToken t = p.getCurrentToken();
if (t.isBoolean()) {
throw new Exception();
}
else if (t.isNumeric()) {
throw new Exception();
}
else if (t == JsonToken.VALUE_STRING) {
return p.getValueAsString();
}
return null;
}
}
- Now inject the deserializer to our application
@SpringBootApplication
@Configuration
public class Application {
@Bean
public SimpleModule injectDeser() {
return new SimpleModule().addDeserializer(String.class, new MyDeser());
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
回答2:
By default, com.fasterxml.jackson.databind.deser.std.StringDeserializer
accepts scalar values. You can implement custom deserialiser and throw exception in this case:
class StrictStringDeserializer extends StringDeserializer {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonToken token = p.currentToken();
if (token.isScalarValue()) {
ctxt.reportInputMismatch(String.class, "%s is not a `String` value!", token.toString());
return null;
}
return super.deserialize(p, ctxt);
}
}
To register it use SimpleModule
:
SimpleModule strictModule = new SimpleModule();
strictModule.addDeserializer(String.class, new StrictStringDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(strictModule);
To how to do that in Spring
read: Customize the Jackson ObjectMapper.
If you only want to change it for a one field: userId
use JsonDeserialize
annotation:
@JsonDeserialize(using = StrictStringDeserializer.class)
private String userId;
See also:
- Is it possible to use a custom serializer/deserializer for a type by default in spring?
来源:https://stackoverflow.com/questions/65439704/restrict-string-data-type-to-only-string-types-for-request-body-in-spring-boot-2