Как стать автором
Обновить

Комментарии 6

Попросили у джависта прикурить, а он фабрику для зажигалок строит

Это первое, что вспомнилось после прочтения статьи. Уж больно сложный способ решения не самой сложной задачи. Понятно, что статья учебная, но подход крайне спорный и можно научить не тому.

Помимо целесообразности такой магии, есть и другие вопросы. Например, что будет, если мы хотим применить механизм для двух разных классов и написали два сервиса WrapperServiceClass1Impl и WrapperServiceClass2Impl? Судя по коду, spring не сможет заинджектить вот сюда:

private final IWrapperService wrapperService;

Что, если нам мало в сервисе только объекта для получения дополнительной информации, а нужен например еще параметр из request или еще откуда-то?

Еще есть пожелание не использовать везде Object, generic же есть.

И да, не стоит использовать I в начале имен интерфейсов - это не C# (https://stackoverflow.com/questions/541912/interface-naming-in-java)

По поводу решения сложным способом не самой сложной задачи - тут двоякий момент, так как по итогу мы имеем просто стартер. А, как говориться, мой стартер всегда со мной. Если проблема в одном месте - данный подход, скорее всего, не имеет смысла использовать. Однако применению такого подхода можно найти множества - различные дополнительные обработки ответов точек входа - это не обязательно обертка ответов. Данный подход скорее ближе к AOP для узкого места применения - и наследует от этого подхода как положительные стороны, так и отрицательные

По поводу реализации интерфейса двумя классами - да, вы совершенно правы, в данном случае проект не запустится с ошибкой спринга о том, что 2 класса претендуют на место 1 бина. Так как это pet проект, то я намеренно не стал обрабатывать данный exception (хотя мне кажется, нет большой необходимости это делать в стартере) и оставил ответственность на человека, использующего стартер. Проблему можно довольно просто решить с помощью использования @Primary . Так же возможным решением будет использование @Qualifier на стороне стартера

Что, если нам мало в сервисе только объекта для получения дополнительной информации, а нужен например еще параметр из request или еще откуда-то?

Вы в праве доработать стартер до того, что необходимо вам в вашей задачи. К тому же, метод beforeBodyWrite дает большие возможности в функциональном его использовании. Среди параметров есть и ServerHttpRequest request, ServerHttpResponse response

Проблему можно довольно просто решить с помощью использования @Primary . Так же возможным решением будет использование @Qualifier на стороне стартера

Смотрите, если механизм вынесен в стартер, то подразумевается, что он универсальный и не зависит от проекта. Так вот, я хочу его использовать в проекте для двух разных классов и соотв. для двух разных сервисов. Не вижу в этом чего-то исключительного. И вот тут у меня ничего не получится, т.к. есть ограничение в коде стартера.

Вы в праве доработать стартер до того, что необходимо вам в вашей задачи.

Опять же, с моей точки зрение, если вынесено в стартер, то это что-то универсальное. В одном проекте параметр нужен, в другом - нет. И что с этим делать? Плодить методы на все случаи в интерфейсе сервиса?

Я все это про то, что на мой взгляд решение получилось несильно гибкое и не очень универсальное.

Есть еще момент. Представьте, что в вашем коде будет разбираться человек, который не в курсе стартера. Он запускает код и видит ответ, который отличается от того, который явно прописан в коде контроллера. Первая реакция - что-то не то смотрю. Потом человек замечает аннотацию (благодаря куче аннотаций lombok и spring это не сразу бросается в глаза), судорожно ищет по проекту код, который ее обрабатывает и не находит. И только потом он может заметить стартер и выкачать его исходники (если они ему доступны) и разобраться что все таки происходит.

Как вариант, можно просто отнаследовать обертку от исходного класса и возвращать дополнительные поля в ней, заполняя явно в сервисе (который будет вызываться в контроллере) или неявно, повесив на этот сервис аспект с аннотацией.

Смотрите, если механизм вынесен в стартер, то подразумевается, что он универсальный и не зависит от проекта

Необязательно. Для проектов автора стартер вполне может быть универсальным в нужной ему степени. Библиотеки постоянно совершенствуется, первые версии необязательно будут идеальными и "универсальными".

Я все это про то, что на мой взгляд решение получилось несильно гибкое и не очень универсальное

Автор, скорее всего, преследовал другие цели: бегло продемонстрировать "фишки" Spring'а. А как ими правильно пользоваться – остаётся на совести читателя :)

Есть еще момент. Представьте, что в вашем коде будет разбираться человек, который не в курсе стартера. Он запускает код и видит ответ, который отличается от того, который явно прописан в коде контроллера.

Я бы поспорил, что это дело вкуса: работаешь со Spring'ом, будь готов к такого рода чудесам и ищи глазками все эти стартеры, аннотации и прочие прелести. Да и без аннотаций порой такой код приходится читать, что без пары стопок не разберёшь :)

TLDR: я бы сказал, что автор просто захотел поделиться своими знаниями Spring'а, опытным программистам данная статья вряд ли понадобится, а кто позеленее может и скажет, прочитав статью, "Ого как можно, пойду стряпать в своем проекте такое же" :)

Библиотеки постоянно совершенствуется, первые версии необязательно будут идеальными и "универсальными".

Я просто не понимаю зачем выносить в стартер то, что нужно только в конкретном проекте. Ковыряйте в проекте, когда устранили все недочеты и поняли, что вот эта часть может быть обобщена, обособлена и полезна в других проектах, тогда да - в стартер или либу.

а кто позеленее может и скажет, прочитав статью, "Ого как можно, пойду стряпать в своем проекте такое же" :)

Именно поэтому я прицепился. Я выше писал, что понимаю, что статья учебная. Но неопытному разработчику может показаться, что этот подход самый правильный и так и надо делать. А он вот далеко не самый правильный и чем меньше будет такой магии тем лучше, на мой взгляд. А так человек прочтет статью, потом почитает комменты с альтернативной точкой зрения и включит голову.

Спасибо за ваш комментарий! Согласен, что универсальность теряется из-за невозможности использования различных реализаций для различных классов-оберток. Добавил комментарий про этот момент в статью

Данную негибкость возможно решить, например, при помощи инжекта мапы с сервисами. Однако, при реализации оказалось, что изменения довольно сильно усложняют проект в рамках целей статьи. Поэтому я не стал включать изменения в статью и проект

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории