Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Прикладная кодогенерация для Java разработчика

Прикладная кодогенерация для Java разработчика

Андрей Когунь (http://deeprefactoring.ru/speakers/andrey-kogun)

Java разработчики, особенно те, кто заняты в заказной разработке, находятся в постоянной борьбе за то, чтобы писать меньше бойлерплейт кода, будь то тривиальные геттеры-сеттеры, конструкторы и т.п. или CRUD репозитории и контроллеры и часто ответом является кодогенерация в разных видах: поддержка генерации в IDE, генерация байткода при помощи Lombok, процессоры аннотаций порождающие новый код, фреймворки, позволяющие по описанию модели получить готовое (почти) приложение и много чего еще, не исключая новые и не очень JVM языки, которые позволют писать более лаконичный код и реализовывать DSL-и для решения прикладных задач.

В докладе мы сделаем ретроспективу наиболее часто применяемых подходов, поговорим об их сильных сторонах, ограничениях и практической применимости, а главное, попробуем взять ситуацию с кодогенерацией под контроль, чтобы она стала реально полезным инструментом эффективного разработчика.

Видео: https://youtu.be/GFnqbPIAPrg

========================
"Глубокий Рефакторинг" - открытый клуб разработчиков и профессионалов IT-индустрии Воронежа, организующий доклады на профильные темы - http://deeprefactoring.ru/

Открытый чат: https://t.me/deeprefactoring
Новостной канал: https://t.me/deeprefactoring_news
Видео всех докладов - https://www.youtube.com/c/deeprefactoring
Слайды выступлений: https://speakerdeck.com/deeprefactoring

Группа FB - https://www.facebook.com/groups/deeprefactoring
Группа ВК - https://vk.com/deeprefactoring
===========================

80eadbf0a221aaa4b764854df32fb781?s=128

Deep Refactoring

June 26, 2019
Tweet

Transcript

  1. Deep refactoring 2019 ПРИКЛАДНАЯ КОДОГЕНЕРАЦИЯ ДЛЯ JAVA РАЗРАБОТЧИКА

  2. 2 # ЧТО ХОТИМ • Делать микросервисы (и монолиты) на

    Spring-e • Spring Framework • Spring Boot • Spring Data (JPA)
  3. 3 # Хотя, все происходит автомагически, не обойтись, без того,

    чтобы не написать немного кода: • Configuration • Entity • Repository • Service • Controller SPRING BOOT: МИНИМАЛЬНОЕ ПРИЛОЖЕНИЕ http://foxminded.com.ua/news/55-sravnenie-stekov-java-ee-i-spring-vozmozhnosti-i-ogranicheniya/
  4. 4 # А КАК ЭТО ОБЫЧНО ВЫГЛЯДИТ? @Entity public class

    User { @Id @GeneratedValue private Long id; @Transient private transient boolean isNew; @Column(nullable = false) private String name; }
  5. 5 # А КАК МЫ ХОТИМ? @Entity public class User

    { @Column(nullable = false) private String name; }
  6. 6 # А КАК МЫ ХОТИМ? @Entity class User {

    @Column(nullable = false) String name; }
  7. 7 # А КАК МЫ ХОТИМ? @Entity class User {

    @Column(nullable = false) String name @ManyToOne @Column(nullable = false) Country country }
  8. 8 # А КАК МЫ ХОТИМ? @Entity class User {

    @Column(nullable = false) String name @ManyToOne @Column(nullable = false) Country country }
  9. 9 # А КАК МЫ ХОТИМ? @Entity class User {

    @Column(nullable = false) String name @ManyToOne @JoinColumn(nullable = false) Country country }
  10. 10 # Когунь Андрей — хоккеист О СЕБЕ

  11. 11 # Когунь Андрей — хоккеист О СЕБЕ

  12. 12 # Когунь Андрей — программист • Работаю в компании

    КРОК • Провожу встречи Московского JUG @mskjug, #jugmsk • Преподаю Java О СЕБЕ
  13. 13 # Департамент разработки программного обеспечения • Заказная (в основном)

    разработка • Для “быстрой” разработки учетных систем реализован собственный фреймворк - jXFW О КРОК ДРПО
  14. 14 # О ЧЕМ ПОГОВОРИМ • Кодогенерация в IDE •

    Java Annotation Processing (apt) • Lombok • JavaPoet • Kotlin • Xtend
  15. 15 # КОДОГЕНЕРАЦИЯ В IDE • Итеративный (и не самый

    быстрый) процесс • Генерировать можно исходный java код, любые другие ресурсы https://youtu.be/EEAiyRuaUXU
  16. 16 # КАК РАБОТАЕТ ANNOTATION PROCESSING • Генерировать можно исходный

    java код, любые другие ресурсы • Процессор должен располагаться в отдельном от прикладного кода модуле • Процессор не может менять код, только создавать новый
  17. 17 # КАК РАБОТАЕТ ANNOTATION PROCESSING • Генерировать можно исходный

    java код, любые другие ресурсы • Процессор должен располагаться в отдельном от прикладного кода модуле • Процессор не может менять код, только создавать новый • Итеративный (и не самый быстрый) процесс
  18. 18 # ПРИМЕРЫ РЕАЛИЗАЦИИ ANNOTATION PROCESSING • Dagger (Android) •

    ButterKnife (Android) • QueryDSL (JPA)
  19. 19 # ДЕЛАЕМ СВОЙ PROCESSOR ДЛЯ ENTITY @AutoService(Processor.class) public class

    EntityProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); // processingEnv.getFiler(); // processingEnv.getMessager(); } @Override public Set<String> getSupportedAnnotationTypes() { Set<String> set = new HashSet<>(); set.add(Entity.class.getCanonicalName()); return set; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } }
  20. 20 # ДЕЛАЕМ СВОЙ PROCESSOR ДЛЯ ENTITY @AutoService(Processor.class) public class

    EntityProcessor extends AbstractProcessor { … @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (TypeElement annotation : annotations) { Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation); // … } return true; } }
  21. 21 # ДЕЛАЕМ СВОЙ PROCESSOR ДЛЯ ENTITY … @Override public

    boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { … JavaFileObject repositoryFile = filer.createSourceFile(repositoryClassName); try (PrintWriter out = new PrintWriter(repositoryFile.openWriter())) { if (packageName != null) { out.print("package "); out.print(packageName); out.println(";"); out.println(); } out.print("public class "); out.print(repositorySimpleClassName); out.println(" {"); out.println(); … } }
  22. 22 # НУ ЭТИ JAVA ПРОГРАММИСТЫ, НУ ВЫ ЗНАЕТЕ…

  23. 23 # УЛУЧШАЕМ ПОДДЕРЖКУ ГЕНЕРАЦИИ ИСХОДНОГО JAVA КОДА • JavaPoet

    - https://github.com/square/javapoet MethodSpec setQueryParamsBuilderFactory = MethodSpec .methodBuilder("setQueryParamsBuilderFactory") .addModifiers(Modifier.PUBLIC) .addParameter(QueryParamsBuilderFactory.class, "queryParamsBuilderFactory") .addStatement("this.queryParamsBuilderFactory = queryParamsBuilderFactory") .addAnnotation(Autowired.class) .build();
  24. 24 # ДЕЛАЕМ СВОЙ PROCESSOR ДЛЯ ENTITY C JAVAPOET …

    @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { … JavaFile.builder(repository, typeSpec) .build() .writeTo(filer); }
  25. 26 # APT + LOMBOK? • Можно пользоваться готовыми аннотациями

    • А можно сделать свою: @MetaInfServices(JavacAnnotationHandler.class) public class EntityJavacHandler extends JavacAnnotationHandler<Entity> { }
  26. 27 # APT + LOMBOK? • Удачи с JCTree This

    is NOT part of any supported API. If you write code that depends on this, you do so at your own risk. This code and its internal interfaces are subject to change or deletion without notice. public void handle(AnnotationValues<Entity> annotation, JCTree.JCAnnotation ast, JavacNode annotationNode) { Context context = annotationNode.getContext(); Javac8BasedLombokOptions options = Javac8BasedLombokOptions.replaceWithDelombokOptions(context); options.deleteLombokAnnotations(); JavacHandlerUtil.deleteAnnotationIfNeccessary(annotationNode, Entity.class); …
  27. 28 # APT + LOMBOK? • JCTree • С этим

    разбирается Шерлок зато, с вашим кодом будет разбираться Шерлок Это больно и неприятно,
  28. 29 # МОЖЕТ, НАПИШЕМ СВОЙ ЯЗЫК? • Описываем доменную модель

    на собственном диалекте • Реализуем maven (gradle) плагин • Генерацию запускаем из IDE
  29. 30 # МОЖЕТ, НАПИШЕМ СВОЙ ЯЗЫК? • Описываем доменную модель

    на собственном диалекте • Реализуем maven (gradle) плагин • Генерацию запускаем из IDE • Иван Пономарев, КУРС – JavaCC + JavaPoet
  30. 31 # МОЖЕТ, НАПИШЕМ СВОЙ ЯЗЫК? • Описываем доменную модель

    на собственном диалекте • Реализуем maven (gradle) плагин • Генерацию запускаем из IDE • Иван Пономарев, КУРС – JavaCC + JavaPoet
  31. 32 # А ЧТО KOTLIN?

  32. 33 # А ЧТО KOTLIN? apt -> kapt

  33. 34 # А ЧТО KOTLIN KAPT? @Entity data class User

    { val name: String } • kotlin-metadata • KotlinPoet
  34. 35 # А ЧТО KOTLIN? • Есть возможность реализовать плагин

    для компилятора, но:
  35. 36 # Xtend (http://xtend-lang.org) — это статически типизированный язык программирования,

    приемник Xpand, построенный с использованием Xtext и компилирующийся в Java исходный код. • Начало разработки – 2011 год • Текущая версия – 2.17.0 О XTEND https://jaxenter.com/pirates-of-the-jvm-the-infographic-132524.html
  36. 37 # • Как в Java – • Классы, методы,

    поля • Лямбда-выражения • var (val) О XTEND • Не как в Java – • Active annotations • Template Expressions • Switch Expression • Нет continue, break
  37. 38 # • Как в Java – • Классы, методы,

    поля • Лямбда-выражения • var (val) О XTEND • Не как в Java – • Active annotations • Template Expressions • Switch Expression • Нет continue, break
  38. 39 # Возможность повлиять на результат компиляции Xtend Java @Active(EntityProcessor.class)

    public @interface Entity { … } АКТИВНЫЕ АННОТАЦИИ Xtend @Active(EntityProcessor) annotation Entity { … }
  39. 40 # Возможность повлиять на результат компиляции Xtend, из коробки:

    Xtend @Accessors(PUBLIC_GETTER, PUBLIC_SETTER) @ToString @EqualsHashCode @FinalFieldsConstructor … АКТИВНЫЕ АННОТАЦИИ
  40. 41 # Живое демо тут: https://2018.jpoint.ru/talks/gnvv9ew1z2wigkemssm4m/ Осторожно Eclipse! АКТИВНЫЕ АННОТАЦИИ

    XTEND И СОБСТВЕННЫЙ ПРОЦЕССОР АННОТАЦИЙ
  41. 42 # üПодключить зависимости Xtend в Maven проект üДобавить собственную

    аннотацию @Entity, модифицировать код генерации сеттера üДобавить интерфейс Repository и класс Service, сгенерировать необходимые методы üПровалидировать модель üСформировать тест на генератор АКТИВНЫЕ АННОТАЦИИ XTEND И СОБСТВЕННЫЙ ПРОЦЕССОР АННОТАЦИЙ
  42. 43 # • Был еще плагин для IntelliJ IDEA, но…

    https://github.com/eclipse/xtext-idea • Сейчас вся надежда на LSP ТОЛЬКО В ECLIPSE IDE?
  43. 44 # НАГЕНЕРИРОВАЛИ КОД, А ЧТО ДАЛЬШЕ? • Перенести в

    src и дальше править там, или • Модифицировать генератор под новые задачи • Переопределить бины в Spring-е при помощи аннотации @Primary • Добавить точки расширения, например как в Spring Data Rest, при помощи событий
  44. 47 # ПОЛЕЗНЫЕ ССЫЛКИ https://github.com/oehme?utf8=%E2%9C%93&tab=repositories&q=xtend

  45. 48 # • Наиболее актуальная группа с обсуждениями вопросов https://groups.google.com/forum/#!forum/xtend-lang

    • Официальная страница проекта https://www.eclipse.org/xtend • Основной репозиторий проекта https://github.com/eclipse/xtext-xtend/ • Тут будет опубликован код демо https://github.com/kogun ПОЛЕЗНЫЕ ССЫЛКИ
  46. 49 # ВЫВОДЫ • Технологии идеальны, …. • Не обязательно

    переводить проект на Xtend целиком • Лучше потратить время на разработку “интересного” кода, будь то генератор или бизнес-логика и не писать “скучный” код • Меньше кода написано – меньше ошибок
  47. БУДУ РАД ОТВЕТИТЬ НА ВАШИ ВОПРОСЫ