【问题标题】:Spring @RestController custom JSON deserializerSpring @RestController 自定义 JSON 反序列化器
【发布时间】:2015-02-17 11:08:45
【问题描述】:

我想为某些类(Role 这里)使用自定义 JSON 反序列化器,但我无法让它工作。只是没有调用自定义反序列化程序。

我使用 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
    }
}

控制器:

@RestController
public class RoleController {

    @RequestMapping(value = "/role", method = RequestMethod.POST)
    public Object createRole(Role role) {
        // ... this is called
    }
}
  1. @JsonDeserialize 角色

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

    @Bean
    public Jackson2ObjectMapperBuilder jacksonBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.deserializerByType(Role.class, new ModelDeserializer());
        return builder;
    }
    

我做错了什么?

EDIT这可能是由@RestController引起的,因为它适用于@Controller...

【问题讨论】:

    标签: java spring rest jackson spring-boot


    【解决方案1】:

    首先,您无需重写 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;
        }
    }
    

    【讨论】:

    • 我需要做同样的事情,唯一的区别是我有一个 get 方法,在我的 pojo 对象中我使用带有 @JsonDeserialize 的 Date 类型,但是当我运行该方法时,我得到一个 http 400 . (spring 4.1.7 y jackson 2.7.4)
    【解决方案2】:

    还有另一个非常有趣的解决方案,如果您想在调用默认反序列化器之前修改 JSON 主体,它会很有帮助。让我们假设您需要为此使用一些额外的 bean(使用 @Autowire 机制)

    让我们想象一下你有以下控制器的情况:

    @RequestMapping(value = "/order/product", method = POST)
    public <T extends OrderProductInterface> RestGenericResponse orderProduct(@RequestBody @Valid T data) {
        orderService.orderProduct(data);
        return generateResponse();
    }
    

    OrderProductInterface 在哪里:

    @JsonIgnoreProperties(ignoreUnknown = true)
    @JsonSerialize(include = NON_EMPTY)
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, visible = true, property = "providerType")
    @JsonSubTypes({
                  @JsonSubTypes.Type(value = OrderProductForARequestData.class, name = "A")
              })
    public interface OrderProductInterface{}
    

    上面的代码将提供基于providerType的动态反序列化,并根据具体实现进行验证。为了更好地掌握,请考虑OrderProductForARequestData 可以是这样的:

    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 中的规则正确反序列化。 为此,您可以通过以下方式修改您的 @Configuration 类:

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

    【讨论】:

      猜你喜欢
      • 2022-07-21
      • 2018-02-19
      • 2011-04-12
      • 2016-12-31
      • 2019-06-14
      • 1970-01-01
      • 2016-01-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多