// Generated by delombok at Sun Feb 26 12:31:38 KST 2017 package scouter.bytebuddy.dynamic.scaffold; import scouter.bytebuddy.ClassFileVersion; import scouter.bytebuddy.description.annotation.AnnotationValue; import scouter.bytebuddy.description.method.MethodDescription; import scouter.bytebuddy.description.method.MethodList; import scouter.bytebuddy.description.modifier.Visibility; import scouter.bytebuddy.description.type.TypeDescription; import scouter.bytebuddy.dynamic.Transformer; import scouter.bytebuddy.implementation.Implementation; import scouter.bytebuddy.implementation.LoadedTypeInitializer; import scouter.bytebuddy.implementation.attribute.MethodAttributeAppender; import scouter.bytebuddy.implementation.bytecode.ByteCodeAppender; import scouter.bytebuddy.matcher.ElementMatcher; import scouter.bytebuddy.matcher.LatentMatcher; import scouter.bytebuddy.utility.CompoundList; import scouter.bytebuddy.matcher.ElementMatchers; import java.util.*; import static scouter.bytebuddy.matcher.ElementMatchers.*; /** * A method registry is responsible for storing information on how a method is intercepted. */ public interface MethodRegistry { /** * Prepends the given method definition to this method registry, i.e. this configuration is applied first. * * @param methodMatcher A matcher to identify any method that this definition concerns. * @param handler The handler to instrument any matched method. * @param attributeAppenderFactory A method attribute appender to apply to any matched method. * @param transformer The method transformer to be applied to implemented methods. * @return An adapted version of this method registry. */ MethodRegistry prepend(LatentMatcher<? super MethodDescription> methodMatcher, Handler handler, MethodAttributeAppender.Factory attributeAppenderFactory, Transformer<MethodDescription> transformer); /** * Appends the given method definition to this method registry, i.e. this configuration is applied last. * * @param methodMatcher A matcher to identify all entries that are to be matched. * @param handler The handler to instrument any matched method. * @param attributeAppenderFactory A method attribute appender to apply to any matched method. * @param transformer The method transformer to be applied to implemented methods. * @return An adapted version of this method registry. */ MethodRegistry append(LatentMatcher<? super MethodDescription> methodMatcher, Handler handler, MethodAttributeAppender.Factory attributeAppenderFactory, Transformer<MethodDescription> transformer); /** * Prepares this method registry. * * @param instrumentedType The instrumented type that should be created. * @param methodGraphCompiler The method graph compiler to be used for analyzing the fully assembled instrumented type. * @param typeValidation Determines if a type should be explicitly validated. * @param ignoredMethods A filter that only matches methods that should be instrumented. * @return A prepared version of this method registry. */ Prepared prepare(InstrumentedType instrumentedType, MethodGraph.Compiler methodGraphCompiler, TypeValidation typeValidation, LatentMatcher<? super MethodDescription> ignoredMethods); /** * A handler for implementing a method. */ interface Handler extends InstrumentedType.Prepareable { /** * Compiles this handler. * * @param implementationTarget The implementation target to compile this handler for. * @return A compiled handler. */ Handler.Compiled compile(Implementation.Target implementationTarget); /** * A handler for defining an abstract or native method. */ enum ForAbstractMethod implements Handler, Compiled { /** * The singleton instance. */ INSTANCE; @Override public InstrumentedType prepare(InstrumentedType instrumentedType) { return instrumentedType; } @Override public Compiled compile(Implementation.Target implementationTarget) { return this; } @Override public TypeWriter.MethodPool.Record assemble(MethodDescription methodDescription, MethodAttributeAppender attributeAppender, Visibility visibility) { return new TypeWriter.MethodPool.Record.ForDefinedMethod.WithoutBody(methodDescription, attributeAppender, visibility); } } /** * A handler for implementing a visibility bridge. */ enum ForVisibilityBridge implements Handler { /** * The singleton instance. */ INSTANCE; @Override public InstrumentedType prepare(InstrumentedType instrumentedType) { throw new IllegalStateException("A visibility bridge handler must not apply any preparations"); } @Override public Compiled compile(Implementation.Target implementationTarget) { return new Compiled(implementationTarget.getInstrumentedType()); } /** * A compiled handler for a visibility bridge handler. */ protected static class Compiled implements Handler.Compiled { /** * The instrumented type. */ private final TypeDescription instrumentedType; /** * Creates a new compiled handler for a visibility bridge. * * @param instrumentedType The instrumented type. */ protected Compiled(TypeDescription instrumentedType) { this.instrumentedType = instrumentedType; } @Override public TypeWriter.MethodPool.Record assemble(MethodDescription methodDescription, MethodAttributeAppender attributeAppender, Visibility visibility) { return TypeWriter.MethodPool.Record.ForDefinedMethod.OfVisibilityBridge.of(instrumentedType, methodDescription, attributeAppender); } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Handler.ForVisibilityBridge.Compiled)) return false; final MethodRegistry.Handler.ForVisibilityBridge.Compiled other = (MethodRegistry.Handler.ForVisibilityBridge.Compiled) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$instrumentedType = this.instrumentedType; final java.lang.Object other$instrumentedType = other.instrumentedType; if (this$instrumentedType == null ? other$instrumentedType != null : !this$instrumentedType.equals(other$instrumentedType)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Handler.ForVisibilityBridge.Compiled; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $instrumentedType = this.instrumentedType; result = result * PRIME + ($instrumentedType == null ? 43 : $instrumentedType.hashCode()); return result; } } } /** * A compiled handler for implementing a method. */ interface Compiled { /** * Assembles this compiled entry with a method attribute appender. * * @param methodDescription The method description to apply with this handler. * @param attributeAppender The method attribute appender to apply together with this handler. * @param visibility The represented method's minimum visibility. * @return A method pool entry representing this handler and the given attribute appender. */ TypeWriter.MethodPool.Record assemble(MethodDescription methodDescription, MethodAttributeAppender attributeAppender, Visibility visibility); } /** * A handler for a method that is implemented as byte code. */ class ForImplementation implements Handler { /** * The implementation to apply. */ private final Implementation implementation; /** * Creates a new handler for implementing a method with byte code. * * @param implementation The implementation to apply. */ public ForImplementation(Implementation implementation) { this.implementation = implementation; } @Override public InstrumentedType prepare(InstrumentedType instrumentedType) { return implementation.prepare(instrumentedType); } @Override public Compiled compile(Implementation.Target implementationTarget) { return new Compiled(implementation.appender(implementationTarget)); } /** * A compiled handler for implementing a method. */ protected static class Compiled implements Handler.Compiled { /** * The byte code appender to apply. */ private final ByteCodeAppender byteCodeAppender; /** * Creates a new compiled handler for a method implementation. * * @param byteCodeAppender The byte code appender to apply. */ protected Compiled(ByteCodeAppender byteCodeAppender) { this.byteCodeAppender = byteCodeAppender; } @Override public TypeWriter.MethodPool.Record assemble(MethodDescription methodDescription, MethodAttributeAppender attributeAppender, Visibility visibility) { return new TypeWriter.MethodPool.Record.ForDefinedMethod.WithBody(methodDescription, byteCodeAppender, attributeAppender, visibility); } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Handler.ForImplementation.Compiled)) return false; final MethodRegistry.Handler.ForImplementation.Compiled other = (MethodRegistry.Handler.ForImplementation.Compiled) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$byteCodeAppender = this.byteCodeAppender; final java.lang.Object other$byteCodeAppender = other.byteCodeAppender; if (this$byteCodeAppender == null ? other$byteCodeAppender != null : !this$byteCodeAppender.equals(other$byteCodeAppender)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Handler.ForImplementation.Compiled; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $byteCodeAppender = this.byteCodeAppender; result = result * PRIME + ($byteCodeAppender == null ? 43 : $byteCodeAppender.hashCode()); return result; } } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Handler.ForImplementation)) return false; final MethodRegistry.Handler.ForImplementation other = (MethodRegistry.Handler.ForImplementation) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$implementation = this.implementation; final java.lang.Object other$implementation = other.implementation; if (this$implementation == null ? other$implementation != null : !this$implementation.equals(other$implementation)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Handler.ForImplementation; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $implementation = this.implementation; result = result * PRIME + ($implementation == null ? 43 : $implementation.hashCode()); return result; } } /** * A handler for defining a default annotation value for a method. */ class ForAnnotationValue implements Handler, Compiled { /** * The annotation value to set as a default value. */ private final AnnotationValue<?, ?> annotationValue; /** * Creates a handler for defining a default annotation value for a method. * * @param annotationValue The annotation value to set as a default value. */ public ForAnnotationValue(AnnotationValue<?, ?> annotationValue) { this.annotationValue = annotationValue; } @Override public InstrumentedType prepare(InstrumentedType instrumentedType) { return instrumentedType; } @Override public Compiled compile(Implementation.Target implementationTarget) { return this; } @Override public TypeWriter.MethodPool.Record assemble(MethodDescription methodDescription, MethodAttributeAppender attributeAppender, Visibility visibility) { return new TypeWriter.MethodPool.Record.ForDefinedMethod.WithAnnotationDefaultValue(methodDescription, annotationValue, attributeAppender); } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Handler.ForAnnotationValue)) return false; final MethodRegistry.Handler.ForAnnotationValue other = (MethodRegistry.Handler.ForAnnotationValue) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$annotationValue = this.annotationValue; final java.lang.Object other$annotationValue = other.annotationValue; if (this$annotationValue == null ? other$annotationValue != null : !this$annotationValue.equals(other$annotationValue)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Handler.ForAnnotationValue; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $annotationValue = this.annotationValue; result = result * PRIME + ($annotationValue == null ? 43 : $annotationValue.hashCode()); return result; } } } /** * A method registry that fully prepared the instrumented type. */ interface Prepared { /** * Returns the fully prepared instrumented type. * * @return The fully prepared instrumented type. */ TypeDescription getInstrumentedType(); /** * Returns the declared or virtually inherited methods of this type. * * @return The declared or virtually inherited methods of this type. */ MethodList<?> getMethods(); /** * Returns a list of all methods that should be instrumented. * * @return A list of all methods that should be instrumented. */ MethodList<?> getInstrumentedMethods(); /** * Returns the loaded type initializer of the instrumented type. * * @return The loaded type initializer of the instrumented type. */ LoadedTypeInitializer getLoadedTypeInitializer(); /** * The type initializer of the instrumented type. * * @return The type initializer of the instrumented type. */ TypeInitializer getTypeInitializer(); /** * Compiles this prepared method registry. * * @param implementationTargetFactory A factory for creating an implementation target. * @param classFileVersion The type's class file version. * @return A factory for creating an implementation target. */ Compiled compile(Implementation.Target.Factory implementationTargetFactory, ClassFileVersion classFileVersion); } /** * A compiled version of a method registry. */ interface Compiled extends TypeWriter.MethodPool { /** * Returns the instrumented type that is to be created. * * @return The instrumented type that is to be created. */ TypeDescription getInstrumentedType(); /** * Returns the declared or virtually inherited methods of this type. * * @return The declared or virtually inherited methods of this type. */ MethodList<?> getMethods(); /** * Returns a list of all methods that should be instrumented. * * @return A list of all methods that should be instrumented. */ MethodList<?> getInstrumentedMethods(); /** * Returns the loaded type initializer of the instrumented type. * * @return The loaded type initializer of the instrumented type. */ LoadedTypeInitializer getLoadedTypeInitializer(); /** * The type initializer of the instrumented type. * * @return The type initializer of the instrumented type. */ TypeInitializer getTypeInitializer(); } /** * A default implementation of a method registry. */ class Default implements MethodRegistry { /** * The list of currently registered entries in their application order. */ private final List<Entry> entries; /** * Creates a new default method registry without entries. */ public Default() { entries = Collections.emptyList(); } /** * Creates a new default method registry. * * @param entries The currently registered entries. */ private Default(List<Entry> entries) { this.entries = entries; } @Override public MethodRegistry prepend(LatentMatcher<? super MethodDescription> matcher, Handler handler, MethodAttributeAppender.Factory attributeAppenderFactory, Transformer<MethodDescription> transformer) { return new Default(CompoundList.of(new Entry(matcher, handler, attributeAppenderFactory, transformer), entries)); } @Override public MethodRegistry append(LatentMatcher<? super MethodDescription> matcher, Handler handler, MethodAttributeAppender.Factory attributeAppenderFactory, Transformer<MethodDescription> transformer) { return new Default(CompoundList.of(entries, new Entry(matcher, handler, attributeAppenderFactory, transformer))); } @Override public MethodRegistry.Prepared prepare(InstrumentedType instrumentedType, MethodGraph.Compiler methodGraphCompiler, TypeValidation typeValidation, LatentMatcher<? super MethodDescription> ignoredMethods) { LinkedHashMap<MethodDescription, Prepared.Entry> implementations = new LinkedHashMap<MethodDescription, Prepared.Entry>(); Set<Handler> handlers = new HashSet<Handler>(); MethodList<?> helperMethods = instrumentedType.getDeclaredMethods(); for (Entry entry : entries) { if (handlers.add(entry.getHandler())) { instrumentedType = entry.getHandler().prepare(instrumentedType); ElementMatcher<? super MethodDescription> handledMethods = noneOf(helperMethods); helperMethods = instrumentedType.getDeclaredMethods(); for (MethodDescription helperMethod : helperMethods.filter(handledMethods)) { implementations.put(helperMethod, entry.asSupplementaryEntry(helperMethod)); } } } MethodGraph.Linked methodGraph = methodGraphCompiler.compile(instrumentedType); // Casting required for Java 6 compiler. ElementMatcher<? super MethodDescription> relevanceMatcher = (ElementMatcher<? super MethodDescription>) ElementMatchers.not(ElementMatchers.anyOf(implementations.keySet())).and(returns(isVisibleTo(instrumentedType))).and(ElementMatchers.hasParameters(ElementMatchers.whereNone(ElementMatchers.hasType(ElementMatchers.not(isVisibleTo(instrumentedType)))))).and(ignoredMethods.resolve(instrumentedType)); List<MethodDescription> methods = new ArrayList<MethodDescription>(); for (MethodGraph.Node node : methodGraph.listNodes()) { MethodDescription methodDescription = node.getRepresentative(); boolean visibilityBridge = instrumentedType.isPublic() && !instrumentedType.isInterface(); if (relevanceMatcher.matches(methodDescription)) { for (Entry entry : entries) { if (entry.resolve(instrumentedType).matches(methodDescription)) { implementations.put(methodDescription, entry.asPreparedEntry(instrumentedType, methodDescription, node.getMethodTypes(), node.getVisibility())); visibilityBridge = false; break; } } } if (visibilityBridge && !node.getSort().isMadeVisible() && methodDescription.isPublic() && !(methodDescription.isAbstract() || methodDescription.isFinal()) && methodDescription.getDeclaringType().isPackagePrivate()) { // Visibility bridges are required for public classes that inherit a public method from a package-private class. implementations.put(methodDescription, Prepared.Entry.forVisibilityBridge(methodDescription, node.getVisibility())); } methods.add(methodDescription); } for (MethodDescription methodDescription : CompoundList.of(instrumentedType.getDeclaredMethods().filter(ElementMatchers.not(ElementMatchers.isVirtual()).and(relevanceMatcher)), new MethodDescription.Latent.TypeInitializer(instrumentedType))) { for (Entry entry : entries) { if (entry.resolve(instrumentedType).matches(methodDescription)) { implementations.put(methodDescription, entry.asPreparedEntry(instrumentedType, methodDescription, methodDescription.getVisibility())); break; } } methods.add(methodDescription); } return new Prepared(implementations, instrumentedType.getLoadedTypeInitializer(), instrumentedType.getTypeInitializer(), typeValidation.isEnabled() ? instrumentedType.validated() : instrumentedType, methodGraph, new MethodList.Explicit<MethodDescription>(methods)); } /** * An entry of a default method registry. */ protected static class Entry implements LatentMatcher<MethodDescription> { /** * The latent method matcher that this entry represents. */ private final LatentMatcher<? super MethodDescription> matcher; /** * The handler to apply to all matched entries. */ private final Handler handler; /** * A method attribute appender factory to apply to all entries. */ private final MethodAttributeAppender.Factory attributeAppenderFactory; /** * The method transformer to be applied to implemented methods. */ private final Transformer<MethodDescription> transformer; /** * Creates a new entry. * * @param matcher The latent method matcher that this entry represents. * @param handler The handler to apply to all matched entries. * @param attributeAppenderFactory A method attribute appender factory to apply to all entries. * @param transformer The method transformer to be applied to implemented methods. */ protected Entry(LatentMatcher<? super MethodDescription> matcher, Handler handler, MethodAttributeAppender.Factory attributeAppenderFactory, Transformer<MethodDescription> transformer) { this.matcher = matcher; this.handler = handler; this.attributeAppenderFactory = attributeAppenderFactory; this.transformer = transformer; } /** * Transforms this entry into a prepared state. * * @param instrumentedType The instrumented type. * @param methodDescription The non-transformed method to be implemented. * @param visibility The represented method's minimum visibility. * @return A prepared version of this entry. */ protected Prepared.Entry asPreparedEntry(TypeDescription instrumentedType, MethodDescription methodDescription, Visibility visibility) { return asPreparedEntry(instrumentedType, methodDescription, Collections.<MethodDescription.TypeToken>emptySet(), visibility); } /** * Transforms this entry into a prepared state. * * @param instrumentedType The instrumented type. * @param methodDescription The non-transformed method to be implemented. * @param methodTypes The method types this method represents. * @param visibility The represented method's minimum visibility. * @return A prepared version of this entry. */ protected Prepared.Entry asPreparedEntry(TypeDescription instrumentedType, MethodDescription methodDescription, Set<MethodDescription.TypeToken> methodTypes, Visibility visibility) { return new Prepared.Entry(handler, attributeAppenderFactory, transformer.transform(instrumentedType, methodDescription), methodTypes, visibility, false); } /** * Returns a prepared entry for a supplementary method. * * @param methodDescription The method to be implemented. * @return An entry for a supplementary entry that is defined by a method implementation instance. */ protected Prepared.Entry asSupplementaryEntry(MethodDescription methodDescription) { return new Prepared.Entry(handler, MethodAttributeAppender.Explicit.of(methodDescription), methodDescription, Collections.<MethodDescription.TypeToken>emptySet(), methodDescription.getVisibility(), false); } /** * Returns this entry's handler. * * @return The handler of this entry. */ protected Handler getHandler() { return handler; } @Override public ElementMatcher<? super MethodDescription> resolve(TypeDescription typeDescription) { return matcher.resolve(typeDescription); } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Default.Entry)) return false; final MethodRegistry.Default.Entry other = (MethodRegistry.Default.Entry) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$matcher = this.matcher; final java.lang.Object other$matcher = other.matcher; if (this$matcher == null ? other$matcher != null : !this$matcher.equals(other$matcher)) return false; final java.lang.Object this$handler = this.getHandler(); final java.lang.Object other$handler = other.getHandler(); if (this$handler == null ? other$handler != null : !this$handler.equals(other$handler)) return false; final java.lang.Object this$attributeAppenderFactory = this.attributeAppenderFactory; final java.lang.Object other$attributeAppenderFactory = other.attributeAppenderFactory; if (this$attributeAppenderFactory == null ? other$attributeAppenderFactory != null : !this$attributeAppenderFactory.equals(other$attributeAppenderFactory)) return false; final java.lang.Object this$transformer = this.transformer; final java.lang.Object other$transformer = other.transformer; if (this$transformer == null ? other$transformer != null : !this$transformer.equals(other$transformer)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Default.Entry; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $matcher = this.matcher; result = result * PRIME + ($matcher == null ? 43 : $matcher.hashCode()); final java.lang.Object $handler = this.getHandler(); result = result * PRIME + ($handler == null ? 43 : $handler.hashCode()); final java.lang.Object $attributeAppenderFactory = this.attributeAppenderFactory; result = result * PRIME + ($attributeAppenderFactory == null ? 43 : $attributeAppenderFactory.hashCode()); final java.lang.Object $transformer = this.transformer; result = result * PRIME + ($transformer == null ? 43 : $transformer.hashCode()); return result; } } /** * A prepared version of a default method registry. */ protected static class Prepared implements MethodRegistry.Prepared { /** * A map of all method descriptions mapped to their handling entries. */ private final LinkedHashMap<MethodDescription, Entry> implementations; /** * The loaded type initializer of the instrumented type. */ private final LoadedTypeInitializer loadedTypeInitializer; /** * The type initializer of the instrumented type. */ private final TypeInitializer typeInitializer; /** * The instrumented type. */ private final TypeDescription instrumentedType; /** * A method graph describing the instrumented type. */ private final MethodGraph.Linked methodGraph; /** * The declared or virtually inherited methods of this type. */ private final MethodList<?> methods; /** * Creates a prepared version of a default method registry. * * @param implementations A map of all method descriptions mapped to their handling entries. * @param loadedTypeInitializer The loaded type initializer of the instrumented type. * @param typeInitializer The type initializer of the instrumented type. * @param instrumentedType The instrumented type. * @param methodGraph A method graph describing the instrumented type. * @param methods The declared or virtually inherited methods of this type. */ protected Prepared(LinkedHashMap<MethodDescription, Entry> implementations, LoadedTypeInitializer loadedTypeInitializer, TypeInitializer typeInitializer, TypeDescription instrumentedType, MethodGraph.Linked methodGraph, MethodList<?> methods) { this.implementations = implementations; this.loadedTypeInitializer = loadedTypeInitializer; this.typeInitializer = typeInitializer; this.instrumentedType = instrumentedType; this.methodGraph = methodGraph; this.methods = methods; } @Override public TypeDescription getInstrumentedType() { return instrumentedType; } @Override public LoadedTypeInitializer getLoadedTypeInitializer() { return loadedTypeInitializer; } @Override public TypeInitializer getTypeInitializer() { return typeInitializer; } @Override public MethodList<?> getMethods() { return methods; } @Override public MethodList<?> getInstrumentedMethods() { return new MethodList.Explicit<MethodDescription>(new ArrayList<MethodDescription>(implementations.keySet())).filter(ElementMatchers.not(ElementMatchers.isTypeInitializer())); } @Override public MethodRegistry.Compiled compile(Implementation.Target.Factory implementationTargetFactory, ClassFileVersion classFileVersion) { Map<Handler, Handler.Compiled> compilationCache = new HashMap<Handler, Handler.Compiled>(); Map<MethodAttributeAppender.Factory, MethodAttributeAppender> attributeAppenderCache = new HashMap<MethodAttributeAppender.Factory, MethodAttributeAppender>(); LinkedHashMap<MethodDescription, Compiled.Entry> entries = new LinkedHashMap<MethodDescription, Compiled.Entry>(); Implementation.Target implementationTarget = implementationTargetFactory.make(instrumentedType, methodGraph, classFileVersion); for (Map.Entry<MethodDescription, Entry> entry : implementations.entrySet()) { Handler.Compiled cachedHandler = compilationCache.get(entry.getValue().getHandler()); if (cachedHandler == null) { cachedHandler = entry.getValue().getHandler().compile(implementationTarget); compilationCache.put(entry.getValue().getHandler(), cachedHandler); } MethodAttributeAppender cachedAttributeAppender = attributeAppenderCache.get(entry.getValue().getAppenderFactory()); if (cachedAttributeAppender == null) { cachedAttributeAppender = entry.getValue().getAppenderFactory().make(instrumentedType); attributeAppenderCache.put(entry.getValue().getAppenderFactory(), cachedAttributeAppender); } entries.put(entry.getKey(), new Compiled.Entry(cachedHandler, cachedAttributeAppender, entry.getValue().getMethodDescription(), entry.getValue().resolveBridgeTypes(), entry.getValue().getVisibility(), entry.getValue().isBridgeMethod())); } return new Compiled(instrumentedType, loadedTypeInitializer, typeInitializer, methods, entries, classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)); } /** * An entry of a prepared method registry. */ protected static class Entry { /** * The handler for implementing methods. */ private final Handler handler; /** * A attribute appender factory for appending attributes for any implemented method. */ private final MethodAttributeAppender.Factory attributeAppenderFactory; /** * The method this entry represents. */ private final MethodDescription methodDescription; /** * The method's type tokens. */ private final Set<MethodDescription.TypeToken> typeTokens; /** * The minimum required visibility of this method. */ private Visibility visibility; /** * Is {@code true} if this entry represents a bridge method. */ private final boolean bridgeMethod; /** * Creates a new prepared entry. * * @param handler The handler for implementing methods. * @param attributeAppenderFactory A attribute appender factory for appending attributes for any implemented method. * @param methodDescription The method this entry represents. * @param typeTokens A set of bridges representing the bridge methods of this method. * @param visibility The minimum required visibility of this method. * @param bridgeMethod {@code true} if this entry represents a bridge method. */ protected Entry(Handler handler, MethodAttributeAppender.Factory attributeAppenderFactory, MethodDescription methodDescription, Set<MethodDescription.TypeToken> typeTokens, Visibility visibility, boolean bridgeMethod) { this.handler = handler; this.attributeAppenderFactory = attributeAppenderFactory; this.methodDescription = methodDescription; this.typeTokens = typeTokens; this.visibility = visibility; this.bridgeMethod = bridgeMethod; } /** * Creates an entry for a visibility bridge. * * @param bridgeTarget The bridge method's target. * @param visibility The represented method's minimum visibility. * @return An entry representing a visibility bridge. */ protected static Entry forVisibilityBridge(MethodDescription bridgeTarget, Visibility visibility) { return new Entry(Handler.ForVisibilityBridge.INSTANCE, MethodAttributeAppender.Explicit.of(bridgeTarget), bridgeTarget, Collections.<MethodDescription.TypeToken>emptySet(), visibility, true); } /** * Returns this entry's handler. * * @return The entry's handler. */ protected Handler getHandler() { return handler; } /** * Returns this entry's attribute appender factory. * * @return This entry's attribute appender factory. */ protected MethodAttributeAppender.Factory getAppenderFactory() { return attributeAppenderFactory; } /** * Returns the method description this entry represents. * * @return The method description this entry represents. */ protected MethodDescription getMethodDescription() { return methodDescription; } /** * Resolves the type tokens of all bridge methods that are required to be implemented for this entry. * * @return A set of type tokens representing the bridge methods required for implementing this type. */ protected Set<MethodDescription.TypeToken> resolveBridgeTypes() { HashSet<MethodDescription.TypeToken> typeTokens = new HashSet<MethodDescription.TypeToken>(this.typeTokens); typeTokens.remove(methodDescription.asTypeToken()); return typeTokens; } /** * Returns the represented method's minimum visibility. * * @return The represented method's minimum visibility. */ protected Visibility getVisibility() { return visibility; } /** * Returns {@code true} if this entry represents a bridge method. * * @return {@code true} if this entry represents a bridge method. */ protected boolean isBridgeMethod() { return bridgeMethod; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Default.Prepared.Entry)) return false; final MethodRegistry.Default.Prepared.Entry other = (MethodRegistry.Default.Prepared.Entry) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$handler = this.getHandler(); final java.lang.Object other$handler = other.getHandler(); if (this$handler == null ? other$handler != null : !this$handler.equals(other$handler)) return false; final java.lang.Object this$attributeAppenderFactory = this.attributeAppenderFactory; final java.lang.Object other$attributeAppenderFactory = other.attributeAppenderFactory; if (this$attributeAppenderFactory == null ? other$attributeAppenderFactory != null : !this$attributeAppenderFactory.equals(other$attributeAppenderFactory)) return false; final java.lang.Object this$methodDescription = this.getMethodDescription(); final java.lang.Object other$methodDescription = other.getMethodDescription(); if (this$methodDescription == null ? other$methodDescription != null : !this$methodDescription.equals(other$methodDescription)) return false; final java.lang.Object this$typeTokens = this.typeTokens; final java.lang.Object other$typeTokens = other.typeTokens; if (this$typeTokens == null ? other$typeTokens != null : !this$typeTokens.equals(other$typeTokens)) return false; final java.lang.Object this$visibility = this.getVisibility(); final java.lang.Object other$visibility = other.getVisibility(); if (this$visibility == null ? other$visibility != null : !this$visibility.equals(other$visibility)) return false; if (this.isBridgeMethod() != other.isBridgeMethod()) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Default.Prepared.Entry; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $handler = this.getHandler(); result = result * PRIME + ($handler == null ? 43 : $handler.hashCode()); final java.lang.Object $attributeAppenderFactory = this.attributeAppenderFactory; result = result * PRIME + ($attributeAppenderFactory == null ? 43 : $attributeAppenderFactory.hashCode()); final java.lang.Object $methodDescription = this.getMethodDescription(); result = result * PRIME + ($methodDescription == null ? 43 : $methodDescription.hashCode()); final java.lang.Object $typeTokens = this.typeTokens; result = result * PRIME + ($typeTokens == null ? 43 : $typeTokens.hashCode()); final java.lang.Object $visibility = this.getVisibility(); result = result * PRIME + ($visibility == null ? 43 : $visibility.hashCode()); result = result * PRIME + (this.isBridgeMethod() ? 79 : 97); return result; } } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Default.Prepared)) return false; final MethodRegistry.Default.Prepared other = (MethodRegistry.Default.Prepared) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$implementations = this.implementations; final java.lang.Object other$implementations = other.implementations; if (this$implementations == null ? other$implementations != null : !this$implementations.equals(other$implementations)) return false; final java.lang.Object this$loadedTypeInitializer = this.getLoadedTypeInitializer(); final java.lang.Object other$loadedTypeInitializer = other.getLoadedTypeInitializer(); if (this$loadedTypeInitializer == null ? other$loadedTypeInitializer != null : !this$loadedTypeInitializer.equals(other$loadedTypeInitializer)) return false; final java.lang.Object this$typeInitializer = this.getTypeInitializer(); final java.lang.Object other$typeInitializer = other.getTypeInitializer(); if (this$typeInitializer == null ? other$typeInitializer != null : !this$typeInitializer.equals(other$typeInitializer)) return false; final java.lang.Object this$instrumentedType = this.getInstrumentedType(); final java.lang.Object other$instrumentedType = other.getInstrumentedType(); if (this$instrumentedType == null ? other$instrumentedType != null : !this$instrumentedType.equals(other$instrumentedType)) return false; final java.lang.Object this$methodGraph = this.methodGraph; final java.lang.Object other$methodGraph = other.methodGraph; if (this$methodGraph == null ? other$methodGraph != null : !this$methodGraph.equals(other$methodGraph)) return false; final java.lang.Object this$methods = this.getMethods(); final java.lang.Object other$methods = other.getMethods(); if (this$methods == null ? other$methods != null : !this$methods.equals(other$methods)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Default.Prepared; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $implementations = this.implementations; result = result * PRIME + ($implementations == null ? 43 : $implementations.hashCode()); final java.lang.Object $loadedTypeInitializer = this.getLoadedTypeInitializer(); result = result * PRIME + ($loadedTypeInitializer == null ? 43 : $loadedTypeInitializer.hashCode()); final java.lang.Object $typeInitializer = this.getTypeInitializer(); result = result * PRIME + ($typeInitializer == null ? 43 : $typeInitializer.hashCode()); final java.lang.Object $instrumentedType = this.getInstrumentedType(); result = result * PRIME + ($instrumentedType == null ? 43 : $instrumentedType.hashCode()); final java.lang.Object $methodGraph = this.methodGraph; result = result * PRIME + ($methodGraph == null ? 43 : $methodGraph.hashCode()); final java.lang.Object $methods = this.getMethods(); result = result * PRIME + ($methods == null ? 43 : $methods.hashCode()); return result; } } /** * A compiled version of a default method registry. */ protected static class Compiled implements MethodRegistry.Compiled { /** * The instrumented type. */ private final TypeDescription instrumentedType; /** * The loaded type initializer of the instrumented type. */ private final LoadedTypeInitializer loadedTypeInitializer; /** * The type initializer of the instrumented type. */ private final TypeInitializer typeInitializer; /** * The declared or virtually inherited methods of this type. */ private final MethodList<?> methods; /** * A map of all method descriptions mapped to their handling entries. */ private final LinkedHashMap<MethodDescription, Entry> implementations; /** * {@code true} if the created type supports bridge methods. */ private final boolean supportsBridges; /** * Creates a new compiled version of a default method registry. * * @param instrumentedType The instrumented type. * @param loadedTypeInitializer The loaded type initializer of the instrumented type. * @param typeInitializer The type initializer of the instrumented type. * @param methods The declared or virtually inherited methods of this type. * @param implementations A map of all method descriptions mapped to their handling entries. * @param supportsBridges {@code true} if the created type supports bridge methods. */ protected Compiled(TypeDescription instrumentedType, LoadedTypeInitializer loadedTypeInitializer, TypeInitializer typeInitializer, MethodList<?> methods, LinkedHashMap<MethodDescription, Entry> implementations, boolean supportsBridges) { this.instrumentedType = instrumentedType; this.loadedTypeInitializer = loadedTypeInitializer; this.typeInitializer = typeInitializer; this.methods = methods; this.implementations = implementations; this.supportsBridges = supportsBridges; } @Override public TypeDescription getInstrumentedType() { return instrumentedType; } @Override public LoadedTypeInitializer getLoadedTypeInitializer() { return loadedTypeInitializer; } @Override public TypeInitializer getTypeInitializer() { return typeInitializer; } @Override public MethodList<?> getMethods() { return methods; } @Override public MethodList<?> getInstrumentedMethods() { return new MethodList.Explicit<MethodDescription>(new ArrayList<MethodDescription>(implementations.keySet())).filter(ElementMatchers.not(ElementMatchers.isTypeInitializer())); } @Override public Record target(MethodDescription methodDescription) { Entry entry = implementations.get(methodDescription); return entry == null ? new Record.ForNonImplementedMethod(methodDescription) : entry.bind(instrumentedType, supportsBridges); } /** * An entry of a compiled method registry. */ protected static class Entry { /** * The handler to be used for implementing a method. */ private final Handler.Compiled handler; /** * The attribute appender of a compiled method. */ private final MethodAttributeAppender attributeAppender; /** * The method to be implemented including potential transformations. */ private final MethodDescription methodDescription; /** * The type tokens representing all bridge methods for the method. */ private final Set<MethodDescription.TypeToken> bridgeTypes; /** * The represented method's minimum visibility. */ private final Visibility visibility; /** * {@code true} if this entry represents a bridge method. */ private final boolean bridgeMethod; /** * Creates a new entry for a compiled method registry. * * @param handler The handler to be used for implementing a method. * @param attributeAppender The attribute appender of a compiled method. * @param methodDescription The method to be implemented including potential transformations. * @param bridgeTypes The type tokens representing all bridge methods for the method. * @param visibility The represented method's minimum visibility. * @param bridgeMethod {@code true} if this entry represents a bridge method. */ protected Entry(Handler.Compiled handler, MethodAttributeAppender attributeAppender, MethodDescription methodDescription, Set<MethodDescription.TypeToken> bridgeTypes, Visibility visibility, boolean bridgeMethod) { this.handler = handler; this.attributeAppender = attributeAppender; this.methodDescription = methodDescription; this.bridgeTypes = bridgeTypes; this.visibility = visibility; this.bridgeMethod = bridgeMethod; } /** * Transforms this entry into a method record. * * @param instrumentedType The instrumented type to bind. * @param supportsBridges {@code true} if the record should support bridge methods. * @return A record representing this entry's properties. */ protected Record bind(TypeDescription instrumentedType, boolean supportsBridges) { if (bridgeMethod && !supportsBridges) { return new Record.ForNonImplementedMethod(methodDescription); } Record record = handler.assemble(methodDescription, attributeAppender, visibility); return supportsBridges ? TypeWriter.MethodPool.Record.AccessBridgeWrapper.of(record, instrumentedType, methodDescription, bridgeTypes, attributeAppender) : record; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Default.Compiled.Entry)) return false; final MethodRegistry.Default.Compiled.Entry other = (MethodRegistry.Default.Compiled.Entry) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$handler = this.handler; final java.lang.Object other$handler = other.handler; if (this$handler == null ? other$handler != null : !this$handler.equals(other$handler)) return false; final java.lang.Object this$attributeAppender = this.attributeAppender; final java.lang.Object other$attributeAppender = other.attributeAppender; if (this$attributeAppender == null ? other$attributeAppender != null : !this$attributeAppender.equals(other$attributeAppender)) return false; final java.lang.Object this$methodDescription = this.methodDescription; final java.lang.Object other$methodDescription = other.methodDescription; if (this$methodDescription == null ? other$methodDescription != null : !this$methodDescription.equals(other$methodDescription)) return false; final java.lang.Object this$bridgeTypes = this.bridgeTypes; final java.lang.Object other$bridgeTypes = other.bridgeTypes; if (this$bridgeTypes == null ? other$bridgeTypes != null : !this$bridgeTypes.equals(other$bridgeTypes)) return false; final java.lang.Object this$visibility = this.visibility; final java.lang.Object other$visibility = other.visibility; if (this$visibility == null ? other$visibility != null : !this$visibility.equals(other$visibility)) return false; if (this.bridgeMethod != other.bridgeMethod) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Default.Compiled.Entry; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $handler = this.handler; result = result * PRIME + ($handler == null ? 43 : $handler.hashCode()); final java.lang.Object $attributeAppender = this.attributeAppender; result = result * PRIME + ($attributeAppender == null ? 43 : $attributeAppender.hashCode()); final java.lang.Object $methodDescription = this.methodDescription; result = result * PRIME + ($methodDescription == null ? 43 : $methodDescription.hashCode()); final java.lang.Object $bridgeTypes = this.bridgeTypes; result = result * PRIME + ($bridgeTypes == null ? 43 : $bridgeTypes.hashCode()); final java.lang.Object $visibility = this.visibility; result = result * PRIME + ($visibility == null ? 43 : $visibility.hashCode()); result = result * PRIME + (this.bridgeMethod ? 79 : 97); return result; } } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Default.Compiled)) return false; final MethodRegistry.Default.Compiled other = (MethodRegistry.Default.Compiled) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$instrumentedType = this.getInstrumentedType(); final java.lang.Object other$instrumentedType = other.getInstrumentedType(); if (this$instrumentedType == null ? other$instrumentedType != null : !this$instrumentedType.equals(other$instrumentedType)) return false; final java.lang.Object this$loadedTypeInitializer = this.getLoadedTypeInitializer(); final java.lang.Object other$loadedTypeInitializer = other.getLoadedTypeInitializer(); if (this$loadedTypeInitializer == null ? other$loadedTypeInitializer != null : !this$loadedTypeInitializer.equals(other$loadedTypeInitializer)) return false; final java.lang.Object this$typeInitializer = this.getTypeInitializer(); final java.lang.Object other$typeInitializer = other.getTypeInitializer(); if (this$typeInitializer == null ? other$typeInitializer != null : !this$typeInitializer.equals(other$typeInitializer)) return false; final java.lang.Object this$methods = this.getMethods(); final java.lang.Object other$methods = other.getMethods(); if (this$methods == null ? other$methods != null : !this$methods.equals(other$methods)) return false; final java.lang.Object this$implementations = this.implementations; final java.lang.Object other$implementations = other.implementations; if (this$implementations == null ? other$implementations != null : !this$implementations.equals(other$implementations)) return false; if (this.supportsBridges != other.supportsBridges) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Default.Compiled; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $instrumentedType = this.getInstrumentedType(); result = result * PRIME + ($instrumentedType == null ? 43 : $instrumentedType.hashCode()); final java.lang.Object $loadedTypeInitializer = this.getLoadedTypeInitializer(); result = result * PRIME + ($loadedTypeInitializer == null ? 43 : $loadedTypeInitializer.hashCode()); final java.lang.Object $typeInitializer = this.getTypeInitializer(); result = result * PRIME + ($typeInitializer == null ? 43 : $typeInitializer.hashCode()); final java.lang.Object $methods = this.getMethods(); result = result * PRIME + ($methods == null ? 43 : $methods.hashCode()); final java.lang.Object $implementations = this.implementations; result = result * PRIME + ($implementations == null ? 43 : $implementations.hashCode()); result = result * PRIME + (this.supportsBridges ? 79 : 97); return result; } } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof MethodRegistry.Default)) return false; final MethodRegistry.Default other = (MethodRegistry.Default) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$entries = this.entries; final java.lang.Object other$entries = other.entries; if (this$entries == null ? other$entries != null : !this$entries.equals(other$entries)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodRegistry.Default; } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public int hashCode() { final int PRIME = 59; int result = 1; final java.lang.Object $entries = this.entries; result = result * PRIME + ($entries == null ? 43 : $entries.hashCode()); return result; } } }