package net.bytebuddy.implementation.attribute; import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationList; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.ParameterDescription; import net.bytebuddy.description.method.ParameterList; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import net.bytebuddy.utility.RandomString; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.objectweb.asm.Type; import java.lang.annotation.Annotation; import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class MethodAttributeAppenderExplicitTest extends AbstractMethodAttributeAppenderTest { private static final int PARAMETER_INDEX = 0; @Mock private MethodDescription methodDescription; @Mock private ParameterDescription parameterDescription; @Before @SuppressWarnings("unchecked") public void setUp() throws Exception { super.setUp(); when(methodDescription.getParameters()).thenReturn((ParameterList) new ParameterList.Explicit<ParameterDescription>(parameterDescription)); when(annotationValueFilter.isRelevant(any(AnnotationDescription.class), any(MethodDescription.InDefinedShape.class))).thenReturn(true); } @Test public void testAnnotationAppenderNoRetention() throws Exception { new MethodAttributeAppender.Explicit(new AnnotationList.ForLoadedAnnotations(new Qux.Instance())) .apply(methodVisitor, methodDescription, annotationValueFilter); verifyZeroInteractions(methodVisitor); verifyZeroInteractions(methodDescription); } @Test public void testAnnotationAppenderRuntimeRetention() throws Exception { new MethodAttributeAppender.Explicit(new AnnotationList.ForLoadedAnnotations(new Baz.Instance())) .apply(methodVisitor, methodDescription, annotationValueFilter); verify(methodVisitor).visitAnnotation(Type.getDescriptor(Baz.class), true); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(methodDescription); } @Test public void testAnnotationAppenderByteCodeRetention() throws Exception { new MethodAttributeAppender.Explicit(new AnnotationList.ForLoadedAnnotations(new QuxBaz.Instance())) .apply(methodVisitor, methodDescription, annotationValueFilter); verify(methodVisitor).visitAnnotation(Type.getDescriptor(QuxBaz.class), false); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(methodDescription); } @Test public void testAnnotationAppenderForParameterNoRetention() throws Exception { new MethodAttributeAppender.Explicit(PARAMETER_INDEX, new AnnotationList.ForLoadedAnnotations(new Qux.Instance())) .apply(methodVisitor, methodDescription, annotationValueFilter); verifyZeroInteractions(methodVisitor); verify(methodDescription).getParameters(); verifyNoMoreInteractions(methodDescription); } @Test public void testAnnotationAppenderForParameterRuntimeRetention() throws Exception { new MethodAttributeAppender.Explicit(PARAMETER_INDEX, new AnnotationList.ForLoadedAnnotations(new Baz.Instance())) .apply(methodVisitor, methodDescription, annotationValueFilter); verify(methodVisitor).visitParameterAnnotation(PARAMETER_INDEX, Type.getDescriptor(Baz.class), true); verifyNoMoreInteractions(methodVisitor); verify(methodDescription).getParameters(); verifyNoMoreInteractions(methodDescription); } @Test public void testAnnotationAppenderForParameterByteCodeRetention() throws Exception { new MethodAttributeAppender.Explicit(PARAMETER_INDEX, new AnnotationList.ForLoadedAnnotations(new QuxBaz.Instance())) .apply(methodVisitor, methodDescription, annotationValueFilter); verify(methodVisitor).visitParameterAnnotation(PARAMETER_INDEX, Type.getDescriptor(QuxBaz.class), false); verifyNoMoreInteractions(methodVisitor); verify(methodDescription).getParameters(); verifyNoMoreInteractions(methodDescription); } @Test(expected = IllegalArgumentException.class) public void testAnnotationAppenderNotEnoughParameters() throws Exception { new MethodAttributeAppender.Explicit(PARAMETER_INDEX + 1, new AnnotationList.ForLoadedAnnotations(new Baz.Instance())) .apply(methodVisitor, methodDescription, annotationValueFilter); } @Test public void testFactory() throws Exception { MethodAttributeAppender.Explicit methodAttributeAppender = new MethodAttributeAppender.Explicit(new AnnotationList.ForLoadedAnnotations(new Qux.Instance())); assertThat(methodAttributeAppender.make(instrumentedType), sameInstance((MethodAttributeAppender) methodAttributeAppender)); verifyZeroInteractions(instrumentedType); } @Test public void testOfMethod() throws Exception { when(methodDescription.getDeclaredAnnotations()).thenReturn(new AnnotationList.ForLoadedAnnotations(new Baz.Instance())); when(parameterDescription.getDeclaredAnnotations()).thenReturn(new AnnotationList.ForLoadedAnnotations(new Baz.Instance())); MethodAttributeAppender methodAttributeAppender = MethodAttributeAppender.Explicit.of(methodDescription).make(instrumentedType); methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilter); verify(methodVisitor).visitAnnotation(Type.getDescriptor(Baz.class), true); verify(methodVisitor).visitParameterAnnotation(PARAMETER_INDEX, Type.getDescriptor(Baz.class), true); verifyNoMoreInteractions(methodVisitor); verify(methodDescription, times(2)).getParameters(); verify(methodDescription).getDeclaredAnnotations(); verifyNoMoreInteractions(methodDescription); verify(parameterDescription).getIndex(); verify(parameterDescription).getDeclaredAnnotations(); verifyNoMoreInteractions(parameterDescription); verifyZeroInteractions(instrumentedType); } @Test public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(MethodAttributeAppender.Explicit.class).create(new ObjectPropertyAssertion.Creator<Annotation>() { @Override public Annotation create() { return new SimpleAnnotation.Instance(RandomString.make()); } }).apply(); ObjectPropertyAssertion.of(MethodAttributeAppender.Explicit.Target.OnMethod.class).apply(); ObjectPropertyAssertion.of(MethodAttributeAppender.Explicit.Target.OnMethodParameter.class).apply(); } public @interface SimpleAnnotation { String value(); class Instance implements SimpleAnnotation { private final String value; public Instance(String value) { this.value = value; } @Override public String value() { return value; } @Override public Class<? extends Annotation> annotationType() { return SimpleAnnotation.class; } } } }