Существует также еще довольно интересное решение, которое может быть полезным в случае, если вы хотите изменить JSON тело перед вызовом по умолчанию десериализации. А давайте представим, что вам нужно использовать некоторый дополнительный боб для этого (использования @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);
}
}
}
мне нужно сделать то же самое, с той лишь разницей, что у меня есть метод получить и в моем объекте Pojo я использую тип Date с @JsonDeserialize, но когда я запускаю метод, я получаю http 400. (весна 4.1.7 y jackson 2.7.4) – Hector