@Override public MethodDelegationBinder.ParameterBinding<?> bind( AnnotationDescription.Loadable<FieldValue> annotation, MethodDescription source, ParameterDescription target, Implementation.Target implementationTarget, Assigner assigner) { FieldLocator.Resolution resolution = FieldLocator.of( annotation.getValue(DEFINING_TYPE, TypeDescription.class), implementationTarget.getTypeDescription()) .resolve(annotation.getValue(FIELD_NAME, String.class), source.isStatic()); if (resolution.isResolved()) { StackManipulation stackManipulation = new StackManipulation.Compound( resolution.getFieldDescription().isStatic() ? StackManipulation.Trivial.INSTANCE : MethodVariableAccess.REFERENCE.loadOffset(0), FieldAccess.forField(resolution.getFieldDescription()).getter(), assigner.assign( resolution.getFieldDescription().getType().asErasure(), target.getType().asErasure(), RuntimeType.Verifier.check(target))); return stackManipulation.isValid() ? new MethodDelegationBinder.ParameterBinding.Anonymous(stackManipulation) : MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE; } else { return MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE; } }
@Test public void testBoxing() throws Exception { StackManipulation boxingStackManipulation = PrimitiveBoxingDelegate.forPrimitive(primitiveTypeDescription) .assignBoxedTo(targetType, chainedAssigner, Assigner.Typing.STATIC); assertThat(boxingStackManipulation.isValid(), is(true)); StackManipulation.Size size = boxingStackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(sizeChange)); assertThat(size.getMaximalSize(), is(0)); verify(primitiveTypeDescription).represents(primitiveType); verify(primitiveTypeDescription, atLeast(1)).represents(any(Class.class)); verifyNoMoreInteractions(primitiveTypeDescription); verify(chainedAssigner) .assign(referenceTypeDescription.asGenericType(), targetType, Assigner.Typing.STATIC); verifyNoMoreInteractions(chainedAssigner); verify(methodVisitor) .visitMethodInsn( Opcodes.INVOKESTATIC, referenceTypeDescription.getInternalName(), VALUE_OF, boxingMethodDescriptor, false); verifyNoMoreInteractions(methodVisitor); verify(stackManipulation, atLeast(1)).isValid(); verify(stackManipulation).apply(methodVisitor, implementationContext); verifyNoMoreInteractions(stackManipulation); }
@Test public void testAssignmentEqual() throws Exception { StackManipulation stackManipulation = Assigner.EqualTypesOnly.INSTANCE.assign(first, first, dynamicallyTyped); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); }
@Test(expected = IllegalStateException.class) public void testTargetToSourceAssignable() throws Exception { defineAssignability(false, true); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign( sourceTypeDescription, targetTypeDescription, false); assertThat(stackManipulation.isValid(), is(false)); stackManipulation.apply(methodVisitor, implementationContext); }
@Test(expected = IllegalStateException.class) public void testPrimitiveAssignabilityWhenNotEqual() throws Exception { TypeDescription primitiveType = new TypeDescription.ForLoadedType(int.class); // Note: cannot mock equals TypeDescription otherPrimitiveType = new TypeDescription.ForLoadedType(long.class); // Note: cannot mock equals StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(primitiveType, otherPrimitiveType, true); assertThat(stackManipulation.isValid(), is(false)); stackManipulation.apply(methodVisitor, implementationContext); }
@Before public void setUp() throws Exception { when(chainedAssigner.assign( any(TypeDescription.Generic.class), any(TypeDescription.Generic.class), any(Assigner.Typing.class))) .thenReturn(stackManipulation); when(stackManipulation.isValid()).thenReturn(true); when(stackManipulation.apply(any(MethodVisitor.class), any(Implementation.Context.class))) .thenReturn(StackSize.ZERO.toIncreasingSize()); }
@Before public void setUp() throws Exception { when(sourceTypeDescription.represents(sourceType)).thenReturn(true); when(sourceTypeDescription.isPrimitive()).thenReturn(true); when(targetTypeDescription.represents(targetType)).thenReturn(true); when(targetTypeDescription.isPrimitive()).thenReturn(false); when(chainedStackManipulation.isValid()).thenReturn(true); when(chainedAssigner.assign( any(TypeDescription.class), any(TypeDescription.class), any(Assigner.Typing.class))) .thenReturn(chainedStackManipulation); primitiveAssigner = new PrimitiveTypeAwareAssigner(chainedAssigner); }
@Test public void testPrimitiveAssignabilityWhenEqual() throws Exception { TypeDescription primitiveType = new TypeDescription.ForLoadedType(int.class); // Note: cannot mock equals StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(primitiveType, primitiveType, true); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verifyZeroInteractions(methodVisitor); }
@Test public void testSourceToTargetAssignable() throws Exception { defineAssignability(true, false); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign( sourceTypeDescription, targetTypeDescription, false); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verifyZeroInteractions(methodVisitor); }
@Test public void testTargetToSourceAssignableRuntimeType() throws Exception { defineAssignability(false, false); when(targetTypeDescription.getInternalName()).thenReturn(FOO); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign( sourceTypeDescription, targetTypeDescription, true); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verify(methodVisitor).visitTypeInsn(Opcodes.CHECKCAST, FOO); verifyNoMoreInteractions(methodVisitor); }
/** * Blueprint method that for applying the actual implementation. * * @param methodVisitor The method visitor to which the implementation is applied to. * @param implementationContext The implementation context for the given implementation. * @param instrumentedMethod The instrumented method that is target of the implementation. * @param fixedValueType A description of the type of the fixed value that is loaded by the {@code * valueLoadingInstruction}. * @param valueLoadingInstruction A stack manipulation that represents the loading of the fixed * value onto the operand stack. * @return A representation of the stack and variable array sized that are required for this * implementation. */ protected ByteCodeAppender.Size apply( MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod, TypeDescription.Generic fixedValueType, StackManipulation valueLoadingInstruction) { StackManipulation assignment = assigner.assign(fixedValueType, instrumentedMethod.getReturnType(), typing); if (!assignment.isValid()) { throw new IllegalArgumentException( "Cannot return value of type " + fixedValueType + " for " + instrumentedMethod); } StackManipulation.Size stackSize = new StackManipulation.Compound( valueLoadingInstruction, assignment, MethodReturn.returning(instrumentedMethod.getReturnType().asErasure())) .apply(methodVisitor, implementationContext); return new ByteCodeAppender.Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); }
@Test public void testBoxingAssignment() { StackManipulation stackManipulation = primitiveAssigner.assign( sourceTypeDescription, targetTypeDescription, Assigner.Typing.STATIC); assertThat(stackManipulation.isValid(), is(assignable)); verify(chainedStackManipulation).isValid(); verifyNoMoreInteractions(chainedStackManipulation); verify(sourceTypeDescription, atLeast(0)).represents(any(Class.class)); verify(sourceTypeDescription).represents(sourceType); verify(sourceTypeDescription, atLeast(1)).isPrimitive(); verifyNoMoreInteractions(sourceTypeDescription); verify(targetTypeDescription, atLeast(1)).isPrimitive(); verifyNoMoreInteractions(targetTypeDescription); verify(chainedAssigner) .assign( new TypeDescription.ForLoadedType(targetType), targetTypeDescription, Assigner.Typing.STATIC); verifyNoMoreInteractions(chainedAssigner); }
@Test public void testAssignmentNotEqual() throws Exception { StackManipulation stackManipulation = Assigner.EqualTypesOnly.INSTANCE.assign(first, second, dynamicallyTyped); assertThat(stackManipulation.isValid(), is(false)); }
@Override public boolean isValid() { return stackManipulation.isValid(); }