Java Spring@RestController自定义JSON反序列化器

Java Spring@RestController自定义JSON反序列化器,java,spring,rest,jackson,spring-boot,Java,Spring,Rest,Jackson,Spring Boot,我想对某些类使用自定义JSON反序列化程序(Role),但无法使其正常工作。只是没有调用自定义反序列化程序 我使用Spring Boot 1.2 反序列化程序: public class ModelDeserializer extends JsonDeserializer<Role> { @Override public Role deserialize(JsonParser jsonParser, DeserializationContext deserializ

我想对某些类使用自定义JSON反序列化程序(Role),但无法使其正常工作。只是没有调用自定义反序列化程序

我使用Spring Boot 1.2

反序列化程序:

public class ModelDeserializer extends JsonDeserializer<Role> {

    @Override
    public Role deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        return null; // this is what should be called but it isn't
    }
}
  • @JsonDeserialize
    关于角色

    @JsonDeserialize(using = ModelDeserializer.class)
    public class Role extends Model {
    
    }
    
  • Jackson2ObjectMapperBuilder
    Java配置中的bean

    @Bean
    public Jackson2ObjectMapperBuilder jacksonBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.deserializerByType(Role.class, new ModelDeserializer());
        return builder;
    }
    
  • 我做错了什么


    EDIT这可能是由
    @RestController
    引起的,因为它与
    @Controller
    一起工作。

    首先,您不需要覆盖
    Jackson2ObjectMapperBuilder来添加自定义反序列化程序。当您无法添加
    @JsonDeserialize
    注释时,应该使用这种方法。您应该使用
    @JsonDeserialize
    或重写
    Jackson2ObjectMapperBuilder

    缺少的是
    @RequestBody
    注释:

    @RestController
    public class JacksonCustomDesRestEndpoint {
    
        @RequestMapping(value = "/role", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
        @ResponseBody
        public Object createRole(@RequestBody Role role) {
            return role;
        }
    }
    
    @JsonDeserialize(using = RoleDeserializer.class)
    public class Role {
        // ......
    }
    
    public class RoleDeserializer extends JsonDeserializer<Role> {
        @Override
        public Role deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            // .................
            return something;
        }
    }
    
    @RestController
    公共类JacksonCustomDesRestEndpoint{
    @RequestMapping(value=“/role”,method=RequestMethod.POST,consumes=MediaType.APPLICATION\u JSON\u value,products=MediaType.APPLICATION\u JSON\u value)
    @应答器
    公共对象createRole(@RequestBody角色){
    返回角色;
    }
    }
    @JsonDeserialize(使用=roledSerializer.class)
    公共阶级角色{
    // ......
    }
    公共类RoleDeserializer扩展JsonDeserializer{
    @凌驾
    公共角色反序列化(JsonParser jp,反序列化上下文ctxt)引发IOException,JsonProcessingException{
    // .................
    归还某物;
    }
    }
    
    还有另一个非常有趣的解决方案,当您想在调用默认反序列化程序之前修改JSON正文时,它会很有帮助。让我们设想一下,您需要为此使用一些额外的bean(使用
    @Autowire
    机制)

    让我们想象一下这样的情况,即您拥有以下控制器:

    @RequestMapping(value = "/order/product", method = POST)
    public <T extends OrderProductInterface> RestGenericResponse orderProduct(@RequestBody @Valid T data) {
        orderService.orderProduct(data);
        return generateResponse();
    }
    
    上面的代码将提供基于field
    providerType
    的动态反序列化,并根据具体实现进行验证。为了更好地理解,请考虑<代码>订单产品> QuestDATABO/<代码>可以是这样的:

    public class OrderProductForARequestData implements OrderProductInterface {
    
        @NotBlank(message = "is mandatory field.")
        @Getter @Setter
        private String providerId;
    
        @NotBlank(message = "is mandatory field.")
        @Getter @Setter
        private String providerType;
    
        @NotBlank(message = "is mandatory field.")
        @Getter @Setter
        private String productToOrder;
    
    }
    
    现在让我们想象一下,在执行默认反序列化之前,我们希望以某种方式初始化
    providerType
    (丰富输入)因此对象将根据
    OrderProductInterface
    中的规则正确反序列化。 为此,您可以通过以下方式修改
    @配置
    类:

    //here can be any annotation which will enable MVC/Boot 
    @Configuration
    public class YourConfiguration{
    
        @Autowired
        private ObjectMapper mapper;
    
        @Autowired
        private ProviderService providerService;
    
        @Override
        public void setup() {
            super.setup();
            SimpleModule module = new SimpleModule();
            module.setDeserializerModifier(new BeanDeserializerModifier() {
                @Override
                public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
    
                    if (beanDesc.getBeanClass() == OrderProductInterface.class) {
                        return new OrderProductInterfaceDeserializer(providerService, beanDesc);
                    }
                    return deserializer;
                }
            });
    
            mapper.registerModule(module);
        }
    
        public static class OrderProductInterfaceDeserializer extends AbstractDeserializer {
    
                private static final long serialVersionUID = 7923585097068641765L;
    
                private final ProviderService providerService;
    
                OrderProductInterfaceDeserializer(roviderService providerService, BeanDescription beanDescription) {
                    super(beanDescription);
                    this.providerService = providerService;
                }
    
                @Override
                public Object deserializeWithType(JsonParser p, DeserializationContext context, TypeDeserializer typeDeserializer) throws IOException {
                    ObjectCodec oc = p.getCodec();
                    JsonNode node = oc.readTree(p);
    
                    //Let's image that we have some identifier for provider type and we want to detect it
                    JsonNode tmp = node.get("providerId");
                    Assert.notNull(tmp, "'providerId' is mandatory field");
                    String providerId = tmp.textValue();
                    Assert.hasText(providerId, "'providerId' can't be empty");
    
                    // Modify node
                    ((ObjectNode) node).put("providerType",providerService.getProvider(providerId));
    
                    JsonFactory jsonFactory = new JsonFactory();
                    JsonParser newParser = jsonFactory.createParser(node.toString());
                    newParser.nextToken();
    
                    return super.deserializeWithType(newParser, context, typeDeserializer);
    
               }
    
          }
    }
    
    //这里可以是启用MVC/Boot的任何注释
    @配置
    公共类配置{
    @自动连线
    私有对象映射器映射器;
    @自动连线
    私人供应商服务供应商服务;
    @凌驾
    公共作废设置(){
    super.setup();
    SimpleModule=新的SimpleModule();
    module.setDeserializerModifier(新的BeanDeserializerModifier(){
    @凌驾
    公共JsonDeserializer modifyDeserializer(反序列化配置、BeanDescription BeanDeserializer、JsonDeserializer反序列化程序){
    if(beanDesc.getBeanClass()==OrderProductInterface.class){
    返回新的OrderProductInterfacedSerializer(providerService,beanDesc);
    }
    返回反序列化器;
    }
    });
    映射器注册表模块(模块);
    }
    公共静态类OrderProductInterfacedSerializer扩展了抽象反序列化程序{
    私有静态最终长serialVersionUID=7923585097068641765L;
    私人最终供应商服务供应商服务;
    OrderProductInterfacedSerializer(roviderService providerService,BeanDescription BeanDescription){
    超级(beanDescription);
    this.providerService=providerService;
    }
    @凌驾
    公共对象deserializeWithType(JsonParser p,DeserializationContext上下文,TypeDeserializer TypeDeserializer)引发IOException{
    ObjectCodec oc=p.getCodec();
    JsonNode=oc.readTree(p);
    //让我们想象一下,我们有一些提供程序类型的标识符,我们想检测它
    JsonNode tmp=node.get(“providerId”);
    Assert.notNull(tmp,“'providerId'是必填字段”);
    字符串providerId=tmp.textValue();
    Assert.hasText(providerId,“'providerId'不能为空”);
    //修改节点
    ((ObjectNode)node.put(“providerType”,providerService.getProvider(providerId));
    JsonFactory JsonFactory=新的JsonFactory();
    JsonParser newParser=jsonFactory.createParser(node.toString());
    newParser.nextToken();
    返回super.deserializeWithType(newParser、context、typeDeserializer);
    }
    }
    }
    
    我也需要这样做,唯一的区别是我有一个get方法,在我的pojo对象中,我使用带有@JsonDeserialize的日期类型,但当我运行该方法时,我会得到一个http 400。(春季4.1.7 y杰克逊2.7.4)
    public class OrderProductForARequestData implements OrderProductInterface {
    
        @NotBlank(message = "is mandatory field.")
        @Getter @Setter
        private String providerId;
    
        @NotBlank(message = "is mandatory field.")
        @Getter @Setter
        private String providerType;
    
        @NotBlank(message = "is mandatory field.")
        @Getter @Setter
        private String productToOrder;
    
    }
    
    //here can be any annotation which will enable MVC/Boot 
    @Configuration
    public class YourConfiguration{
    
        @Autowired
        private ObjectMapper mapper;
    
        @Autowired
        private ProviderService providerService;
    
        @Override
        public void setup() {
            super.setup();
            SimpleModule module = new SimpleModule();
            module.setDeserializerModifier(new BeanDeserializerModifier() {
                @Override
                public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
    
                    if (beanDesc.getBeanClass() == OrderProductInterface.class) {
                        return new OrderProductInterfaceDeserializer(providerService, beanDesc);
                    }
                    return deserializer;
                }
            });
    
            mapper.registerModule(module);
        }
    
        public static class OrderProductInterfaceDeserializer extends AbstractDeserializer {
    
                private static final long serialVersionUID = 7923585097068641765L;
    
                private final ProviderService providerService;
    
                OrderProductInterfaceDeserializer(roviderService providerService, BeanDescription beanDescription) {
                    super(beanDescription);
                    this.providerService = providerService;
                }
    
                @Override
                public Object deserializeWithType(JsonParser p, DeserializationContext context, TypeDeserializer typeDeserializer) throws IOException {
                    ObjectCodec oc = p.getCodec();
                    JsonNode node = oc.readTree(p);
    
                    //Let's image that we have some identifier for provider type and we want to detect it
                    JsonNode tmp = node.get("providerId");
                    Assert.notNull(tmp, "'providerId' is mandatory field");
                    String providerId = tmp.textValue();
                    Assert.hasText(providerId, "'providerId' can't be empty");
    
                    // Modify node
                    ((ObjectNode) node).put("providerType",providerService.getProvider(providerId));
    
                    JsonFactory jsonFactory = new JsonFactory();
                    JsonParser newParser = jsonFactory.createParser(node.toString());
                    newParser.nextToken();
    
                    return super.deserializeWithType(newParser, context, typeDeserializer);
    
               }
    
          }
    }