private void testLegalStrictBinding(boolean dynamicallyTyped, Annotation... targetAnnotation) throws Exception { when(annotation.value()).thenReturn(AllArguments.Assignment.STRICT); when(stackManipulation.isValid()).thenReturn(true); when(source.getParameters()) .thenReturn(new ParameterList.Explicit.ForTypes(source, firstSourceType, secondSourceType)); when(source.isStatic()).thenReturn(false); when(targetType.isArray()).thenReturn(true); when(targetType.getComponentType()).thenReturn(componentType); when(componentType.getStackSize()).thenReturn(StackSize.SINGLE); when(target.getType()).thenReturn(targetType); when(target.getDeclaredAnnotations()) .thenReturn(new AnnotationList.ForLoadedAnnotations(targetAnnotation)); MethodDelegationBinder.ParameterBinding<?> parameterBinding = AllArguments.Binder.INSTANCE.bind( annotationDescription, source, target, implementationTarget, assigner); assertThat(parameterBinding.isValid(), is(true)); verify(source, atLeast(1)).getParameters(); verify(source, atLeast(1)).isStatic(); verify(target, atLeast(1)).getType(); verify(target, atLeast(1)).getDeclaredAnnotations(); verify(assigner).assign(firstSourceType, componentType, Assigner.Typing.of(dynamicallyTyped)); verify(assigner).assign(secondSourceType, componentType, Assigner.Typing.of(dynamicallyTyped)); verifyNoMoreInteractions(assigner); }
@Test public void testLegalSlackBinding() throws Exception { when(target.getIndex()).thenReturn(1); when(annotation.value()).thenReturn(AllArguments.Assignment.SLACK); when(stackManipulation.isValid()).thenReturn(false); when(source.getParameters()) .thenReturn(new ParameterList.Explicit.ForTypes(source, firstSourceType, secondSourceType)); when(source.isStatic()).thenReturn(false); when(targetType.isArray()).thenReturn(true); when(targetType.getComponentType()).thenReturn(componentType); when(componentType.getStackSize()).thenReturn(StackSize.SINGLE); when(target.getType()).thenReturn(targetType); when(target.getDeclaredAnnotations()).thenReturn(new AnnotationList.Empty()); when(rawComponentType.getInternalName()).thenReturn(FOO); MethodDelegationBinder.ParameterBinding<?> parameterBinding = AllArguments.Binder.INSTANCE.bind( annotationDescription, source, target, implementationTarget, assigner); MethodVisitor methodVisitor = mock(MethodVisitor.class); Implementation.Context implementationContext = mock(Implementation.Context.class); StackManipulation.Size size = parameterBinding.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(1)); assertThat(size.getMaximalSize(), is(1)); verify(methodVisitor).visitInsn(Opcodes.ICONST_0); verify(methodVisitor).visitTypeInsn(Opcodes.ANEWARRAY, FOO); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(implementationContext); assertThat(parameterBinding.isValid(), is(true)); verify(source, atLeast(1)).getParameters(); verify(source, atLeast(1)).isStatic(); verify(target, atLeast(1)).getType(); verify(target, atLeast(1)).getDeclaredAnnotations(); verify(assigner).assign(firstSourceType, componentType, Assigner.Typing.STATIC); verify(assigner).assign(secondSourceType, componentType, Assigner.Typing.STATIC); verifyNoMoreInteractions(assigner); }
@Override public AnnotationAppender onWildcard(TypeDescription.Generic wildcard) { TypeList.Generic lowerBounds = wildcard.getLowerBounds(); return (lowerBounds.isEmpty() ? wildcard.getUpperBounds().getOnly() : lowerBounds.getOnly()) .accept( new ForTypeAnnotations( apply(wildcard, typePath), annotationValueFilter, typeReference, typePath + WILDCARD_TYPE_PATH)); }
@Test(expected = IllegalStateException.class) public void testNonArrayTypeBinding() throws Exception { when(target.getIndex()).thenReturn(0); TypeDescription.Generic targetType = mock(TypeDescription.Generic.class); TypeDescription rawTargetType = mock(TypeDescription.class); when(targetType.asErasure()).thenReturn(rawTargetType); when(targetType.isArray()).thenReturn(false); when(target.getType()).thenReturn(targetType); AllArguments.Binder.INSTANCE.bind( annotationDescription, source, target, implementationTarget, assigner); }
@Override public void apply( MethodVisitor methodVisitor, MethodDescription methodDescription, AnnotationValueFilter annotationValueFilter) { AnnotationAppender annotationAppender = new AnnotationAppender.Default(new AnnotationAppender.Target.OnMethod(methodVisitor)); annotationAppender = methodDescription .getReturnType() .accept( AnnotationAppender.ForTypeAnnotations.ofMethodReturnType( annotationAppender, annotationValueFilter)); annotationAppender = AnnotationAppender.ForTypeAnnotations.ofTypeVariable( annotationAppender, annotationValueFilter, AnnotationAppender.ForTypeAnnotations.VARIABLE_ON_INVOKEABLE, methodDescription.getTypeVariables()); for (AnnotationDescription annotation : methodDescription.getDeclaredAnnotations()) { annotationAppender = annotationAppender.append(annotation, annotationValueFilter); } for (ParameterDescription parameterDescription : methodDescription.getParameters()) { AnnotationAppender parameterAppender = new AnnotationAppender.Default( new AnnotationAppender.Target.OnMethodParameter( methodVisitor, parameterDescription.getIndex())); parameterAppender = parameterDescription .getType() .accept( AnnotationAppender.ForTypeAnnotations.ofMethodParameterType( parameterAppender, annotationValueFilter, parameterDescription.getIndex())); for (AnnotationDescription annotation : parameterDescription.getDeclaredAnnotations()) { parameterAppender = parameterAppender.append(annotation, annotationValueFilter); } } int exceptionTypeIndex = 0; for (TypeDescription.Generic exceptionType : methodDescription.getExceptionTypes()) { annotationAppender = exceptionType.accept( AnnotationAppender.ForTypeAnnotations.ofExceptionType( annotationAppender, annotationValueFilter, exceptionTypeIndex++)); } }
@Override public AnnotationAppender onParameterizedType(TypeDescription.Generic parameterizedType) { StringBuilder typePath = new StringBuilder(this.typePath); for (int index = 0; index < parameterizedType.asErasure().getSegmentCount(); index++) { typePath = typePath.append(INNER_CLASS_PATH); } AnnotationAppender annotationAppender = apply(parameterizedType, typePath.toString()); TypeDescription.Generic ownerType = parameterizedType.getOwnerType(); if (ownerType != null) { annotationAppender = ownerType.accept( new ForTypeAnnotations( annotationAppender, annotationValueFilter, typeReference, this.typePath)); } int index = 0; for (TypeDescription.Generic typeArgument : parameterizedType.getTypeArguments()) { annotationAppender = typeArgument.accept( new ForTypeAnnotations( annotationAppender, annotationValueFilter, typeReference, typePath.toString() + index++ + INDEXED_TYPE_DELIMITER)); } return annotationAppender; }
/** * Writes all annotations of the supplied type to this instance's annotation appender. * * @param typeDescription The type of what all annotations should be written of. * @param typePath The type path to use. * @return The resulting annotation appender. */ private AnnotationAppender apply(TypeDescription.Generic typeDescription, String typePath) { AnnotationAppender annotationAppender = this.annotationAppender; for (AnnotationDescription annotationDescription : typeDescription.getDeclaredAnnotations()) { annotationAppender = annotationAppender.append( annotationDescription, annotationValueFilter, typeReference, typePath); } return annotationAppender; }
@Override public AnnotationAppender onNonGenericType(TypeDescription.Generic typeDescription) { StringBuilder typePath = new StringBuilder(this.typePath); for (int index = 0; index < typeDescription.asErasure().getSegmentCount(); index++) { typePath = typePath.append(INNER_CLASS_PATH); } AnnotationAppender annotationAppender = apply(typeDescription, typePath.toString()); if (typeDescription.isArray()) { annotationAppender = typeDescription .getComponentType() .accept( new ForTypeAnnotations( annotationAppender, annotationValueFilter, typeReference, this.typePath + COMPONENT_TYPE_PATH)); // Impossible to be inner class } return annotationAppender; }
@Override public AnnotationAppender onGenericArray(TypeDescription.Generic genericArray) { return genericArray .getComponentType() .accept( new ForTypeAnnotations( apply(genericArray, typePath), annotationValueFilter, typeReference, typePath + COMPONENT_TYPE_PATH)); }
@Override @Before @SuppressWarnings("unchecked") public void setUp() throws Exception { super.setUp(); when(firstSourceType.getStackSize()).thenReturn(StackSize.SINGLE); when(secondSourceType.getStackSize()).thenReturn(StackSize.SINGLE); when(componentType.asErasure()).thenReturn(rawComponentType); when(targetType.getComponentType()).thenReturn(componentType); when(targetType.asErasure()).thenReturn(rawTargetType); when(firstSourceType.asGenericType()).thenReturn(firstSourceType); when(firstSourceType.accept(any(TypeDescription.Generic.Visitor.class))) .thenReturn(firstSourceType); when(secondSourceType.asGenericType()).thenReturn(secondSourceType); when(secondSourceType.accept(any(TypeDescription.Generic.Visitor.class))) .thenReturn(secondSourceType); }
/** * Appends all supplied type variables to the supplied method appender. * * @param annotationAppender The annotation appender to write any type annotation to. * @param annotationValueFilter The annotation value filter to apply. * @param variableOnType {@code true} if the type variables are declared by a type, {@code * false} if they are declared by a method. * @param subListIndex The index of the first type variable to append. All previous type * variables are ignored. * @param typeVariables The type variables to append. * @return The resulting annotation appender. */ public static AnnotationAppender ofTypeVariable( AnnotationAppender annotationAppender, AnnotationValueFilter annotationValueFilter, boolean variableOnType, int subListIndex, List<? extends TypeDescription.Generic> typeVariables) { int typeVariableIndex = subListIndex, variableBaseReference, variableBoundBaseBase; if (variableOnType) { variableBaseReference = TypeReference.CLASS_TYPE_PARAMETER; variableBoundBaseBase = TypeReference.CLASS_TYPE_PARAMETER_BOUND; } else { variableBaseReference = TypeReference.METHOD_TYPE_PARAMETER; variableBoundBaseBase = TypeReference.METHOD_TYPE_PARAMETER_BOUND; } for (TypeDescription.Generic typeVariable : typeVariables.subList(subListIndex, typeVariables.size())) { int typeReference = TypeReference.newTypeParameterReference(variableBaseReference, typeVariableIndex) .getValue(); for (AnnotationDescription annotationDescription : typeVariable.getDeclaredAnnotations()) { annotationAppender = annotationAppender.append( annotationDescription, annotationValueFilter, typeReference, EMPTY_TYPE_PATH); } int boundIndex = !typeVariable.getUpperBounds().get(0).getSort().isTypeVariable() && typeVariable.getUpperBounds().get(0).asErasure().isInterface() ? 1 : 0; for (TypeDescription.Generic typeBound : typeVariable.getUpperBounds()) { annotationAppender = typeBound.accept( new ForTypeAnnotations( annotationAppender, annotationValueFilter, TypeReference.newTypeParameterBoundReference( variableBoundBaseBase, typeVariableIndex, boundIndex++))); } typeVariableIndex++; } return annotationAppender; }