/** * {@inheritDoc} */ public Dispatcher.Resolved.ForMethodExit asMethodExit(List<? extends OffsetMapping.Factory<?>> userFactories, ClassReader classReader, Unresolved methodEnter) { Map<String, TypeDefinition> namedTypes = methodEnter.getNamedTypes(); for (ParameterDescription parameterDescription : adviceMethod.getParameters().filter(isAnnotatedWith(Local.class))) { String name = parameterDescription.getDeclaredAnnotations().ofType(Local.class).loadSilent().value(); TypeDefinition typeDefinition = namedTypes.get(name); if (typeDefinition == null) { throw new IllegalStateException(adviceMethod + " attempts use of undeclared local variable " + name); } else if (!typeDefinition.equals(parameterDescription.getType())) { throw new IllegalStateException(adviceMethod + " does not read variable " + name + " as " + typeDefinition); } } return Resolved.ForMethodExit.of(adviceMethod, namedTypes, userFactories, methodEnter.getAdviceType()); }
methodEnter = locate(OnMethodEnter.class, INLINE_ENTER, methodEnter, methodDescription); if (!methodEnter.isAlive()) { throw new IllegalArgumentException("No enter advice defined by " + enterAdvice); methodExit = locate(OnMethodExit.class, INLINE_EXIT, methodExit, methodDescription); if (!methodExit.isAlive()) { throw new IllegalArgumentException("No exit advice defined by " + exitAdvice); return new Advice(methodEnter.asMethodEnter(userFactories, methodEnter.isBinary() ? OpenedClassReader.of(classFileLocator.locate(enterAdvice.getName()).resolve()) : UNDEFINED, methodExit), methodExit.asMethodExit(userFactories, methodExit.isBinary() ? OpenedClassReader.of(classFileLocator.locate(exitAdvice.getName()).resolve()) : UNDEFINED, methodEnter));
/** * Locates a dispatcher for the method if available. * * @param type The annotation type that indicates a given form of advice that is currently resolved. * @param property An annotation property that indicates if the advice method should be inlined. * @param dispatcher Any previous dispatcher that was discovered or {@code null} if no such dispatcher was yet found. * @param methodDescription The method description that is considered as an advice method. * @return A resolved dispatcher or {@code null} if no dispatcher was resolved. */ private static Dispatcher.Unresolved locate(Class<? extends Annotation> type, MethodDescription.InDefinedShape property, Dispatcher.Unresolved dispatcher, MethodDescription.InDefinedShape methodDescription) { AnnotationDescription annotation = methodDescription.getDeclaredAnnotations().ofType(type); if (annotation == null) { return dispatcher; } else if (dispatcher.isAlive()) { throw new IllegalStateException("Duplicate advice for " + dispatcher + " and " + methodDescription); } else if (!methodDescription.isStatic()) { throw new IllegalStateException("Advice for " + methodDescription + " is not static"); } else { return annotation.getValue(property).resolve(Boolean.class) ? new Dispatcher.Inlining(methodDescription) : new Dispatcher.Delegating(methodDescription); } }
/** * Creates a new advice. * * @param advice A description of the type declaring the advice. * @param classFileLocator The class file locator for locating the advisory class's class file. * @param userFactories A list of custom factories for user generated offset mappings. * @return A method visitor wrapper representing the supplied advice. */ protected static Advice to(TypeDescription advice, ClassFileLocator classFileLocator, List<? extends OffsetMapping.Factory<?>> userFactories) { Dispatcher.Unresolved methodEnter = Dispatcher.Inactive.INSTANCE, methodExit = Dispatcher.Inactive.INSTANCE; for (MethodDescription.InDefinedShape methodDescription : advice.getDeclaredMethods()) { methodEnter = locate(OnMethodEnter.class, INLINE_ENTER, methodEnter, methodDescription); methodExit = locate(OnMethodExit.class, INLINE_EXIT, methodExit, methodDescription); } if (!methodEnter.isAlive() && !methodExit.isAlive()) { throw new IllegalArgumentException("No advice defined by " + advice); } try { ClassReader classReader = methodEnter.isBinary() || methodExit.isBinary() ? OpenedClassReader.of(classFileLocator.locate(advice.getName()).resolve()) : UNDEFINED; return new Advice(methodEnter.asMethodEnter(userFactories, classReader, methodExit), methodExit.asMethodExit(userFactories, classReader, methodEnter)); } catch (IOException exception) { throw new IllegalStateException("Error reading class file of " + advice, exception); } }
/** * {@inheritDoc} */ public Dispatcher.Resolved.ForMethodExit asMethodExit(List<? extends OffsetMapping.Factory<?>> userFactories, ClassReader classReader, Unresolved methodEnter) { Map<String, TypeDefinition> namedTypes = methodEnter.getNamedTypes(); for (Map.Entry<String, TypeDefinition> entry : this.namedTypes.entrySet()) { TypeDefinition typeDefinition = this.namedTypes.get(entry.getKey()); if (typeDefinition == null) { throw new IllegalStateException(adviceMethod + " attempts use of undeclared local variable " + entry.getKey()); } else if (!typeDefinition.equals(entry.getValue())) { throw new IllegalStateException(adviceMethod + " does not read variable " + entry.getKey() + " as " + typeDefinition); } } return Resolved.ForMethodExit.of(adviceMethod, namedTypes, userFactories, classReader, methodEnter.getAdviceType()); }
/** * {@inheritDoc} */ public Dispatcher.Resolved.ForMethodEnter asMethodEnter(List<? extends OffsetMapping.Factory<?>> userFactories, ClassReader classReader, Unresolved methodExit) { return Resolved.ForMethodEnter.of(adviceMethod, userFactories, methodExit.getAdviceType(), methodExit.isAlive()); }
/** * {@inheritDoc} */ public Dispatcher.Resolved.ForMethodEnter asMethodEnter(List<? extends OffsetMapping.Factory<?>> userFactories, ClassReader classReader, Unresolved methodExit) { return Resolved.ForMethodEnter.of(adviceMethod, namedTypes, userFactories, methodExit.getAdviceType(), classReader, methodExit.isAlive()); }