I'm new to annotation processing and code generation. I want to find out how can I perform such operation like appending new method to existing class. Here is an example of what I want to do:
Assume that we have a class with with custom annotations like this one:
class SourceClass {
@CustomAnnotation
fun annotatedFun1(vararg argument: Any) {
//Do something
}
@CustomAnnotation
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
And the result I want to get - extended copy of that class:
class ResultClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
fun annotatedFun1(vararg argument: Any) {
//Do something
}
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
I've already found out how to create annotation processor. I'm looking for a method to save all existing fields, properties and methods in source class and to append a few more methods to it.
If it is possible to modify class without creating new one - it would be perfect, but in all tutorials only new classes are created and I didn't find any example where all contents of source class are being copied to another one.
Please, do not advise to use reflection. I need this for android and so reflection is not the option cause of resources cost. I'm looking for compile-time solution.
It is required for custom script language implemented in app and should be used to simplify wrapper classes structure. When this job is done directly in code - it looks awful when such method count exceeds 20 per class.
Select the Java element to which you want to add an annotation. Click Add annotation. You see in the Java class the @Stateless annotation is added to your code. You see in the Java class that your annotation is added to the code.
Annotation processing is a tool built into javac for scanning and processing annotations at compile time. It can create new source files; however, it can't modify existing ones. It's done in rounds. The first round starts when the compilation reaches the pre-compile phase.
It is also possible to use multiple annotations on the same declaration: @Author(name = "Jane Doe") @EBook class MyClass { ... } If the annotations have the same type, then this is called a repeating annotation: @Author(name = "Jane Doe") @Author(name = "John Smith") class MyClass { ... }
It is the preferred way of declaring source code metadata as it standardize format and function, and is closely coupled. Kotlin supports Java-like annotations and in this tutorial, we will discuss custom annotations and how they can be used through reflection. Defining an annotation can be as simple as this.
Here is a good example of Java Annotation Processing I recently worked with.
It's an implementation of @Immutable
annotation.
Check out ByteBuddy or Kotlin Poet to understand how additional code generation works.
For Kotlin you do almost the same, check this manual for Kotlin-specific steps.
With Kotlin, you can use extension functions and that is the recommended way of adding new functionality to existing classes that you don't control. https://kotlinlang.org/docs/reference/extensions.html
You may be abel to follow the pattern used by Project Lombok. See How does lombok work? or the source code for details.
Another option would be to write a new class that extends your source class:
class ResultClass : SourceClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
}
Or perhaps use composition instead and implemnent cover methods for all the public methods in SourceClass
.
If you are not tied to doing this using annotation processing, you could use a separate piece of custom code to process the source code files before compiling. Maybe use a regular expression like /@CustomAnnotation\s+.*fun (\w+)\s*\(([^)]*)\)/gm
(Test on Regex101) to find the annotated methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With