Подавал через госуслуги, но приходил отказ по причине проблем взаимодействия межведомственных сервисов; но была назначена дата приема для разъяснения отказа. Вот на этом приеме мой представитель передал распечатанные (не заверенные) сканы документов, которые я прислал в электронном виде и снял меня с учета без вопросов. Как выяснилось - они (мой военкомат) специально шлют отказ, чтобы все приходили лично и разбираться так проще)
Я пользовался - сделал там зеркала парочки реп с Github. Некоторые элементы интерфейса имеют странный перевод («опасность» например, в настройках репозитория); Но зато, зеркалирование там бесплатное - (по крайней мере на данный момент), тех поддержка отвечает на письма, интерфейс по сути как дословно переведенный GitHub. В целом для моих задач - отличный сервис.
Позвольте вмешаться, про инъекции с вами согласен, но не в этом конкретном примере. У автора метод принимает коллекцию из различных Long и скорее всего в этом случае не найдется никакого long значения = «1);DROP DATABASE;--».
Благодарю за хороший ответ. Точно также, как это реализовано у Вас сейчас, с небольшими изменениями. Вы создаете новый TaskListener в методе init() Вашего процессора; я лишь хотел показать, что инициализировать TaskListener можно иначе, тогда AbstractProcessor не нужен. К сожалению сейчас не обладаю достаточным временем, чтобы написать что-то конкретное по Вашему примеру. Но, в общих словах: Сейчас логика поиска нужных элементов по аннотирпованным классам и реализация проверки у Вас реуализована в SwitchExhaustiveCheckerProcessor и TestMethodTreePathScanner Можете просто объединить эту логику в одном Вашем TestMethodTreePathScanner - это конечно очень некрасиво и лучше бы потом отрефакторить и разбить ответственности, но зато позволит быстрее опробовать другой подход. Далее можно в самом AnalyzeTaskListener имплементить визитера TestMethodTreePathScanner к каждому элементу и все должно быть ОК, хотя чую, что с первого раза все не заведется, учитывая что пока предлдожение абстрактное.
class AnalyzeTaskListener implements TaskListener {
private final SwitchExhaustiveCheckerProcessor processor;
AnalyzeTaskListener() {}
@Override
public void started(TaskEvent taskEvent) {
}
@Override
public void finished(final TaskEvent e) {
if (e.getKind() != TaskEvent.Kind.ANALYZE) {
return;
}
CompilationUnitTree compilationUnit = event.getCompilationUnit();
if (compilationUnit == null) {
return;
}
compilationUnit.accept(scanningVisitor, null);
}
}
А в самом плагине уже проинициализировать AnalyzeTaskListener как писали ранее. Если нужны какие-нибудь утилитные класссы, наподобии тех , что используются у Вас в процессоре или визитере, то можно в классе плагина их проинициализировать и передать через конструктор AnalyzeTaskListener далее. Например ``
…
@Override
public void init(JavacTask task, String... args) {
final Context context = ((BasicJavacTask)task).getContext();
Log log = Log.instance(context);
}
...
Приветствую! Спасибо за статью. Интересная проблема и решение через обработку аннотаций) В свое время тоже столкнулся с подобной проблемой поведения AnnotationProcessor и реализовал через такой же хак, чтобы достучатся до переменных внутри методов в одном пет проекте - https://ololx.github.io/cranberry/cranberry-statement/.
Позвольте мне немного дополнить статью и задать вопрос.
В Java 8+ можно зарегистрировать кастомный TaskListener через свою реализацию com.sun.source.util.Plugin; В вашем случае это выглядело бы следующим образом: 1 - Написать свою реализацию Plugin вместо SwitchExhaustiveCheckerProcessor
public class SwitchExhaustiveChecker implements Plugin {
@Override
public String getName() {
return "SwitchExhaustiveCheckerPlugin";
}
@Override
public void init(JavacTask task, String... args) {
task.addTaskListener(new AnalyzeTaskListener());
}
}
2 - Зарегистрировать свой плагин в …/src/main/resources/META-INF/services/com.sun.source.util.Plugin ( аналогично тому, как Вы регистрировали свой процессор)
Это пример подобного плагина, который я смог найти на github (надеюсь, что авто рне будет против за то, что выложил лине) - https://github.com/moditect/deptective
Вопрос: Рассматривали ли Вы описанный мной способ реализации Вашей задачи? Если - да, то почему остановились на своем варианте - чем он показался Вам выигрышней?
Все куда проще - именно продюсера на spring-cloud-stream который вызывался непосредственно после успешной манипуляции с сущностью; написал ДТО по образу того, что есть в debezium (поля T before, T after + метод, который по соотношению значений полей определяет тип события - delete, update и create). Что хорошего в такой реализации - можно по необходимости Google Protobuff применить.
Получается при возникновении события в сервисе (например создании сущности) создается инстанс ДТО, с before = null, after = объект; ДТО поститься в кафку; ну а далее уже консьюмеры отрабатывают. На тот момент это было быстрее, чем разбираться с debezium до конца.
Спасибо за статью, очень полезная. Года 2 назад уже рассматривал debezium, с СУБД mysql все работало хорошо по мануалам, но с postgresql не получилось никак реализовать CDC. Поэтому писал реализацию CDC уже сам под каждый конкретный сервис - у сервиса (master data) пишется продюсер для кафки, а у зависимых (slave) сервисов уже консьюмеры.
Но благодаря Вашей статье решил попробовать debezium снова, тем более за два года могло многое измениться)
Да, при помощи open tracing, настроил отправку данных трассировки на развернутый сервис Jaeger. А сам Jaeger подключил как datasource в Graphana; по мимо Jaeger просто собираем статы с prometheus и loki.
Согласен, но в поддержку автора добавлю, что у меня был опыт работы с «обиженной крошкой»; правда не из-за ревью, но суть в том, что открытый конфликт реально помог, когда мы друг другу высказали все в лицо) после чего перекурили и спокойно продолжили работать без всяких обид. Это было на стадии притирки команды, но иногда такие вот открытые споры и даже конфликты намного лучше постоянно пассивной агрессии от коллеги; причем когда еще и из подтяжка)
Интересная статья, был опыт реализации REST-сервиса для индексов на Sphinx для поиска адреса с опечатками.
Спасибо автору за осознание того, что я мог выбросит на помойку свой REST, поскольку Sphinx может столько же и даже лучше =)
На самом деле можно реализовать еще проще: как Optional + Jackson ObjectMapper для простого частичного обновления сущности из ДТО.
У меня есть подробный пример реализации метода PATCH при помощи такого подхода здесь https://github.com/ololx/restful-updating-instances; если Вам будет интересно.
В Вашем случае, это может выглядеть так:
Сущность (без аннотаций Hibernate):
@SneakyThrows
@PatchMapping(
path = "/{id}"
)
public UserDetail update(
@ApiParam(
name="id",
value = "The update user entity id",
required = true
) @PathVariable Long id,
@ApiParam(
name="updateUserRequest",
value = "The update user request",
required = true
) @RequestBody UserDetail updateUserRequest) {
UserModel user = this.userRepository.findById(id).orElse(null);
assertNotNull(user, String.format("User with id - {} is not existed", id));
objectMapper.updateValue(user, updateUserRequest);
this.userRepository.save(user);
UserDetail updateUserResponse = new UserDetail();
objectMapper.updateValue(updateUserResponse, user);
return updateUserResponse;
}
Где userRepository — обычный JpaRepository; а objectMapper — стандартный ObjectMapper.
Подавал через госуслуги, но приходил отказ по причине проблем взаимодействия межведомственных сервисов; но была назначена дата приема для разъяснения отказа. Вот на этом приеме мой представитель передал распечатанные (не заверенные) сканы документов, которые я прислал в электронном виде и снял меня с учета без вопросов.
Как выяснилось - они (мой военкомат) специально шлют отказ, чтобы все приходили лично и разбираться так проще)
Я пользовался - сделал там зеркала парочки реп с Github. Некоторые элементы интерфейса имеют странный перевод («опасность» например, в настройках репозитория); Но зато, зеркалирование там бесплатное - (по крайней мере на данный момент), тех поддержка отвечает на письма, интерфейс по сути как дословно переведенный GitHub. В целом для моих задач - отличный сервис.
Позвольте вмешаться, про инъекции с вами согласен, но не в этом конкретном примере. У автора метод принимает коллекцию из различных Long и скорее всего в этом случае не найдется никакого long значения = «1);DROP DATABASE;--».
Заметил кучу ошибок в примерах кода - не надо было спешить вчера.
Внесу небольшие правки, чтобы в будущем никог оне путать.
Благодарю за хороший ответ. Точно также, как это реализовано у Вас сейчас, с небольшими изменениями. Вы создаете новый TaskListener в методе init() Вашего процессора; я лишь хотел показать, что инициализировать TaskListener можно иначе, тогда AbstractProcessor не нужен. К сожалению сейчас не обладаю достаточным временем, чтобы написать что-то конкретное по Вашему примеру. Но, в общих словах:
Сейчас логика поиска нужных элементов по аннотирпованным классам и реализация проверки у Вас реуализована в
SwitchExhaustiveCheckerProcessor
иTestMethodTreePathScanner
Можете просто объединить эту логику в одном Вашем
TestMethodTreePathScanner
- это конечно очень некрасиво и лучше бы потом отрефакторить и разбить ответственности, но зато позволит быстрее опробовать другой подход. Далее можно в самом
AnalyzeTaskListener
имплементить визитераTestMethodTreePathScanner
к каждому элементу и все должно быть ОК, хотя чую, что с первого раза все не заведется, учитывая что пока предлдожение абстрактное.А в самом плагине уже проинициализировать
AnalyzeTaskListener
как писали ранее. Если нужны какие-нибудь утилитные класссы, наподобии тех , что используются у Вас в процессоре или визитере, то можно в классе плагина их проинициализировать и передать через конструкторAnalyzeTaskListener
далее.Например ``
Тут есть хорошие примеры кода для такого подхода - https://annimon.com/article/2626
Приветствую!
Спасибо за статью.
Интересная проблема и решение через обработку аннотаций)
В свое время тоже столкнулся с подобной проблемой поведения
AnnotationProcessor
и реализовал через такой же хак, чтобы достучатся до переменных внутри методов в одном пет проекте - https://ololx.github.io/cranberry/cranberry-statement/.Позвольте мне немного дополнить статью и задать вопрос.
В Java 8+ можно зарегистрировать кастомный
TaskListener
через свою реализацию com.sun.source.util.Plugin; В вашем случае это выглядело бы следующим образом:1 - Написать свою реализацию
Plugin
вместоSwitchExhaustiveCheckerProcessor
2 - Зарегистрировать свой плагин в
…/src/main/resources/META-INF/services/com.sun.source.util.Plugin
( аналогично тому, как Вы регистрировали свой процессор)3 - Для реализации такого плагина потребуется еще указать зависимость на JDK tools в Вашем
pom.xml
После чего можно использовать Ваш плагин, подключив его к проекту и указав аргумент в maven-compiler-plugin
Это пример подобного плагина, который я смог найти на
github
(надеюсь, что авто рне будет против за то, что выложил лине) - https://github.com/moditect/deptectiveВопрос: Рассматривали ли Вы описанный мной способ реализации Вашей задачи? Если - да, то почему остановились на своем варианте - чем он показался Вам выигрышней?
Скорее всего ничего, как и с автомобилями, которые были выпущены и куплены ранее под стандарты ЕВРО-2, и эксплуатируются при текущем ЕВРО-5.
Все куда проще - именно продюсера на spring-cloud-stream который вызывался непосредственно после успешной манипуляции с сущностью; написал ДТО по образу того, что есть в debezium (поля T before, T after + метод, который по соотношению значений полей определяет тип события - delete, update и create). Что хорошего в такой реализации - можно по необходимости Google Protobuff применить.
Получается при возникновении события в сервисе (например создании сущности) создается инстанс ДТО, с before = null, after = объект; ДТО поститься в кафку; ну а далее уже консьюмеры отрабатывают. На тот момент это было быстрее, чем разбираться с debezium до конца.
Спасибо за статью, очень полезная. Года 2 назад уже рассматривал debezium, с СУБД mysql все работало хорошо по мануалам, но с postgresql не получилось никак реализовать CDC. Поэтому писал реализацию CDC уже сам под каждый конкретный сервис - у сервиса (master data) пишется продюсер для кафки, а у зависимых (slave) сервисов уже консьюмеры.
Но благодаря Вашей статье решил попробовать debezium снова, тем более за два года могло многое измениться)
Недавно наткнулся еще и на embedded реализацию debezium и начал изучать этот вариант. Если интересно начало проекта тут - https://github.com/innopolis-university-java-team/change-data-capture-instances.
Да, при помощи open tracing, настроил отправку данных трассировки на развернутый сервис Jaeger. А сам Jaeger подключил как datasource в Graphana; по мимо Jaeger просто собираем статы с prometheus и loki.
Пока разбирался, сделал небольшой пет проект на эту тему для себя еще; если интересно, то он доступен тут - https://github.com/innopolis-university-java-team/spring-boot-metrics-instances
Благодарю, гляну, пока подключил postgres как datasource и создавал свои графики на основании служебных таблиц.
Спасибо за статью, как раз прикручиваю графики для postgres (не через Prometheus) в Graphana. Будет очень полезно.
Сразу вопрос: если уже настроена трассировка через тот же Jaeger, то чем этот способ лучше? В Jaeger же можно видеть запросы и их время выполнения.
Согласен, но в поддержку автора добавлю, что у меня был опыт работы с «обиженной крошкой»; правда не из-за ревью, но суть в том, что открытый конфликт реально помог, когда мы друг другу высказали все в лицо) после чего перекурили и спокойно продолжили работать без всяких обид. Это было на стадии притирки команды, но иногда такие вот открытые споры и даже конфликты намного лучше постоянно пассивной агрессии от коллеги; причем когда еще и из подтяжка)
Интересная статья, был опыт реализации REST-сервиса для индексов на Sphinx для поиска адреса с опечатками.
Спасибо автору за осознание того, что я мог выбросит на помойку свой REST, поскольку Sphinx может столько же и даже лучше =)
На самом деле можно реализовать еще проще: как Optional + Jackson ObjectMapper для простого частичного обновления сущности из ДТО.
У меня есть подробный пример реализации метода PATCH при помощи такого подхода здесь https://github.com/ololx/restful-updating-instances; если Вам будет интересно.
В Вашем случае, это может выглядеть так:
Сущность (без аннотаций
Hibernate
):ДТО для этой сущности:
Кусок реализации метода PATCH:
Где
userRepository
— обычный JpaRepository; аobjectMapper
— стандартный ObjectMapper.