Учитывая следующую базовую c модель домена:
abstract class BaseData { ... }
class DataA extends BaseData { ... }
class DataB extends BaseData { ... }
Я хочу написать конечную точку контроллера Spring MVC таким образом ...
@PostMapping(path="/{typeOfData}", ...)
ResponseEntity<Void> postData(@RequestBody BaseData baseData) { ... }
Требуемый конкретный тип baseData может быть выведен из typeOfData в пути.
Это позволяет мне иметь один метод, который может обрабатывать несколько URL-адресов с различными полезными нагрузками тела. У меня был бы конкретный тип для каждой полезной нагрузки, но я не хочу создавать несколько методов контроллера, которые все делают одно и то же (хотя каждый из них делает очень мало).
Проблема, с которой я сталкиваюсь, заключается в как «сообщить» процессу десериализации, чтобы был создан конкретный конкретный тип.
Я могу придумать два способа сделать это.
Сначала используйте пользовательский HttpMessageConverter
...
@Bean
HttpMessageConverter httpMessageConverter() {
return new MappingJackson2HttpMessageConverter() {
@Override
public Object read(final Type type, final Class<?> contextClass, final HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
// TODO How can I set this dynamically ?
final Type subType = DataA.class;
return super.read(subType, contextClass, inputMessage);
}
};
}
... что дает мне задачу определить подтип на основе HttpInputMessage
. Возможно, я мог бы использовать Filter
, чтобы установить пользовательский заголовок раньше, когда URL доступен для меня, или я мог бы использовать ThreadLocal
, также установленный через Filter
. Ни один из них не звучит идеально для меня.
Мой второй подход заключается в том, чтобы снова использовать Filter
и на этот раз обернуть входящую полезную нагрузку во внешний объект, который затем предоставит тип таким образом, который позволит Джексону выполнить работать через @JsonTypeInfo
. На данный момент это, вероятно, мой предпочтительный подход.
Я исследовал HandlerMethodArgumentResolver
, но если я пытаюсь зарегистрировать пользовательский, он регистрируется ПОСЛЕ RequestResponseBodyMethodProcessor
, и этот класс имеет приоритет.