All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fitbur.mockito.bytebuddy.implementation.bind.annotation.Origin Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
package com.fitbur.mockito.bytebuddy.implementation.bind.annotation;

import com.fitbur.mockito.bytebuddy.description.annotation.AnnotationDescription;
import com.fitbur.mockito.bytebuddy.description.method.MethodDescription;
import com.fitbur.mockito.bytebuddy.description.method.ParameterDescription;
import com.fitbur.mockito.bytebuddy.description.type.TypeDescription;
import com.fitbur.mockito.bytebuddy.implementation.Implementation;
import com.fitbur.mockito.bytebuddy.implementation.bind.MethodDelegationBinder;
import com.fitbur.mockito.bytebuddy.implementation.bytecode.assign.Assigner;
import com.fitbur.mockito.bytebuddy.implementation.bytecode.constant.*;
import com.fitbur.mockito.bytebuddy.utility.JavaConstant;
import com.fitbur.mockito.bytebuddy.utility.JavaType;

import java.lang.annotation.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * 

* The origin annotation provides some meta information about the source method that is bound to this method where * the binding is dependant of the parameter's type: *

*
    *
  1. If the annotated parameter is of type {@link java.lang.reflect.Method}, {@link java.lang.reflect.Constructor} or * {@code java.lang.reflect.Executable}, the parameter is assigned a reference to the method or constructor it * instruments. If the reference is not assignable to the sort of the intercepted source, the target is not considered * for binding.
  2. *
  3. If the annotated parameter is of type {@link java.lang.Class}, the parameter is assigned a reference of the * type of the instrumented type.
  4. *
  5. If the annotated parameter is of type {@link java.lang.String}, the parameter is assigned a string with * the value that would be returned by the {@link Method#toString()} method. *
  6. *
  7. If the annotated parameter is a {@code int} type, it is assigned the intercepted method's modifiers.
  8. *
  9. If the annotated type is {@code java.lang.invoke.MethodHandle}, a handle of the intercepted method is injected. * A {@code java.lang.invoke.MethodHandle} is stored in a class's constant pool and does therefore not face the same * runtime performance limitations as a (non-cached) {@link java.lang.reflect.Method} reference. Method handles are * only supported for byte code versions starting from Java 7.
  10. *
  11. If the annotated type is {@code java.lang.invoke.MethodType}, a description of the intercepted method's type * is injected. Method type descriptions are only supported for byte code versions starting from Java 7.
  12. *
*

* Any other parameter type will cause an {@link java.lang.IllegalStateException}. *

*

* Important: A method handle or method type reference can only be used if the referenced method's types are all visible * to the instrumented type or an {@link IllegalAccessError} will be thrown at runtime. *

* * @see com.fitbur.mockito.bytebuddy.implementation.MethodDelegation * @see com.fitbur.mockito.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface Origin { /** * Determines if the value that is assigned by this annotation is cached. For values that can be stored in the constant pool, * this value is ignored as such values are cached implicitly. As a result, this value currently only affects caching of * {@link Method} instances. * * @return {@code true} if the value for this parameter should be cached in a {@code static} field inside the instrumented class. */ boolean cache() default true; /** * A binder for binding parameters that are annotated with * {@link com.fitbur.mockito.bytebuddy.implementation.bind.annotation.Origin}. * * @see TargetMethodAnnotationDrivenBinder */ enum Binder implements TargetMethodAnnotationDrivenBinder.ParameterBinder { /** * The singleton instance. */ INSTANCE; @Override public Class getHandledType() { return Origin.class; } @Override public MethodDelegationBinder.ParameterBinding bind(AnnotationDescription.Loadable annotation, MethodDescription source, ParameterDescription target, Implementation.Target implementationTarget, Assigner assigner) { TypeDescription parameterType = target.getType().asErasure(); if (parameterType.represents(Class.class)) { return new MethodDelegationBinder.ParameterBinding.Anonymous(ClassConstant.of(implementationTarget.getOriginType().asErasure())); } else if (parameterType.represents(Method.class)) { return source.isMethod() ? new MethodDelegationBinder.ParameterBinding.Anonymous( annotation.loadSilent().cache() ? MethodConstant.forMethod(source.asDefined()).cached() : MethodConstant.forMethod(source.asDefined())) : MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE; } else if (parameterType.represents(Constructor.class)) { return source.isConstructor() ? new MethodDelegationBinder.ParameterBinding.Anonymous( annotation.loadSilent().cache() ? MethodConstant.forMethod(source.asDefined()).cached() : MethodConstant.forMethod(source.asDefined())) : MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE; } else if (JavaType.EXECUTABLE.getTypeStub().equals(parameterType)) { return new MethodDelegationBinder.ParameterBinding.Anonymous(annotation.loadSilent().cache() ? MethodConstant.forMethod(source.asDefined()).cached() : MethodConstant.forMethod(source.asDefined())); } else if (parameterType.represents(String.class)) { return new MethodDelegationBinder.ParameterBinding.Anonymous(new TextConstant(source.toString())); } else if (parameterType.represents(int.class)) { return new MethodDelegationBinder.ParameterBinding.Anonymous(IntegerConstant.forValue(source.getModifiers())); } else if (parameterType.equals(JavaType.METHOD_HANDLE.getTypeStub())) { return new MethodDelegationBinder.ParameterBinding.Anonymous(JavaConstant.MethodHandle.of(source.asDefined()).asStackManipulation()); } else if (parameterType.equals(JavaType.METHOD_TYPE.getTypeStub())) { return new MethodDelegationBinder.ParameterBinding.Anonymous(JavaConstant.MethodType.of(source.asDefined()).asStackManipulation()); } else { throw new IllegalStateException("The " + target + " method's " + target.getIndex() + " parameter is annotated with a Origin annotation with an argument not representing a Class," + " Method, Constructor, String, int, MethodType or MethodHandle type"); } } @Override public String toString() { return "Origin.Binder." + name(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy