Monday 22 May 2023

Micronaut: Around advice: Decorate a method

In this post, I am going to show how to decorate a method using @Around advice.

 

Step 1: Define @Around advice.

@Documented
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
@Around
public @interface LogAdvice {

}

 

a. The retention policy of the annotation should be RUNTIME

b. In General, we apply advice at the class or method level so the target types are TYPE and METHOD

c. @Around annotation is added to tell Micronaut that the annotation is Around advice

 

Step 2: Implement a method interceptor.

@Singleton
@InterceptorBean(LogAdvice.class)
public class LogInterceptor implements MethodInterceptor<Object, Object> {

  @Override
  public Object intercept(MethodInvocationContext<Object, Object> context) {

    String methodName = context.getMethodName();
    System.out.println(methodName + " method called with below arguments");

    Set<Entry<String, MutableArgumentValue<?>>> entrySet = context.getParameters().entrySet();
    for (Entry<String, MutableArgumentValue<?>> entry : entrySet) {
      MutableArgumentValue<?> argumentValue = entry.getValue();
      System.out.println("\t" + entry.getKey() + " -> " + argumentValue.getValue());
    }

    return context.proceed();
  }

}

a. The @InterceptorBean annotation specify the the annotation the interceptor is associated with. Note that @InterceptorBean is meta-annotated with a default scope of @Singleton therefore if you want a new interceptor created and associated with each intercepted bean you should annotate the interceptor with @Prototype.

 

b. ‘context.proceed()’ is called to proceed with the method invocation.

 

Step 3: Apply the LogAdvice annotation on the method definition.

@Singleton
public class ArithmeticUtil {

  @LogAdvice
  public Integer add(int a, int b) {
    return a + b;
  }
}

Whenever the type ArithmeticUtil bean is injected into a class, a compile-time-generated proxy is injected that decorates method calls with the @LogAdvice defined earlier.

 

Find the below working application.

 

Step 1: Create new maven project ‘micronaut-around-advice’.

 

Step 2: Update pom.xml with maven dependencies.

 

pom.xml

<?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>com.sample.app</groupId>
  <artifactId>micronaut-around-advice</artifactId>
  <version>0.1</version>
  <packaging>jar</packaging>

  <parent>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-parent</artifactId>
    <version>3.7.3</version>
  </parent>

  <properties>
    <packaging>jar</packaging>
    <jdk.version>11</jdk.version>
    <release.version>11</release.version>
    <micronaut.version>3.7.3</micronaut.version>
    <micronaut.runtime>netty</micronaut.runtime>
    <exec.mainClass>com.sample.app.App</exec.mainClass>
  </properties>

  <repositories>
    <repository>
      <id>central</id>
      <url>https://repo.maven.apache.org/maven2</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-inject</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-validation</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-http-client</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-http-server-netty</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-jackson-databind</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>jakarta.annotation</groupId>
      <artifactId>jakarta.annotation-api</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut.test</groupId>
      <artifactId>micronaut-test-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>io.micronaut.build</groupId>
        <artifactId>micronaut-maven-plugin</artifactId>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <!-- Uncomment to enable incremental compilation -->
          <!-- <useIncrementalCompilation>false</useIncrementalCompilation> -->

          <annotationProcessorPaths
            combine.children="append">
            <path>
              <groupId>io.micronaut</groupId>
              <artifactId>micronaut-http-validation</artifactId>
              <version>${micronaut.version}</version>
            </path>
          </annotationProcessorPaths>

        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

Step 3: Define LogAdvice class.

 

LogAdvice.java

package com.sample.app.advices;

import io.micronaut.aop.Around;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
@Around
public @interface LogAdvice {

}

Step 4: Define LogInterceptor class.

 

LogInterceptor.java

package com.sample.app.interceptor;

import java.util.Map.Entry;
import java.util.Set;

import com.sample.app.advices.LogAdvice;

import io.micronaut.aop.InterceptorBean;
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import io.micronaut.core.type.MutableArgumentValue;
import jakarta.inject.Singleton;

@Singleton
@InterceptorBean(LogAdvice.class)
public class LogInterceptor implements MethodInterceptor<Object, Object> {

  @Override
  public Object intercept(MethodInvocationContext<Object, Object> context) {

    String methodName = context.getMethodName();
    System.out.println(methodName + " method called with below arguments");

    Set<Entry<String, MutableArgumentValue<?>>> entrySet = context.getParameters().entrySet();
    for (Entry<String, MutableArgumentValue<?>> entry : entrySet) {
      MutableArgumentValue<?> argumentValue = entry.getValue();
      System.out.println("\t" + entry.getKey() + " -> " + argumentValue.getValue());
    }

    return context.proceed();
  }

}

Step 5: Define ArithmeticUtil class.

 

ArithmeticUtil.java

package com.sample.app.components;

import com.sample.app.advices.LogAdvice;

import jakarta.inject.Singleton;

@Singleton
public class ArithmeticUtil {

  @LogAdvice
  public Integer add(int a, int b) {
    return a + b;
  }
}

Step 6: Define main application class.

 

App.java

package com.sample.app;

import com.sample.app.components.ArithmeticUtil;

import io.micronaut.context.ApplicationContext;

public class App {

  public static void main(String[] args) {

    try (ApplicationContext applicationContext = ApplicationContext.run()) {

      ArithmeticUtil arithmeticUtil = applicationContext.getBean(ArithmeticUtil.class);
      arithmeticUtil.add(10, 20);
    }

  }
}

Total project structure looks like below.



Build the project using mvn package command.

Navigate to the folder where pom.xml is located and execute the command ‘mvn package’.

 

Upon command successful execution, you can see the jar file ‘micronaut-around-advice-0.1.jar’ in project target folder.

$ls ./target/
classes
generated-sources
generated-test-sources
maven-archiver
maven-status
micronaut-around-advice-0.1.jar
original-micronaut-around-advice-0.1.jar
test-classes

Execute below command to run the application.

java -jar ./target/micronaut-around-advice-0.1.jar

You will see below messages in the console.

add method called with below arguments
  a -> 10
  b -> 20

You can download the application from this link.



 

Previous                                                    Next                                                    Home

No comments:

Post a Comment