Restrict string data type to only string types for request body in Spring boot 2.4 (Jackson)

Tags: , , , ,



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

Answer

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.

  1. 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;
        }
    }

  1. 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);
         }
     }



Source: stackoverflow