@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; } }
@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); }
/** * 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); }
/** * Creates a stack manipulation that boxes the represented primitive type and applies a chained * assignment to the result of this boxing operation. * * @param targetType The type that is target of the assignment operation. * @param chainedAssigner The assigner that is to be used to perform the chained assignment. * @param dynamicallyTyped If {@code true}, unsafe cast operations are allowed for performing an * assignment. * @return A stack manipulation that represents the described assignment operation. */ public StackManipulation assignBoxedTo( TypeDescription targetType, Assigner chainedAssigner, boolean dynamicallyTyped) { return new BoxingStackManipulation( chainedAssigner.assign(wrapperType, targetType, dynamicallyTyped)); }