Как указано в моем комментарии: почти во всех случаях более желательно использовать соответствующий шаблон проектирования, чем начинать полагаться на такие вещи, как динамические прокси, отражение или AOP для решения такой проблемы.
При этом возникает вопрос, возможно ли изменять функции Kotlin во время компиляции посредством метапрограммирования, и ответ - «Да». Для демонстрации ниже приведен полный пример, в котором используется AspectJ.
Структура проекта
Я создал небольшой проект на основе Maven со следующей структурой:
.
├── pom.xml
└── src
└── main
└── kotlin
├── Aop.kt
└── Main.kt
Я воспроизведу содержимое всех файлов в разделах ниже.
Код приложения
Фактический код приложения находится в файле с именем Main.kt
, и - за исключением того факта, что я переименовал вашу функцию, чтобы она соответствовала Правила именования Kotlin - они идентичны коду, приведенному в вашем вопросе. Метод getNumber()
предназначен для возврата 3.
fun main(args: Array<String>) {
println(getNumber())
}
fun getNumber(): Int {
return 3
}
Код АОП
Код, связанный с АОП, находится в Aop.kt
и очень прост. В нем есть @Around
совет с точечным разрезом, который соответствует выполнению функции getNumber()
. Совет перехватит вызов метода getNumber()
и вернет 42 (вместо 3).
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
@Aspect
class Aop {
@Around("execution(* MainKt.getNumber(..))")
fun getRealNumber(joinPoint: ProceedingJoinPoint): Any {
return 42
}
}
(Обратите внимание, как имя сгенерированного класса для файла Main.kt
MainKt
.)
POM файл
Файл POM объединяет все воедино. Я использую 4 плагина:
Это полный файл POM:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>x.y.z</groupId>
<artifactId>kotlin-aop</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<kotlin.version>1.2.61</kotlin.version>
<aspectj.version>1.9.1</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
</execution>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-maven-plugin</artifactId>
<version>0.14.1</version>
<executions>
<execution>
<goals>
<goal>ajc</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>MainKt</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Строительство и выполнение
Для сборки, как и для любого проекта Maven, вам просто нужно запустить:
mvn clean package
Это создаст толстый JAR в месте target/kotlin-aop-1.0-SNAPSHOT.jar
. Затем этот JAR можно запустить с помощью команды java
:
java -jar target/kotlin-aop-1.0-SNAPSHOT.jar
Затем выполнение дает нам следующий результат, демонстрирующий, что все работает, как ожидалось:
42
(Приложение было создано и выполнено с использованием самой последней версии Oracle Java 8 JDK на момент написания - 1.8.0_181)
Заключение
Как демонстрирует приведенный выше пример, определенно можно переопределить функции Kotlin, но, повторяя мою исходную точку зрения, почти во всех случаях существуют более элегантные решения, позволяющие достичь того, что вам нужно.
person
Robby Cornelissen
schedule
30.08.2018