Désérialiseur JSON personnalisé Spring @RestController

Je souhaite utiliser le désérialiseur JSON personnalisé pour certaines classes ( Role here) mais je ne parviens pas à le faire fonctionner Le désérialiseur personnalisé n’est tout simplement pas appelé.

J’utilise Spring Boot 1.2.

Désérialiseur:

public class ModelDeserializer extends JsonDeserializer { @Override public Role deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { return null; // this is what should be called but it isn't } } 

Manette:

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

     @JsonDeserialize(using = ModelDeserializer.class) public class Role extends Model { } 
  2. Bean Jackson2ObjectMapperBuilder dans Java Config

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

Qu’est-ce que je fais mal?

EDIT C’est probablement causé par @RestController car cela fonctionne avec @Controller

Tout d’abord, vous n’avez pas besoin de remplacer Jackson2ObjectMapperBuilder pour append un désérialiseur personnalisé. Cette approche doit être utilisée lorsque vous ne pouvez pas append d’annotation @JsonDeserialize . Vous devez utiliser @JsonDeserialize ou substituer Jackson2ObjectMapperBuilder .

Ce qui manque, c’est l’annotation @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 { @Override public Role deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // ................. return something; } } 

Il existe également une autre solution intéressante qui peut être utile si vous souhaitez modifier votre corps JSON avant d’appeler le désérialiseur par défaut. Et imaginons que vous deviez utiliser un bean supplémentaire pour cela (utilisez le mécanisme @Autowire )

Imaginons que vous ayez le contrôleur suivant:

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

OrderProductInterface est:

 @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{} 

Le code ci-dessus fournira une base de désérialisation dynamic sur le type de providerType déposé et une validation selon une implémentation concrète. Pour une meilleure compréhension, considérez que OrderProductForARequestData peut être quelque chose comme ça:

 public class OrderProductForARequestData implements OrderProductInterface { @NotBlank(message = "is mandatory field.") @Getter @Setter private Ssortingng providerId; @NotBlank(message = "is mandatory field.") @Getter @Setter private Ssortingng providerType; @NotBlank(message = "is mandatory field.") @Getter @Setter private Ssortingng productToOrder; } 

Et imaginons maintenant que nous voulons lancer en quelque sorte providerType (enrichir l’entrée) avant que la désérialisation par défaut ne soit exécutée. ainsi, l’object sera désérialisé correctement conformément à la règle de OrderProductInterface . Pour ce faire, vous pouvez simplement modifier votre classe @Configuration de la manière suivante:

 //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"); Ssortingng 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.toSsortingng()); newParser.nextToken(); return super.deserializeWithType(newParser, context, typeDeserializer); } } }