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

那年仲夏 提交于 2021-01-27 13:29:10

问题


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.

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




回答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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!