Around.java

/*
 * Copyright 2017-2020 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.aop;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * <p>Annotation stereotype to applied to other annotations to indicate the annotation provides Around advice.</p>
 *
 * <p>Around advice decorates a method invocation such that the method can be intercepted via a {@link MethodInterceptor}</p>
 *
 * <p>For example:</p>
 *
 * <pre><code>
 *  {@literal @}Around
 *  {@literal @}Type(ExampleInterceptor.class)
 *  {@literal @}Documented
 *  {@literal @}Retention(RUNTIME)
 *   public @interface Example {
 *   }
 * </code></pre>
 *
 * <p>Note that the annotation MUST be {@link java.lang.annotation.RetentionPolicy#RUNTIME} and the specified {@link io.micronaut.context.annotation.Type} must implement {@link MethodInterceptor}</p>
 *
 * @author Graeme Rocher
 * @since 1.0
 */
@Documented
@Retention(RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD})
@InterceptorBinding(kind = InterceptorKind.AROUND)
public @interface Around {

    /**
     * <p>By default Micronaut will compile subclasses of the target class and call super.foo(..) to invoke the original method since
     * this is more efficient and allows proxied methods to work for calls from within the class.</p>
     *
     * <p>However certain cases it may be useful to be able to to instead proxy all public methods of the original implementation.
     * By setting the value here to <code>true</code> the {@link Interceptor} can specify that it requires proxying of the class</p>
     *
     * <p>Generated subclasses will implement {@link InterceptedProxy} if this attribute is set to true</p>
     *
     * @return True if the original implementation should be proxied. Defaults to false.
     * @see InterceptedProxy
     */
    boolean proxyTarget() default false;

    /**
     * <p>If {@link #proxyTarget()} is set to <code>true</code> then one can optionally set the value of <code>hotswap</code> to true
     * in which case the proxy will implement the {@link HotSwappableInterceptedProxy} interface.</p>
     *
     * @return True if the proxy should allow hotswap
     * @see HotSwappableInterceptedProxy
     */
    boolean hotswap() default false;

    /**
     * <p>By default Micronaut will initialize the proxy target eagerly when the proxy is created. This is better for performance, but some use
     * cases may require the bean to be resolved lazily (for example for resolving the bean from a custom scope).</p>
     *
     * <p>If {@link #proxyTarget()} is set to <code>true</code> then one can optionally set the of <code>lazy</code> to true</p>
     *
     * @return True if the proxy target should be resolved lazily
     */
    boolean lazy() default false;

    /**
     * If true the proxy cache and reuse the target.
     *
     * @return True if the proxy target should be cacheable
     * @since 3.1.0
     */
    boolean cacheableLazyTarget() default false;

    /**
     * Sets the {@link io.micronaut.aop.Around.ProxyTargetConstructorMode}. See the
     * javadoc for {@link io.micronaut.aop.Around.ProxyTargetConstructorMode} for more information.
     *
     * @return The {@link io.micronaut.aop.Around.ProxyTargetConstructorMode}.
     * @see io.micronaut.aop.Around.ProxyTargetConstructorMode
     * @since 3.0.0
     */
    ProxyTargetConstructorMode proxyTargetMode() default ProxyTargetConstructorMode.ERROR;

    /**
     * When using {@link #proxyTarget()} on a {@link io.micronaut.context.annotation.Factory} method if the
     * returned bean features constructor arguments this can lead to undefined behaviour since it is expected
     * with factory methods that the developer is responsible for constructing the object.
     *
     * <p>For example if the type accepts an argument of type <code>String</code> then there is no way
     * for Micronaut to know what to inject as a value for the argument and injecting <code>null</code> is inherently unsafe.</p>
     *
     * <p>The {@link io.micronaut.aop.Around.ProxyTargetConstructorMode} allows the developer decide if they wish to allow
     * proxies to be constructed and if a proxy is allowed then Micronaut will either inject a bean if it is found or <code>null</code> if is not. For primitive types Micronaut will inject <code>true</code> for booleans and <code>0</code> for number types</p>
     */
    enum ProxyTargetConstructorMode {
        /**
         * Do not allow types with constructor arguments to be proxied. This is the default behaviour and compilation will fail.
         */
        ERROR,
        /**
         * Allow types to be proxied but print a warning when this feature is used.
         *
         * <p>In this case if a constructor parameter cannot be injected Micronaut will inject <code>null</code> for objects or <code>false</code> for boolean or <code>0</code> for any other primitive.</p>
         */
        WARN,
        /**
         * Allow types to be proxied and don't print any warnings.
         */
        ALLOW
    }
}