Exercise: Annotation Processing execution measurement wrapper
Your task is to implement a custom Annotation Processor, that will generate a wrapper for measuring the execution time of public methods annotated with Measured
annotation.
This processor should generate a wrapper class for each class that contains at least one method annotated with Measured
annotation.
This wrapper class should be a Java class under the same package, and be named just like the wrapped class but with Measured
prefix.
It should have two constructors: one that takes an instance of the original class as a parameter, and one that creates an instance of the original class based on the default constructor.
It should have the same methods as the original class, but each method with Measured
annotation should measure the time of its execution and print it in the format "{method name} from {wrapped class name} took {execution time} ms".
For example, for the following class:
package academy.kt
class TokenService {
@Measured
fun getToken(): String {
Thread.sleep(1000)
return "ABCD"
}
}
The following wrapper class should be generated:
package academy.kt;
import java.lang.String;
import org.jetbrains.annotations.NotNull;
class MeasuredTokenService {
private TokenService wrapper;
MeasuredTokenService(TokenService wrapper) {
this.wrapper = wrapper;
}
MeasuredTokenService() {
this.wrapper = new TokenService();
}
@NotNull
public final String getToken() {
long before = System.currentTimeMillis();
java.lang.String value = wrapper.getToken();
long after = System.currentTimeMillis();
System.out.println("getToken from TokenService took " + (after - before) + " ms");
return value;
}
}
package academy.kt
class UserService(
private val tokenService: TokenService
) {
@Measured
fun findUser(id: Int): User {
tokenService.getToken()
Thread.sleep(1000)
return User("$id")
}
@Measured
fun findUsers(): User {
Thread.sleep(1000)
return User("")
}
}
The following wrapper class should be generated:
package academy.kt;
import org.jetbrains.annotations.NotNull;
class MeasuredUserService {
private UserService wrapper;
MeasuredUserService(UserService wrapper) {
this.wrapper = wrapper;
}
MeasuredUserService(@NotNull TokenService tokenService) {
this.wrapper = new UserService(tokenService);
}
@NotNull
public final User findUser(int id) {
long before = System.currentTimeMillis();
academy.kt.User value = wrapper.findUser(id);
long after = System.currentTimeMillis();
System.out.println("findUser from UserService took " + (after - before) + " ms");
return value;
}
@NotNull
public final User findUsers() {
long before = System.currentTimeMillis();
academy.kt.User value = wrapper.findUsers();
long after = System.currentTimeMillis();
System.out.println("findUsers from UserService took " + (after - before) + " ms");
return value;
}
}
Example usage of generated classes:
fun main() {
val tokenService = TokenService()
val userService = UserService(tokenService)
val measuredService = MeasuredUserService(tokenService)
val user = measuredService.findUser(12)
// findUser from UserService took 200Xms
val user2 = measuredService.findUsers()
// findUser from UserService took 100Xms
val measuredTokenService = MeasuredTokenService(tokenService)
val token = measuredTokenService.getToken()
// getToken from TokenService took 100Xms
}
For generating Kotlin code use Java Poet. Assume that wrapped class has no type parameters.
Here is a project, that provides configuration and sample use, and only requires processor implementation:
Once you are done with the exercise, you can check your solution here.
Marcin Moskala is a highly experienced developer and Kotlin instructor as the founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training, Google Developers Expert, known for his significant contributions to the Kotlin community. Moskala is the author of several widely recognized books, including "Effective Kotlin," "Kotlin Coroutines," "Functional Kotlin," "Advanced Kotlin," "Kotlin Essentials," and "Android Development with Kotlin."
Beyond his literary achievements, Moskala is the author of the largest Medium publication dedicated to Kotlin. As a respected speaker, he has been invited to share his insights at numerous programming conferences, including events such as Droidcon and the prestigious Kotlin Conf, the premier conference dedicated to the Kotlin programming language.