【问题标题】:Restrict string data type to only string types for request body in Spring boot 2.4 (Jackson)在 Spring boot 2.4 (Jackson) 中将字符串数据类型限制为仅用于请求正文的字符串类型
【发布时间】:2021-04-02 23:41:38
【问题描述】:

我已经按如下方式创建了我的请求 POJO

@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;

当我如下发送请求正文时,它工作正常。

{
   "clientId":"9563",
    "userId":"5855541",
    "requestingService":"cm-dm-service",
    "message":"Document Created",
    "messageType":"user-msg"
}

但是当我像下面这样发送时

{
   "clientId":"9563",
    "userId":true,
    "requestingService":"cm-dm-service",
    "message":"Document Created",
    "messageType":"user-msg"
}

这是我的控制器

public ResponseEntity<Status> createNotification(@RequestBody @Valid Notification notification,
            BindingResult bindingResult, HttpServletRequest request) throws AppException {

预期:抛出一些错误

实际:将 userIdtrue 值转换为 jackson 的字符串。

请告诉我是否有办法实现预期行为

【问题讨论】:

标签: java json spring spring-boot jackson


【解决方案1】:

jackson NumberDeserializers.BooleanDeserializer 被编程为将布尔值转换为字符串。

我们可以用我们的重写反序列化器并阻止转换并抛出异常。

我可以给你一个例子,你试着在你的问题陈述中实现它。

  1. 创建一个布尔反序列化类

    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. 现在将反序列化程序注入我们的应用程序

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

【讨论】:

  • 这里 t.asString() 返回 null。所以我使用了 p.getValueAsString();并将返回类型更改为字符串。公共字符串反序列化(.....)。执行此操作后,代码按预期工作正常。谢谢 Srinivasa Raghavan。
  • 您好,我已经按照您的说法进行了编辑。如果这是您要求的解决方案,请接受此答案作为解决方案,以便对其他人也有用。谢谢
【解决方案2】:

默认情况下,com.fasterxml.jackson.databind.deser.std.StringDeserializer 接受标量值。在这种情况下,您可以实现自定义反序列化器并抛出异常:

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

要注册它,请使用SimpleModule:

SimpleModule strictModule = new SimpleModule();
strictModule.addDeserializer(String.class, new StrictStringDeserializer());

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(strictModule);

如何在Spring 阅读:Customize the Jackson ObjectMapper

如果您只想为一个字段更改它:userId 使用 JsonDeserialize 注释:

@JsonDeserialize(using = StrictStringDeserializer.class)
private String userId;

另见:

【讨论】:

    猜你喜欢
    • 2022-11-24
    • 2019-01-23
    • 2021-08-10
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多