Gri*_*ort 5 overloading self-modifying kotlin kotlin-extension
在JavaScript/Python等动态语言中,可以在运行时覆盖或"修改"函数.例如,为了修改alertJS中的函数,可以这样做:
const _prev_alert = window.alert;
window.alert = function() {
_prev_alert.apply(this, arguments);
console.log("Alert function was called!");
}
Run Code Online (Sandbox Code Playgroud)
这将输出"调用警报功能!" 每次alert调用函数时都到控制台.
现在,显然这样的事情在Kotlin-JVM或Kotlin-Native的运行时期间是不可能的,因为它们具有静态特性.但是,对于那些相同的语言,是否有可能在编译期间修改未编译的函数?我不是指来自库的预编译函数,而是我在我正在开发的同一个项目中编写的函数.
例如,假设我有一个我写的函数get_number.我可以修改get_number为返回一个不同的数字而不改变它在main中的调用方式而不直接修改它的代码吗?(或者有一种方法我可以写原件,get_number所以修改可能在线下吗?)
fun main(args: Array<String>) {
println(get_number())
}
fun get_number(): Int {
return 3
}
// Without modifying the code above, can I get main to print something besides 3?
Run Code Online (Sandbox Code Playgroud)
我一直在阅读Kotlin的Annotations and Reflections元编程,所以也许那些可以控制编译器的行为并覆盖get_number代码?或者这是完全的疯狂,这种性质的唯一方法是通过在Kotlin上开发我自己的,独立的元编程包装器?
此外,只是为了澄清,这个问题不是关于Kotlin-JS,答案(如果存在)应该适用于Kotlin-JVM或Native.
正如我的评论中所述:在几乎所有情况下,使用适当的设计模式比开始依赖动态代理,反射或AOP之类的东西来解决这类问题更为可取.
话虽如此,问题是询问是否可以通过元编程在编译时修改Kotlin函数,答案是"是".为了演示,下面是一个使用AspectJ的完整示例.
我建立了一个基于Maven的小项目,具有以下结构:
.
??? pom.xml
??? src
??? main
??? kotlin
??? Aop.kt
??? Main.kt
Run Code Online (Sandbox Code Playgroud)
我将在下面的部分中重现所有文件的内容.
实际的应用程序代码位于名为的文件中Main.kt,除了我将您的函数重命名为符合Kotlin命名规则的事实- 这与您的问题中提供的代码完全相同.该getNumber()方法旨在返回3.
fun main(args: Array<String>) {
println(getNumber())
}
fun getNumber(): Int {
return 3
}
Run Code Online (Sandbox Code Playgroud)
与AOP相关的代码在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
}
}
Run Code Online (Sandbox Code Playgroud)
(注意Main.kt文件生成的类的名称是如何的MainKt.)
POM文件将所有内容放在一起.我正在使用4个插件:
kotlin-maven-plugin需要编译Kotline文件的照顾.配置包括执行kapt插件以处理AspectJ注释.jcabi-maven-plugin执行AspectJ的编译器/织入到编织方面向二进制类.maven-jar-plugin引用主类的清单构建JAR文件.maven-shade-plugin构建一个胖JAR包含所有库的依赖.这是完整的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>
Run Code Online (Sandbox Code Playgroud)
要像任何Maven项目一样构建,您只需要运行:
mvn clean package
Run Code Online (Sandbox Code Playgroud)
这将在该target/kotlin-aop-1.0-SNAPSHOT.jar位置建立一个胖JAR .然后可以使用以下java命令执行此JAR :
java -jar target/kotlin-aop-1.0-SNAPSHOT.jar
Run Code Online (Sandbox Code Playgroud)
执行然后给我们以下结果,证明一切按预期工作:
42
(在编写1.8.0_181时,使用最新的Oracle Java 8 JDK构建并执行了应用程序)
正如上面的例子所示,重新定义Kotlin函数当然是可能的,但是 - 重申我原来的观点 - 在几乎所有情况下,都有更优雅的解决方案可用于实现您的需求.
| 归档时间: |
|
| 查看次数: |
972 次 |
| 最近记录: |