/** * {@inheritDoc} */ public InDefinedShape asDefined() { return methodDescription.getParameters().get(index); } }
@Override protected ParameterDescription resolve(MethodDescription instrumentedMethod) { ParameterList<?> parameters = instrumentedMethod.getParameters(); if (parameters.size() <= index) { throw new IllegalStateException(instrumentedMethod + " does not define an index " + index); } else { return parameters.get(index); } }
/** * {@inheritDoc} */ public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) { if (instrumentedMethod.getParameters().size() <= index) { throw new IllegalStateException(instrumentedMethod + " does not declare a parameter with index " + index); } else if (!instrumentedMethod.getParameters().get(index).getType().isArray()) { throw new IllegalStateException("Cannot access an item from non-array parameter " + instrumentedMethod.getParameters().get(index)); } return Collections.<ArgumentLoader>singletonList(new ForMethodParameterArrayElement(instrumentedMethod.getParameters().get(index), arrayIndex)); } }
/** * {@inheritDoc} */ public Resolved resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Assigner assigner, Assigner.Typing typing) { ParameterList<?> parameters = instrumentedMethod.getParameters(); if (index >= parameters.size()) { throw new IllegalStateException("No parameter " + index + " for " + instrumentedMethod); } return doResolve(MethodVariableAccess.load(parameters.get(index)), parameters.get(index).getType(), assigner, typing); }
/** * Binds the supplied annotation to the supplied parameter's argument. * * @param type The type of the annotation being bound. * @param constructor The constructor that defines the parameter. * @param index The index of the parameter. * @param <T> The annotation type. * @return A new builder for an advice that considers the supplied annotation type during binding. */ public <T extends Annotation> WithCustomMapping bind(Class<T> type, Constructor<?> constructor, int index) { if (index < 0) { throw new IllegalArgumentException("A parameter cannot be negative: " + index); } else if (constructor.getParameterTypes().length <= index) { throw new IllegalArgumentException(constructor + " does not declare a parameter with index " + index); } return bind(type, new MethodDescription.ForLoadedConstructor(constructor).getParameters().get(index)); }
/** * Binds the supplied annotation to the supplied parameter's argument. * * @param type The type of the annotation being bound. * @param method The method that defines the parameter. * @param index The index of the parameter. * @param <T> The annotation type. * @return A new builder for an advice that considers the supplied annotation type during binding. */ public <T extends Annotation> WithCustomMapping bind(Class<T> type, Method method, int index) { if (index < 0) { throw new IllegalArgumentException("A parameter cannot be negative: " + index); } else if (method.getParameterTypes().length <= index) { throw new IllegalArgumentException(method + " does not declare a parameter with index " + index); } return bind(type, new MethodDescription.ForLoadedMethod(method).getParameters().get(index)); }
/** * {@inheritDoc} */ public TargetHandler.Resolved resolve(MethodDescription instrumentedMethod) { if (instrumentedMethod.getParameters().size() < index) { throw new IllegalArgumentException(instrumentedMethod + " does not have a parameter with index " + index); } return new Resolved(instrumentedMethod.getParameters().get(index)); }
/** * {@inheritDoc} */ public StackManipulation ofIndex(TypeDescription parameterType, int index) { TypeDescription targetType = bridgeTarget.getParameters().get(index).getType().asErasure(); return parameterType.equals(targetType) ? Trivial.INSTANCE : TypeCasting.to(targetType); } }
/** * {@inheritDoc} */ public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) { if (instrumentedMethod.getParameters().size() <= index) { throw new IllegalStateException(instrumentedMethod + " does not declare a parameter with index " + index); } else if (!instrumentedMethod.getParameters().get(index).getType().isArray()) { throw new IllegalStateException("Cannot access an item from non-array parameter " + instrumentedMethod.getParameters().get(index)); } List<ArgumentLoader> argumentLoaders = new ArrayList<ArgumentLoader>(instrumentedMethod.getParameters().size()); for (int index = 0; index < invokedMethod.getParameters().size(); index++) { argumentLoaders.add(new ForMethodParameterArrayElement(instrumentedMethod.getParameters().get(this.index), index++)); } return argumentLoaders; } }
/** * {@inheritDoc} */ protected StackManipulation resolve(Void unused, FieldDescription fieldDescription, TypeDescription instrumentedType, MethodDescription instrumentedMethod) { if (instrumentedMethod.getParameters().size() <= index) { throw new IllegalStateException(instrumentedMethod + " does not define a parameter with index " + index); } else { return new StackManipulation.Compound( MethodVariableAccess.load(instrumentedMethod.getParameters().get(index)), assigner.assign(instrumentedMethod.getParameters().get(index).getType(), fieldDescription.getType(), typing) ); } }
/** * {@inheritDoc} */ public boolean isConstantBootstrap() { ParameterList<?> parameters = getParameters(); return !parameters.isEmpty() && getParameters().get(0).getType().asErasure().equals(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub()) && isBootstrap(TypeDescription.CLASS); }
/** * {@inheritDoc} */ public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) { ParameterDescription parameterDescription = instrumentedMethod.getParameters().get(index); StackManipulation stackManipulation = new StackManipulation.Compound( MethodVariableAccess.load(parameterDescription), assigner.assign(parameterDescription.getType(), target.getType(), typing)); if (!stackManipulation.isValid()) { throw new IllegalStateException("Cannot assign " + parameterDescription + " to " + target + " for " + instrumentedMethod); } return stackManipulation; }
/** * Extracts the only method of a given type and validates to fit the constraints of the morph annotation. * * @param typeDescription The type to extract the method from. * @return The only method after validation. */ private static MethodDescription onlyMethod(TypeDescription typeDescription) { if (!typeDescription.isInterface()) { throw new IllegalArgumentException(typeDescription + " is not an interface"); } else if (!typeDescription.getInterfaces().isEmpty()) { throw new IllegalArgumentException(typeDescription + " must not extend other interfaces"); } else if (!typeDescription.isPublic()) { throw new IllegalArgumentException(typeDescription + " is mot public"); } MethodList<?> methodCandidates = typeDescription.getDeclaredMethods().filter(isAbstract()); if (methodCandidates.size() != 1) { throw new IllegalArgumentException(typeDescription + " must declare exactly one abstract method"); } MethodDescription methodDescription = methodCandidates.getOnly(); if (!methodDescription.getReturnType().asErasure().represents(Object.class)) { throw new IllegalArgumentException(methodDescription + " does not return an Object-type"); } else if (methodDescription.getParameters().size() != 1 || !methodDescription.getParameters().get(0).getType().asErasure().represents(Object[].class)) { throw new IllegalArgumentException(methodDescription + " does not take a single argument of type Object[]"); } return methodDescription; }
/** * {@inheritDoc} */ public MethodDelegationBinder.ParameterBinding<?> bind(AnnotationDescription.Loadable<Argument> annotation, MethodDescription source, ParameterDescription target, Implementation.Target implementationTarget, Assigner assigner, Assigner.Typing typing) { Argument argument = annotation.loadSilent(); if (argument.value() < 0) { throw new IllegalArgumentException("@Argument annotation on " + target + " specifies negative index"); } else if (source.getParameters().size() <= argument.value()) { return MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE; } return argument.bindingMechanic().makeBinding(source.getParameters().get(argument.value()).getType(), target.getType(), argument.value(), assigner, typing, source.getParameters().get(argument.value()).getOffset()); } }
/** * Creates a binder by installing two proxy types which are implemented by this binder if a field getter * or a field setter is requested by using the * {@link FieldProxy} annotation. * * @param getterType The type which should be used for getter proxies. The type must * represent an interface which defines a single method which returns an * {@link java.lang.Object} return type and does not take any arguments. The use of generics * is permitted. * @param setterType The type which should be uses for setter proxies. The type must * represent an interface which defines a single method which returns {@code void} * and takes a single {@link java.lang.Object}-typed argument. The use of generics * is permitted. * @return A binder for the {@link FieldProxy} annotation. */ public static TargetMethodAnnotationDrivenBinder.ParameterBinder<FieldProxy> install(TypeDescription getterType, TypeDescription setterType) { MethodDescription.InDefinedShape getterMethod = onlyMethod(getterType); if (!getterMethod.getReturnType().asErasure().represents(Object.class)) { throw new IllegalArgumentException(getterMethod + " must take a single Object-typed parameter"); } else if (getterMethod.getParameters().size() != 0) { throw new IllegalArgumentException(getterMethod + " must not declare parameters"); } MethodDescription.InDefinedShape setterMethod = onlyMethod(setterType); if (!setterMethod.getReturnType().asErasure().represents(void.class)) { throw new IllegalArgumentException(setterMethod + " must return void"); } else if (setterMethod.getParameters().size() != 1 || !setterMethod.getParameters().get(0).getType().asErasure().represents(Object.class)) { throw new IllegalArgumentException(setterMethod + " must declare a single Object-typed parameters"); } return new Binder(getterMethod, setterMethod); }
/** * {@inheritDoc} */ public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { if (instrumentedMethod.getParameters().size() <= index) { throw new IllegalStateException(instrumentedMethod + " does not define a parameter with index " + index); } ParameterDescription parameterDescription = instrumentedMethod.getParameters().get(index); StackManipulation stackManipulation = new StackManipulation.Compound( MethodVariableAccess.load(parameterDescription), assigner.assign(parameterDescription.getType(), instrumentedMethod.getReturnType(), typing), MethodReturn.of(instrumentedMethod.getReturnType()) ); if (!stackManipulation.isValid()) { throw new IllegalStateException("Cannot assign " + instrumentedMethod.getReturnType() + " to " + parameterDescription); } return new Size(stackManipulation.apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize()); }
/** * {@inheritDoc} */ public Resolution resolve(MethodDescription source, MethodDelegationBinder.MethodBinding left, MethodDelegationBinder.MethodBinding right) { Resolution resolution = Resolution.UNKNOWN; ParameterList<?> sourceParameters = source.getParameters(); int leftExtra = 0, rightExtra = 0; for (int sourceParameterIndex = 0; sourceParameterIndex < sourceParameters.size(); sourceParameterIndex++) { ParameterIndexToken parameterIndexToken = new ParameterIndexToken(sourceParameterIndex); Integer leftParameterIndex = left.getTargetParameterIndex(parameterIndexToken); Integer rightParameterIndex = right.getTargetParameterIndex(parameterIndexToken); if (leftParameterIndex != null && rightParameterIndex != null) { resolution = resolution.merge(resolveRivalBinding(sourceParameters.get(sourceParameterIndex).getType().asErasure(), leftParameterIndex, left, rightParameterIndex, right)); } else if (leftParameterIndex != null /* && rightParameterIndex == null */) { leftExtra++; } else if (/*leftParameterIndex == null && */ rightParameterIndex != null) { rightExtra++; } } return resolution == Resolution.UNKNOWN ? resolveByScore(leftExtra - rightExtra) : resolution; }
/** * {@inheritDoc} */ public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { TypeDescription.Generic parameterType = instrumentedMethod.getParameters().get(0).getType(); MethodDescription setterMethod = methodAccessorFactory.registerSetterFor(fieldDescription, MethodAccessorFactory.AccessType.DEFAULT); StackManipulation.Size stackSize = new StackManipulation.Compound( fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE : new StackManipulation.Compound( MethodVariableAccess.loadThis(), FieldAccess.forField(typeDescription.getDeclaredFields() .filter((named(AccessorProxy.FIELD_NAME))).getOnly()).read()), MethodVariableAccess.of(parameterType).loadFrom(1), assigner.assign(parameterType, setterMethod.getParameters().get(0).getType(), Assigner.Typing.DYNAMIC), MethodInvocation.invoke(setterMethod), MethodReturn.VOID ).apply(methodVisitor, implementationContext); return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); } }
/** * {@inheritDoc} */ public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { FieldList<?> fieldList = instrumentedType.getDeclaredFields(); StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()]; int index = 0; for (FieldDescription fieldDescription : fieldList) { fieldLoading[index] = new StackManipulation.Compound( MethodVariableAccess.loadThis(), MethodVariableAccess.load(instrumentedMethod.getParameters().get(index)), FieldAccess.forField(fieldDescription).write() ); index++; } StackManipulation.Size stackSize = new StackManipulation.Compound( MethodVariableAccess.loadThis(), MethodInvocation.invoke(ConstructorCall.INSTANCE.objectTypeDefaultConstructor), new StackManipulation.Compound(fieldLoading), MethodReturn.VOID ).apply(methodVisitor, implementationContext); return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); } }
/** * {@inheritDoc} */ public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { FieldList<?> fieldList = instrumentedType.getDeclaredFields(); StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()]; int index = 0; for (FieldDescription fieldDescription : fieldList) { fieldLoading[index] = new StackManipulation.Compound( MethodVariableAccess.loadThis(), MethodVariableAccess.load(instrumentedMethod.getParameters().get(index)), FieldAccess.forField(fieldDescription).write() ); index++; } StackManipulation.Size stackSize = new StackManipulation.Compound( MethodVariableAccess.loadThis(), MethodInvocation.invoke(ConstructorCall.INSTANCE.objectTypeDefaultConstructor), new StackManipulation.Compound(fieldLoading), MethodReturn.VOID ).apply(methodVisitor, implementationContext); return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); } }