/** * {@inheritDoc} */ public DynamicType.Builder<?> apply(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassFileLocator classFileLocator) { for (MethodDescription.InDefinedShape methodDescription : typeDescription.getDeclaredMethods() .filter(not(isBridge()).<MethodDescription>and(isAnnotatedWith(Enhance.class)))) { if (methodDescription.isAbstract()) { throw new IllegalStateException("Cannot cache the value of an abstract method: " + methodDescription); } else if (!methodDescription.getParameters().isEmpty()) { throw new IllegalStateException("Cannot cache the value of a method with parameters: " + methodDescription); } else if (methodDescription.getReturnType().represents(void.class)) { throw new IllegalStateException("Cannot cache void result for " + methodDescription); } String name = methodDescription.getDeclaredAnnotations().ofType(Enhance.class).loadSilent().value(); if (name.length() == 0) { name = methodDescription.getName() + NAME_INFIX + randomString.nextString(); } builder = builder .defineField(name, methodDescription.getReturnType().asErasure(), methodDescription.isStatic() ? Ownership.STATIC : Ownership.MEMBER, Visibility.PRIVATE, SyntheticState.SYNTHETIC, FieldPersistence.TRANSIENT) .visit(Advice.withCustomMapping() .bind(CacheField.class, new CacheFieldOffsetMapping(name)) .to(adviceByType.get(methodDescription.getReturnType().isPrimitive() ? methodDescription.getReturnType().asErasure() : TypeDescription.OBJECT), this.classFileLocator) .on(is(methodDescription))); } return builder; }
/** * Binds an annotation to a dynamically computed value. Whenever the {@link Advice} component discovers the given annotation on * a parameter of an advice method, the dynamic value is asked to provide a value that is then assigned to the parameter in question. * * @param offsetMapping The dynamic value that is computed for binding the parameter to a value. * @return A new builder for an advice that considers the supplied annotation type during binding. */ public WithCustomMapping bind(OffsetMapping.Factory<?> offsetMapping) { Map<Class<? extends Annotation>, OffsetMapping.Factory<?>> offsetMappings = new HashMap<Class<? extends Annotation>, OffsetMapping.Factory<?>>(this.offsetMappings); if (!offsetMapping.getAnnotationType().isAnnotation()) { throw new IllegalArgumentException("Not an annotation type: " + offsetMapping.getAnnotationType()); } else if (offsetMappings.put(offsetMapping.getAnnotationType(), offsetMapping) != null) { throw new IllegalArgumentException("Annotation type already mapped: " + offsetMapping.getAnnotationType()); } return new WithCustomMapping(offsetMappings); }
/** * Binds the supplied annotation to the supplied fixed value. * * @param type The type of the annotation being bound. * @param value The value to bind to this annotation. * @param <T> The annotation type. * @return A new builder for an advice that considers the supplied annotation type during binding. */ @SuppressWarnings("unchecked") public <T extends Annotation> WithCustomMapping bindSerialized(Class<T> type, Serializable value) { return bindSerialized(type, value, (Class<Serializable>) value.getClass()); }
if ( collectionField.getType().asErasure().isAssignableTo( Map.class ) ) { isDirty = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapAreCollectionFieldsDirty.class, adviceLocator ) .wrap( isDirty ); getDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapGetCollectionFieldDirtyNames.class, adviceLocator ) .wrap( getDirtyNames ); clearDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapGetCollectionClearDirtyNames.class, adviceLocator ) .wrap( clearDirtyNames ); .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.CollectionAreCollectionFieldsDirty.class, adviceLocator ) .wrap( isDirty ); getDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.CollectionGetCollectionFieldDirtyNames.class, adviceLocator ) .wrap( getDirtyNames ); clearDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() )
.bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.OneToOneHandler.class ) .wrap( implementation ); .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( persistentField.getType().asErasure().isAssignableTo( Map.class ) ? CodeTemplates.OneToManyOnMapHandler.class : CodeTemplates.OneToManyOnCollectionHandler.class ) .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.ManyToOneHandler.class ) .wrap( implementation ); .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.ManyToManyHandler.class ) .wrap( implementation );
DynamicType.Unloaded<?> unloaded = byteBuddy.redefine(classBeingRedefined, of(classBeingRedefined.getName(), classfileBuffer)) .visit(Advice.withCustomMapping() .bind(MockKProxyAdviceId.class, advice.getId()) .to(MockKProxyAdvice.class).on( isMethod() .and(not(isStatic())) .and(not(isDefaultFinalizer())))) .visit(Advice.withCustomMapping() .bind(MockKProxyAdviceId.class, staticProxyAdviceId(className)) .to(staticProxyAdvice(className)).on( isStatic() .and(not(isTypeInitializer()))
static Implementation wrap( TypeDescription managedCtClass, ByteBuddyEnhancementContext enhancementContext, AnnotatedFieldDescription persistentField, Implementation implementation) { if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { if ( enhancementContext.isCompositeClass( managedCtClass ) ) { implementation = Advice.to( CodeTemplates.CompositeDirtyCheckingHandler.class ).wrap( implementation ); } else if ( !persistentField.hasAnnotation( Id.class ) && !persistentField.hasAnnotation( EmbeddedId.class ) && !( persistentField.getType().asErasure().isAssignableTo( Collection.class ) && enhancementContext.isMappedCollection( persistentField ) ) ) { implementation = new InlineDirtyCheckingHandler( implementation, managedCtClass, persistentField.asDefined() ); } if ( enhancementContext.isCompositeClass( persistentField.getType().asErasure() ) && persistentField.hasAnnotation( Embedded.class ) ) { implementation = Advice.withCustomMapping() .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.FieldName.class, persistentField.getName() ) .to( CodeTemplates.CompositeFieldDirtyCheckingHandler.class ) .wrap( implementation ); } } return implementation; }
if ( collectionField.getType().asErasure().isAssignableTo( Map.class ) ) { isDirty = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapAreCollectionFieldsDirty.class, adviceLocator ) .wrap( isDirty ); getDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapGetCollectionFieldDirtyNames.class, adviceLocator ) .wrap( getDirtyNames ); clearDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapGetCollectionClearDirtyNames.class, adviceLocator ) .wrap( clearDirtyNames ); .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.CollectionAreCollectionFieldsDirty.class, adviceLocator ) .wrap( isDirty ); getDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.CollectionGetCollectionFieldDirtyNames.class, adviceLocator ) .wrap( getDirtyNames ); clearDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() )
.bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.OneToOneHandler.class ) .wrap( implementation ); .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( persistentField.getType().asErasure().isAssignableTo( Map.class ) ? CodeTemplates.OneToManyOnMapHandler.class : CodeTemplates.OneToManyOnCollectionHandler.class ) .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.ManyToOneHandler.class ) .wrap( implementation ); .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.ManyToManyHandler.class ) .wrap( implementation );
static Implementation wrap( TypeDescription managedCtClass, ByteBuddyEnhancementContext enhancementContext, AnnotatedFieldDescription persistentField, Implementation implementation) { if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { if ( enhancementContext.isCompositeClass( managedCtClass ) ) { implementation = Advice.to( CodeTemplates.CompositeDirtyCheckingHandler.class ).wrap( implementation ); } else if ( !persistentField.hasAnnotation( Id.class ) && !persistentField.hasAnnotation( EmbeddedId.class ) && !( persistentField.getType().asErasure().isAssignableTo( Collection.class ) && enhancementContext.isMappedCollection( persistentField ) ) ) { implementation = new InlineDirtyCheckingHandler( implementation, managedCtClass, persistentField.asDefined() ); } if ( enhancementContext.isCompositeClass( persistentField.getType().asErasure() ) && persistentField.hasAnnotation( Embedded.class ) ) { implementation = Advice.withCustomMapping() .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.FieldName.class, persistentField.getName() ) .to( CodeTemplates.CompositeFieldDirtyCheckingHandler.class ) .wrap( implementation ); } } return implementation; }
.and(not(isDeclaredBy(nameStartsWith("java.")).<MethodDescription>and(isPackagePrivate()))), Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class)) .method(isHashCode(), Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForHashCode.class)) .method(isEquals(), Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class)); Method getModule, canRead, redefineModule; try {
private Advice.WithCustomMapping registerDynamicValues() { List<Advice.OffsetMapping.Factory<? extends Annotation>> offsetMappingFactories = getOffsetMappingFactories(); Advice.WithCustomMapping withCustomMapping = Advice.withCustomMapping(); for (Advice.OffsetMapping.Factory<? extends Annotation> offsetMappingFactory : offsetMappingFactories) { withCustomMapping = withCustomMapping.bind((Advice.OffsetMapping.Factory<? super Annotation>) offsetMappingFactory); } return withCustomMapping; }
private AsmVisitorWrapper.ForDeclaredMethods getAdvice() { try { return registerDynamicValues() .to(getAdviceClass()) .on(timed("method", transformerName, getMethodElementMatcher())); } catch (NoClassDefFoundError error) { logger.debug("Error while creating advice. This usually means that an optional type is not present " + "so this is nothing wo worry about. Error message: {}", error.getMessage()); return null; } }
/** * 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)); }
/** * 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)); }
/** * Implements advice where every matched method is advised by the given type's advisory methods. The advices binary representation is * accessed by querying the class loader of the supplied class for a class file. * * @param enterAdvice The type declaring the enter advice. * @param exitAdvice The type declaring the exit advice. * @return A method visitor wrapper representing the supplied advice. */ public Advice to(Class<?> enterAdvice, Class<?> exitAdvice) { ClassLoader enterLoader = enterAdvice.getClassLoader(), exitLoader = exitAdvice.getClassLoader(); return to(enterAdvice, exitAdvice, enterLoader == exitLoader ? ClassFileLocator.ForClassLoader.of(enterLoader) : new ClassFileLocator.Compound(ClassFileLocator.ForClassLoader.of(enterLoader), ClassFileLocator.ForClassLoader.of(exitLoader))); }
/** * Binds the supplied annotation to the value of the supplied field. The field must be visible by the * instrumented type and must be declared by a super type of the instrumented field. The binding is defined * as read-only and applied static typing. * * @param type The type of the annotation being bound. * @param fieldDescription The field to bind to this annotation. * @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, FieldDescription fieldDescription) { return bind(new OffsetMapping.ForField.Resolved.Factory<T>(type, fieldDescription)); }
/** * Binds the supplied annotation to the supplied fixed value. * * @param type The type of the annotation being bound. * @param value The value to bind to this annotation. * @param targetType The type of {@code value} as which the instance should be treated. * @param <T> The annotation type. * @param <S> The type of the serialized instance. * @return A new builder for an advice that considers the supplied annotation type during binding. */ public <T extends Annotation, S extends Serializable> WithCustomMapping bindSerialized(Class<T> type, S value, Class<? super S> targetType) { return bind(OffsetMapping.ForSerializedValue.Factory.of(type, value, targetType)); }
/** * Binds the supplied annotation to the value of the supplied field. The field must be visible by the * instrumented type and must be declared by a super type of the instrumented field. * * @param type The type of the annotation being bound. * @param field The field to bind to this annotation. * @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, Field field) { return bind(type, new FieldDescription.ForLoadedField(field)); }