@Override protected boolean resolve(TypeDefinition typeDefinition) { return typeDefinition.represents(String.class); } },
/** * Locates the delegate that is capable of widening the given type into another type. * * @param typeDefinition A non-void primitive type that is to be widened into another type. * @return A delegate for the given type. */ public static PrimitiveWideningDelegate forPrimitive(TypeDefinition typeDefinition) { if (typeDefinition.represents(boolean.class)) { return BOOLEAN; } else if (typeDefinition.represents(byte.class)) { return BYTE; } else if (typeDefinition.represents(short.class)) { return SHORT; } else if (typeDefinition.represents(char.class)) { return CHARACTER; } else if (typeDefinition.represents(int.class)) { return INTEGER; } else if (typeDefinition.represents(long.class)) { return LONG; } else if (typeDefinition.represents(float.class)) { return FLOAT; } else if (typeDefinition.represents(double.class)) { return DOUBLE; } else { throw new IllegalArgumentException("Not a primitive, non-void type: " + typeDefinition); } }
/** * Attempts to widen the represented type into another type. * * @param typeDefinition A non-void primitive type that is the expected result of the widening operation. * @return A widening instruction or an illegal stack manipulation if such widening is not legitimate. */ public StackManipulation widenTo(TypeDefinition typeDefinition) { if (typeDefinition.represents(boolean.class)) { return toBooleanStackManipulation; } else if (typeDefinition.represents(byte.class)) { return toByteStackManipulation; } else if (typeDefinition.represents(short.class)) { return toShortStackManipulation; } else if (typeDefinition.represents(char.class)) { return toCharacterStackManipulation; } else if (typeDefinition.represents(int.class)) { return toIntegerStackManipulation; } else if (typeDefinition.represents(long.class)) { return toLongStackManipulation; } else if (typeDefinition.represents(float.class)) { return toFloatStackManipulation; } else if (typeDefinition.represents(double.class)) { return toDoubleStackManipulation; } else { throw new IllegalArgumentException("Not a primitive non-void type: " + typeDefinition); } }
/** * Locates a boxing delegate for a given primitive type. * * @param typeDefinition A non-void primitive type. * @return A delegate capable of boxing the given primitive type. */ public static PrimitiveBoxingDelegate forPrimitive(TypeDefinition typeDefinition) { if (typeDefinition.represents(boolean.class)) { return BOOLEAN; } else if (typeDefinition.represents(byte.class)) { return BYTE; } else if (typeDefinition.represents(short.class)) { return SHORT; } else if (typeDefinition.represents(char.class)) { return CHARACTER; } else if (typeDefinition.represents(int.class)) { return INTEGER; } else if (typeDefinition.represents(long.class)) { return LONG; } else if (typeDefinition.represents(float.class)) { return FLOAT; } else if (typeDefinition.represents(double.class)) { return DOUBLE; } else { throw new IllegalArgumentException("Not a non-void, primitive type: " + typeDefinition); } }
/** * Creates a stack assignment that loads the default value for a given type. * * @param typeDefinition The type for which a default value should be loaded onto the operand stack. * @return A stack manipulation loading the default value for the given type. */ public static StackManipulation of(TypeDefinition typeDefinition) { if (typeDefinition.isPrimitive()) { if (typeDefinition.represents(long.class)) { return LONG; } else if (typeDefinition.represents(double.class)) { return DOUBLE; } else if (typeDefinition.represents(float.class)) { return FLOAT; } else if (typeDefinition.represents(void.class)) { return VOID; } else { return INTEGER; } } else { return REFERENCE; } }
/** * Returns a method return corresponding to a given type. * * @param typeDefinition The type to be returned. * @return The stack manipulation representing the method return. */ public static StackManipulation of(TypeDefinition typeDefinition) { if (typeDefinition.isPrimitive()) { if (typeDefinition.represents(long.class)) { return LONG; } else if (typeDefinition.represents(double.class)) { return DOUBLE; } else if (typeDefinition.represents(float.class)) { return FLOAT; } else if (typeDefinition.represents(void.class)) { return VOID; } else { return INTEGER; } } else { return REFERENCE; } }
/** * Locates an array accessor by the array's component type. * * @param componentType The array's component type. * @return An array accessor for the given type. */ public static ArrayAccess of(TypeDefinition componentType) { if (!componentType.isPrimitive()) { return REFERENCE; } else if (componentType.represents(boolean.class) || componentType.represents(byte.class)) { return BYTE; } else if (componentType.represents(short.class)) { return SHORT; } else if (componentType.represents(char.class)) { return CHARACTER; } else if (componentType.represents(int.class)) { return INTEGER; } else if (componentType.represents(long.class)) { return LONG; } else if (componentType.represents(float.class)) { return FLOAT; } else if (componentType.represents(double.class)) { return DOUBLE; } else { throw new IllegalArgumentException("Not a legal array type: " + componentType); } }
/** * Locates the correct accessor for a variable of a given type. * * @param typeDefinition The type of the variable to be loaded. * @return An accessor for the given type. */ public static MethodVariableAccess of(TypeDefinition typeDefinition) { if (typeDefinition.isPrimitive()) { if (typeDefinition.represents(long.class)) { return LONG; } else if (typeDefinition.represents(double.class)) { return DOUBLE; } else if (typeDefinition.represents(float.class)) { return FLOAT; } else if (typeDefinition.represents(void.class)) { throw new IllegalArgumentException("Variable type cannot be void"); } else { return INTEGER; } } else { return REFERENCE; } }
/** * Creates a suitable array creator for the given component type. * * @param componentType The component type of the array to be created. * @return A suitable array creator. */ private static ArrayCreator makeArrayCreatorFor(TypeDefinition componentType) { if (!componentType.isPrimitive()) { return new ArrayCreator.ForReferenceType(componentType.asErasure()); } else if (componentType.represents(boolean.class)) { return ArrayCreator.ForPrimitiveType.BOOLEAN; } else if (componentType.represents(byte.class)) { return ArrayCreator.ForPrimitiveType.BYTE; } else if (componentType.represents(short.class)) { return ArrayCreator.ForPrimitiveType.SHORT; } else if (componentType.represents(char.class)) { return ArrayCreator.ForPrimitiveType.CHARACTER; } else if (componentType.represents(int.class)) { return ArrayCreator.ForPrimitiveType.INTEGER; } else if (componentType.represents(long.class)) { return ArrayCreator.ForPrimitiveType.LONG; } else if (componentType.represents(float.class)) { return ArrayCreator.ForPrimitiveType.FLOAT; } else if (componentType.represents(double.class)) { return ArrayCreator.ForPrimitiveType.DOUBLE; } else { throw new IllegalArgumentException("Cannot create array of type " + componentType); } }
/** * Resolves a relocation handler for a given type. * * @param typeDefinition The type to be resolved for a relocation attempt. * @param inverted {@code true} if the relocation should be applied for any non-default value of a type. * @return An appropriate relocation handler. */ protected static RelocationHandler of(TypeDefinition typeDefinition, boolean inverted) { ForValue skipDispatcher; if (typeDefinition.represents(long.class)) { skipDispatcher = LONG; } else if (typeDefinition.represents(float.class)) { skipDispatcher = FLOAT; } else if (typeDefinition.represents(double.class)) { skipDispatcher = DOUBLE; } else if (typeDefinition.represents(void.class)) { throw new IllegalStateException("Cannot skip on default value for void return type"); } else if (typeDefinition.isPrimitive()) { // anyOf(byte, short, char, int) skipDispatcher = INTEGER; } else { skipDispatcher = REFERENCE; } return inverted ? skipDispatcher.new Inverted() : skipDispatcher; }
/** * {@inheritDoc} */ public int variable(int index) { return (instrumentedMethod.isStatic() ? 0 : 1) + instrumentedMethod.getParameters().size() + (exitType.represents(void.class) ? 0 : 1) + namedTypes.size() + (enterType.represents(void.class) ? 0 : 1) + index; }
/** * {@inheritDoc} */ public int variable(int index) { return index < (instrumentedMethod.isStatic() ? 0 : 1) + instrumentedMethod.getParameters().size() ? index : index + (exitType.represents(void.class) ? 0 : 1) + StackSize.of(namedTypes.values()) + (enterType.represents(void.class) ? 0 : 1); }
/** * Creates a new factory for creating a {@link ForExitValue} offset mapping. * * @param typeDefinition The supplied type of the enter method. * @return An appropriate offset mapping factory. */ protected static OffsetMapping.Factory<Exit> of(TypeDefinition typeDefinition) { return typeDefinition.represents(void.class) ? new Illegal<Exit>(Exit.class) : new Factory(typeDefinition); }
/** * {@inheritDoc} */ public void onEnd(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodSizeHandler.ForAdvice methodSizeHandler, StackMapFrameHandler.ForAdvice stackMapFrameHandler, TypeDefinition returnType) { methodVisitor.visitLabel(endOfMethod); stackMapFrameHandler.injectExceptionFrame(methodVisitor); methodSizeHandler.requireStackSize(1 + exceptionHandler.apply(methodVisitor, implementationContext).getMaximalSize()); if (returnType.represents(boolean.class) || returnType.represents(byte.class) || returnType.represents(short.class) || returnType.represents(char.class) || returnType.represents(int.class)) { methodVisitor.visitInsn(Opcodes.ICONST_0); } else if (returnType.represents(long.class)) { methodVisitor.visitInsn(Opcodes.LCONST_0); } else if (returnType.represents(float.class)) { methodVisitor.visitInsn(Opcodes.FCONST_0); } else if (returnType.represents(double.class)) { methodVisitor.visitInsn(Opcodes.DCONST_0); } else if (!returnType.represents(void.class)) { methodVisitor.visitInsn(Opcodes.ACONST_NULL); } }
/** * Creates a new factory for creating a {@link ForEnterValue} offset mapping. * * @param typeDefinition The supplied type of the enter advice. * @return An appropriate offset mapping factory. */ protected static OffsetMapping.Factory<Enter> of(TypeDefinition typeDefinition) { return typeDefinition.represents(void.class) ? new Illegal<Enter>(Enter.class) : new Factory(typeDefinition); }
/** * {@inheritDoc} */ public void initialize() { for (Map.Entry<Integer, TypeDefinition> typeDefinition : resolveInitializationTypes(argumentHandler).entrySet()) { if (typeDefinition.getValue().represents(boolean.class) || typeDefinition.getValue().represents(byte.class) || typeDefinition.getValue().represents(short.class) || typeDefinition.getValue().represents(char.class) || typeDefinition.getValue().represents(int.class)) { methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitVarInsn(Opcodes.ISTORE, typeDefinition.getKey()); } else if (typeDefinition.getValue().represents(long.class)) { methodVisitor.visitInsn(Opcodes.LCONST_0); methodVisitor.visitVarInsn(Opcodes.LSTORE, typeDefinition.getKey()); } else if (typeDefinition.getValue().represents(float.class)) { methodVisitor.visitInsn(Opcodes.FCONST_0); methodVisitor.visitVarInsn(Opcodes.FSTORE, typeDefinition.getKey()); } else if (typeDefinition.getValue().represents(double.class)) { methodVisitor.visitInsn(Opcodes.DCONST_0); methodVisitor.visitVarInsn(Opcodes.DSTORE, typeDefinition.getKey()); } else { methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitVarInsn(Opcodes.ASTORE, typeDefinition.getKey()); } methodSizeHandler.requireStackSize(typeDefinition.getValue().getStackSize().getSize()); } }
/** * {@inheritDoc} */ public FieldDefinition.Optional<S> defineProperty(String name, TypeDefinition type, boolean readOnly) { if (name.length() == 0) { throw new IllegalArgumentException("A bean property cannot have an empty name"); } else if (type.represents(void.class)) { throw new IllegalArgumentException("A bean property cannot have a void type"); } DynamicType.Builder<S> builder = this; FieldManifestation fieldManifestation; if (!readOnly) { builder = builder .defineMethod("set" + Character.toUpperCase(name.charAt(0)) + name.substring(1), void.class, Visibility.PUBLIC) .withParameters(type) .intercept(FieldAccessor.ofField(name)); fieldManifestation = FieldManifestation.PLAIN; } else { fieldManifestation = FieldManifestation.FINAL; } return builder .defineMethod((type.represents(boolean.class) || type.represents(Boolean.class) ? "is" : "get") + Character.toUpperCase(name.charAt(0)) + name.substring(1), type, Visibility.PUBLIC) .intercept(FieldAccessor.ofField(name)) .defineField(name, type, Visibility.PRIVATE, fieldManifestation); }
/** * {@inheritDoc} */ public StackManipulation resolveIncrement(int value) { return typeDefinition.represents(int.class) ? MethodVariableAccess.of(typeDefinition).increment(offset, value) : new StackManipulation.Compound(resolveRead(), IntegerConstant.forValue(1), Addition.INTEGER, resolveWrite()); } }
@Override protected HashCodeMethod hashCodeMethod(TypeDescription instrumentedType) { TypeDefinition typeDefinition = instrumentedType.getSuperClass(); while (typeDefinition != null && !typeDefinition.represents(Object.class)) { if (typeDefinition.asErasure().getDeclaredAnnotations().isAnnotationPresent(Enhance.class)) { return HashCodeMethod.usingSuperClassOffset(); } MethodList<?> hashCode = typeDefinition.getDeclaredMethods().filter(isHashCode()); if (!hashCode.isEmpty()) { return hashCode.getOnly().isAbstract() ? HashCodeMethod.usingDefaultOffset() : HashCodeMethod.usingSuperClassOffset(); } typeDefinition = typeDefinition.getSuperClass(); } return HashCodeMethod.usingDefaultOffset(); }
@Override protected EqualsMethod equalsMethod(TypeDescription instrumentedType) { TypeDefinition typeDefinition = instrumentedType.getSuperClass(); while (typeDefinition != null && !typeDefinition.represents(Object.class)) { if (typeDefinition.asErasure().getDeclaredAnnotations().isAnnotationPresent(Enhance.class)) { return EqualsMethod.requiringSuperClassEquality(); } MethodList<?> hashCode = typeDefinition.getDeclaredMethods().filter(isHashCode()); if (!hashCode.isEmpty()) { return hashCode.getOnly().isAbstract() ? EqualsMethod.isolated() : EqualsMethod.requiringSuperClassEquality(); } typeDefinition = typeDefinition.getSuperClass().asErasure(); } return EqualsMethod.isolated(); } },