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
===========================

Deep Refactoring

June 26, 2019
Tweet

More Decks by Deep Refactoring

Other Decks in Programming

Transcript

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

    View full-size slide

  2. 2
    # ЧТО ХОТИМ
    • Делать микросервисы (и монолиты) на Spring-e
    • Spring Framework
    • Spring Boot
    • Spring Data (JPA)

    View full-size slide

  3. 3
    #
    Хотя, все происходит автомагически, не обойтись, без того, чтобы не написать
    немного кода:
    • Configuration
    • Entity
    • Repository
    • Service
    • Controller
    SPRING BOOT: МИНИМАЛЬНОЕ ПРИЛОЖЕНИЕ
    http://foxminded.com.ua/news/55-sravnenie-stekov-java-ee-i-spring-vozmozhnosti-i-ogranicheniya/

    View full-size slide

  4. 4
    # А КАК ЭТО ОБЫЧНО ВЫГЛЯДИТ?
    @Entity
    public class User {
    @Id
    @GeneratedValue
    private Long id;
    @Transient
    private transient boolean isNew;
    @Column(nullable = false)
    private String name;
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  12. 12
    #
    Когунь Андрей — программист
    • Работаю в компании КРОК
    • Провожу встречи Московского JUG
    @mskjug, #jugmsk
    • Преподаю Java
    О СЕБЕ

    View full-size slide

  13. 13
    #
    Департамент разработки программного обеспечения
    • Заказная (в основном) разработка
    • Для “быстрой” разработки учетных
    систем реализован собственный
    фреймворк - jXFW
    О КРОК ДРПО

    View full-size slide

  14. 14
    # О ЧЕМ ПОГОВОРИМ
    • Кодогенерация в IDE
    • Java Annotation Processing (apt)
    • Lombok
    • JavaPoet
    • Kotlin
    • Xtend

    View full-size slide

  15. 15
    # КОДОГЕНЕРАЦИЯ В IDE
    • Итеративный (и не самый быстрый) процесс
    • Генерировать можно исходный java код, любые другие ресурсы
    https://youtu.be/EEAiyRuaUXU

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. 18
    # ПРИМЕРЫ РЕАЛИЗАЦИИ ANNOTATION PROCESSING
    • Dagger (Android)
    • ButterKnife (Android)
    • QueryDSL (JPA)

    View full-size slide

  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 getSupportedAnnotationTypes() {
    Set set = new HashSet<>();
    set.add(Entity.class.getCanonicalName());
    return set;
    }
    @Override
    public SourceVersion getSupportedSourceVersion() {
    return SourceVersion.latestSupported();
    }
    }

    View full-size slide

  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;
    }
    }

    View full-size slide

  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();

    }
    }

    View full-size slide

  22. 22
    # НУ ЭТИ JAVA ПРОГРАММИСТЫ, НУ ВЫ ЗНАЕТЕ…

    View full-size slide

  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();

    View full-size slide

  24. 24
    # ДЕЛАЕМ СВОЙ PROCESSOR ДЛЯ ENTITY C JAVAPOET

    @Override
    public boolean process(Set extends TypeElement> annotations,
    RoundEnvironment roundEnv) {

    JavaFile.builder(repository, typeSpec)
    .build()
    .writeTo(filer);
    }

    View full-size slide

  25. 26
    # APT + LOMBOK?
    • Можно пользоваться готовыми аннотациями
    • А можно сделать свою:
    @MetaInfServices(JavacAnnotationHandler.class)
    public class EntityJavacHandler extends JavacAnnotationHandler {
    }

    View full-size slide

  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 annotation, JCTree.JCAnnotation ast,
    JavacNode annotationNode) {
    Context context = annotationNode.getContext();
    Javac8BasedLombokOptions options = Javac8BasedLombokOptions.replaceWithDelombokOptions(context);
    options.deleteLombokAnnotations();
    JavacHandlerUtil.deleteAnnotationIfNeccessary(annotationNode, Entity.class);

    View full-size slide

  27. 28
    # APT + LOMBOK?
    • JCTree
    • С этим разбирается Шерлок
    зато, с вашим кодом
    будет разбираться Шерлок
    Это больно и неприятно,

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  31. 32
    # А ЧТО KOTLIN?

    View full-size slide

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

    View full-size slide

  33. 34
    # А ЧТО KOTLIN KAPT?
    @Entity
    data class User {
    val name: String
    }
    • kotlin-metadata
    • KotlinPoet

    View full-size slide

  34. 35
    # А ЧТО KOTLIN?
    • Есть возможность реализовать плагин для компилятора, но:

    View full-size slide

  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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  38. 39
    #
    Возможность повлиять на результат компиляции Xtend
    Java
    @Active(EntityProcessor.class)
    public @interface Entity {

    }
    АКТИВНЫЕ АННОТАЦИИ
    Xtend
    @Active(EntityProcessor)
    annotation Entity {

    }

    View full-size slide

  39. 40
    #
    Возможность повлиять на результат компиляции Xtend, из коробки:
    Xtend
    @Accessors(PUBLIC_GETTER,
    PUBLIC_SETTER)
    @ToString
    @EqualsHashCode
    @FinalFieldsConstructor

    АКТИВНЫЕ АННОТАЦИИ

    View full-size slide

  40. 41
    #
    Живое демо тут: https://2018.jpoint.ru/talks/gnvv9ew1z2wigkemssm4m/
    Осторожно Eclipse!
    АКТИВНЫЕ АННОТАЦИИ XTEND И СОБСТВЕННЫЙ ПРОЦЕССОР
    АННОТАЦИЙ

    View full-size slide

  41. 42
    #
    üПодключить зависимости Xtend в Maven проект
    üДобавить собственную аннотацию @Entity, модифицировать код генерации
    сеттера
    üДобавить интерфейс Repository и класс Service, сгенерировать необходимые
    методы
    üПровалидировать модель
    üСформировать тест на генератор
    АКТИВНЫЕ АННОТАЦИИ XTEND И СОБСТВЕННЫЙ ПРОЦЕССОР
    АННОТАЦИЙ

    View full-size slide

  42. 43
    #
    • Был еще плагин для IntelliJ IDEA, но…
    https://github.com/eclipse/xtext-idea
    • Сейчас вся надежда на LSP
    ТОЛЬКО В ECLIPSE IDE?

    View full-size slide

  43. 44
    # НАГЕНЕРИРОВАЛИ КОД, А ЧТО ДАЛЬШЕ?
    • Перенести в src и дальше править там, или
    • Модифицировать генератор под новые
    задачи
    • Переопределить бины в Spring-е при
    помощи аннотации @Primary
    • Добавить точки расширения, например как в
    Spring Data Rest, при помощи событий

    View full-size slide

  44. 47
    # ПОЛЕЗНЫЕ ССЫЛКИ
    https://github.com/oehme?utf8=%E2%9C%93&tab=repositories&q=xtend

    View full-size slide

  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
    ПОЛЕЗНЫЕ ССЫЛКИ

    View full-size slide

  46. 49
    # ВЫВОДЫ
    • Технологии идеальны, ….
    • Не обязательно переводить проект на Xtend
    целиком
    • Лучше потратить время на разработку
    “интересного” кода, будь то генератор или
    бизнес-логика и не писать “скучный” код
    • Меньше кода написано – меньше ошибок

    View full-size slide

  47. БУДУ РАД ОТВЕТИТЬ
    НА ВАШИ ВОПРОСЫ

    View full-size slide