Spec-Zone.ru › Kotlin 1.4

Плагины компилятора

  • Плагин "all-open" компилятора
  • Плагин "no-arg" компилятора
  • Плагин "SAM-с-приемником" компилятора
  • Parcelable генератор реализаций

Плагин "all-open" компилятора

В Kotlin классы и их члены final по умолчанию, что затрудняет использование фреймворков и библиотек, таких как Spring AOP, которые требуют, чтобы классы были open. Плагин компилятора all-open адаптирует Kotlin к требованиям таких фреймворков и делает классы, помеченные определённой аннотацией, и их члены открытыми без явного open ключевого слова.

Например, при использовании Spring вам не нужно, чтобы все классы были открытыми, а только те, которые помечены определёнными аннотациями, такими как @Configuration или @Service. All-open позволяет указать такие аннотации.

Мы предоставляем поддержку плагина all-open как для Gradle, так и для Maven с полной интеграцией в IDE.

Примечание: для Spring можно использовать плагин компилятора kotlin-spring (см. ниже).

Использование в Gradle

Добавьте артефакт плагина в зависимости buildscript и примените плагин:

buildscript {
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
    }
}

apply plugin: "kotlin-allopen"

В качестве альтернативы, вы можете включить его, используя блок plugins:

plugins {
  id "org.jetbrains.kotlin.plugin.allopen" version "1.4.10"
}

Затем укажите список аннотаций, которые сделают классы открытыми:

allOpen {
    annotation("com.my.Annotation")
    // annotations("com.another.Annotation", "com.third.Annotation")
}

Если класс (или любой из его суперклассов) помечен аннотацией com.my.Annotation, сам класс и все его члены станут открытыми.

Он также работает с мета-аннотациями:

@com.my.Annotation
annotation class MyFrameworkAnnotation

@MyFrameworkAnnotation
class MyClass // will be all-open

MyFrameworkAnnotation помечен мета-аннотацией all-open com.my.Annotation, поэтому он также становится аннотацией all-open.

Использование в Maven

Вот как использовать all-open с Maven:

<plugin>
    <artifactId>kotlin-maven-plugin</artifactId>
    <groupId>org.jetbrains.kotlin</groupId>
    <version>${kotlin.version}</version>

    <configuration>
        <compilerPlugins>
            <!-- Or "spring" for the Spring support -->
            <plugin>all-open</plugin>
        </compilerPlugins>

        <pluginOptions>
            <!-- Each annotation is placed on its own line -->
            <option>all-open:annotation=com.my.Annotation</option>
            <option>all-open:annotation=com.their.AnotherAnnotation</option>
        </pluginOptions>
    </configuration>

    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-allopen</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
    </dependencies>
</plugin>

Обратитесь к разделу "Использование в Gradle", чтобы получить подробную информацию о работе аннотаций all-open.

Поддержка Spring

Если вы используете Spring, вы можете включить плагин компилятора kotlin-spring вместо ручного указания аннотаций Spring. kotlin-spring является обёрткой над all-open и ведет себя точно так же.

Как и с all-open, добавьте плагин в зависимости buildscript:

buildscript {
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
    }
}

apply plugin: "kotlin-spring" // instead of "kotlin-allopen"

Или с помощью DSL плагинов Gradle:

plugins {
  id "org.jetbrains.kotlin.plugin.spring" version "1.4.10"
}

В Maven плагин spring предоставляется зависимостью плагина kotlin-maven-allopen, поэтому для его включения:

<configuration>
    <compilerPlugins>
        <plugin>spring</plugin>
    </compilerPlugins>
</configuration>

<dependencies>
    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-maven-allopen</artifactId>
        <version>${kotlin.version}</version>
    </dependency>
</dependencies>

Плагин указывает следующие аннотации: @Component, @Async, @Transactional, @Cacheable и @SpringBootTest. Благодаря поддержке мета-аннотаций классы, помеченные аннотациями @Configuration, @Controller, @RestController, @Service или @Repository автоматически открываются, так как эти аннотации мета-аннотированы аннотацией @Component.

Конечно, вы можете использовать как kotlin-allopen , так и kotlin-spring в одном проекте.

Обратите внимание, что если вы используете шаблон проекта, сгенерированный сервисом start.spring.io, плагин kotlin-spring будет включен по умолчанию.

Использование в командной строке

JAR-файл плагина компилятора all-open доступен в бинарном распределении компилятора Kotlin. Вы можете подключить плагин, указав путь к его JAR-файлу с помощью параметра Xplugin kotlinc:

-Xplugin=$KOTLIN_HOME/lib/allopen-compiler-plugin.jar

Вы можете указать аннотации all-open напрямую, используя параметр плагина annotation , или включить "пресет". Единственный доступный сейчас пресет для all-open — spring.

# The plugin option format is: "-P plugin:<plugin id>:<key>=<value>". 
# Options can be repeated.

-P plugin:org.jetbrains.kotlin.allopen:annotation=com.my.Annotation
-P plugin:org.jetbrains.kotlin.allopen:preset=spring

Плагин "no-arg" компилятора

Плагин компилятора no-arg генерирует дополнительный конструктор без аргументов для классов с определённой аннотацией.

Сгенерированный конструктор является синтетическим, поэтому его нельзя напрямую вызвать из Java или Kotlin, но его можно вызвать с помощью рефлексии.

Это позволяет API Java Persistence (JPA) создавать экземпляр класса, даже если у него нет конструктора без параметров с точки зрения Kotlin или Java (см. описание плагина kotlin-jpa ниже).

Использование в Gradle

Использование очень похоже на all-open.

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

buildscript {
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
    }
}

apply plugin: "kotlin-noarg"

Или с помощью DSL плагинов Gradle:

plugins {
  id "org.jetbrains.kotlin.plugin.noarg" version "1.4.10"
}

Затем укажите список аннотаций no-arg:

noArg {
    annotation("com.my.Annotation")
}

Включите опцию invokeInitializers , если вы хотите, чтобы плагин выполнял логику инициализации из синтетического конструктора. Начиная с Kotlin 1.1.3-2, она отключена по умолчанию из-за KT-18667 и KT-18668, которые будут устранены в будущем.

noArg {
    invokeInitializers = true
}

Использование в Maven

<plugin>
    <artifactId>kotlin-maven-plugin</artifactId>
    <groupId>org.jetbrains.kotlin</groupId>
    <version>${kotlin.version}</version>

    <configuration>
        <compilerPlugins>
            <!-- Or "jpa" for JPA support -->
            <plugin>no-arg</plugin>
        </compilerPlugins>

        <pluginOptions>
            <option>no-arg:annotation=com.my.Annotation</option>
            <!-- Call instance initializers in the synthetic constructor -->
            <!-- <option>no-arg:invokeInitializers=true</option> -->
        </pluginOptions>
    </configuration>

    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-noarg</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
    </dependencies>
</plugin>

Поддержка JPA

Как и плагин kotlin-spring, обернутый поверх all-open, kotlin-jpa обернут поверх no-arg. Плагин автоматически указывает аннотации @Entity, @Embeddable и @MappedSuperclass no-arg.

Вот как добавить плагин в Gradle:

buildscript {
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
    }
}

apply plugin: "kotlin-jpa"

Или с помощью DSL плагинов Gradle:

plugins {
  id "org.jetbrains.kotlin.plugin.jpa" version "1.4.10"
}

В Maven включите плагин jpa:

<compilerPlugins>
    <plugin>jpa</plugin>
</compilerPlugins>

Использование в командной строке

Как и с all-open, добавьте JAR-файл плагина в путь к классам плагинов компилятора и укажите аннотации или пресеты:

-Xplugin=$KOTLIN_HOME/lib/noarg-compiler-plugin.jar
-P plugin:org.jetbrains.kotlin.noarg:annotation=com.my.Annotation
-P plugin:org.jetbrains.kotlin.noarg:preset=jpa

Плагин "SAM-с-приемником" компилятора

Плагин компилятора sam-with-receiver делает первый параметр аннотированного Java-интерфейса "single abstract method" (SAM) метода приемником в Kotlin. Это преобразование работает только тогда, когда интерфейс SAM передаётся в Kotlin в качестве лямбда-выражения, как для адаптеров SAM, так и для конструкторов SAM (подробности см. в документации).

Вот пример:

public @interface SamWithReceiver {}

@SamWithReceiver
public interface TaskRunner {
    void run(Task task);
}
fun test(context: TaskContext) {
    val runner = TaskRunner { 
        // Here 'this' is an instance of 'Task'
        
        println("$name is started")
        context.executeTask(this)
        println("$name is finished")
    }
}

Использование в Gradle

Использование аналогично all-open и no-arg, за исключением того, что sam-with-receiver не имеет встроенных пресетов, и вам нужно указать свой собственный список аннотаций для обработки.

buildscript {
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-sam-with-receiver:$kotlin_version"
    }
}

apply plugin: "kotlin-sam-with-receiver"

Затем укажите список аннотаций SAM-с-приемником:

samWithReceiver {
    annotation("com.my.SamWithReceiver")
}

Использование в Maven

<plugin>
    <artifactId>kotlin-maven-plugin</artifactId>
    <groupId>org.jetbrains.kotlin</groupId>
    <version>${kotlin.version}</version>

    <configuration>
        <compilerPlugins>
            <plugin>sam-with-receiver</plugin>
        </compilerPlugins>

        <pluginOptions>
            <option>
                sam-with-receiver:annotation=com.my.SamWithReceiver
            </option>
        </pluginOptions>
    </configuration>

    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-sam-with-receiver</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
    </dependencies>
</plugin>

Использование в командной строке

Просто добавьте файл JAR плагина в пути к классам плагина компилятора и укажите список аннотаций sam-with-receiver:

-Xplugin=$KOTLIN_HOME/lib/sam-with-receiver-compiler-plugin.jar
-P plugin:org.jetbrains.kotlin.samWithReceiver:annotation=com.my.SamWithReceiver

Parcelable генератор реализаций

Плагин Android Extensions предоставляет генератор реализаций Parcelable.

Добавьте аннотацию @Parcelize, и реализация Parcelable будет сгенерирована автоматически.

import kotlinx.android.parcel.Parcelize

@Parcelize
class User(val firstName: String, val lastName: String, val age: Int): Parcelable

@Parcelize требует, чтобы все сериализуемые свойства были объявлены в первичном конструкторе. Android Extensions выведет предупреждение для каждого свойства с вспомогательным полем, объявленным в теле класса. Также, аннотация @Parcelize не может быть применена, если некоторые параметры первичного конструктора не являются свойствами.

Если ваш класс требует более сложной логики сериализации, напишите её внутри класса-компаньона:

@Parcelize
data class User(val firstName: String, val lastName: String, val age: Int) : Parcelable {
    private companion object : Parceler<User> {
        override fun User.write(parcel: Parcel, flags: Int) {
            // Custom write implementation
        }

        override fun create(parcel: Parcel): User {
            // Custom read implementation
        }
    }
}

Поддерживаемые типы

@Parcelize поддерживает широкий спектр типов:

  • примитивные типы (и их упакованные версии);
  • объекты и перечисления;
  • String, CharSequence;
  • Exception;
  • Size, SizeF, Bundle, IBinder, IInterface, FileDescriptor;
  • SparseArray, SparseIntArray, SparseLongArray, SparseBooleanArray;
  • все Serializable (да, Date тоже поддерживается) и Parcelable реализации;
  • коллекции всех поддерживаемых типов: List (отображается на ArrayList), Set (отображается на LinkedHashSet), Map (отображается на LinkedHashMap);
    • Также ряд конкретных реализаций: ArrayList, LinkedList, SortedSet, NavigableSet, HashSet, LinkedHashSet, TreeSet, SortedMap, NavigableMap, HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap;
  • массивы всех поддерживаемых типов;
  • необязательные версии всех поддерживаемых типов.

Пользовательские Parceler

Даже если ваш тип не поддерживается напрямую, вы можете написать объект сопоставления Parceler для него.

class ExternalClass(val value: Int)

object ExternalClassParceler : Parceler<ExternalClass> {
    override fun create(parcel: Parcel) = ExternalClass(parcel.readInt())

    override fun ExternalClass.write(parcel: Parcel, flags: Int) {
        parcel.writeInt(value)
    }
}

Внешние parcelers могут быть применены с использованием аннотаций @TypeParceler или @WriteWith.

// Class-local parceler
@Parcelize
@TypeParceler<ExternalClass, ExternalClassParceler>()
class MyClass(val external: ExternalClass)

// Property-local parceler
@Parcelize
class MyClass(@TypeParceler<ExternalClass, ExternalClassParceler>() val external: ExternalClass)

// Type-local parceler
@Parcelize
class MyClass(val external: @WriteWith<ExternalClassParceler>() ExternalClass)

© 2010–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/compiler-plugins.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API