package net.bytebuddy.implementation.auxiliary; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import lombok.EqualsAndHashCode; import net.bytebuddy.ClassFileVersion; import net.bytebuddy.description.modifier.ModifierContributor; import net.bytebuddy.description.modifier.SyntheticState; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.implementation.MethodAccessorFactory; import net.bytebuddy.utility.RandomString; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * An auxiliary type that provides services to the instrumentation of another type. Implementations should provide * meaningful {@code equals(Object)} and {@code hashCode()} implementations in order to avoid multiple creations * of this type. */ public interface AuxiliaryType { /** * The default type access of an auxiliary type. <b>This array must not be mutated</b>. */ @SuppressFBWarnings(value = {"MS_MUTABLE_ARRAY", "MS_OOI_PKGPROTECT"}, justification = "The array is not to be modified by contract") ModifierContributor.ForType[] DEFAULT_TYPE_MODIFIER = {SyntheticState.SYNTHETIC}; /** * Creates a new auxiliary type. * * @param auxiliaryTypeName The fully qualified binary name for this auxiliary type. The type should be in * the same package than the instrumented type this auxiliary type is providing services * to in order to allow package-private access. * @param classFileVersion The class file version the auxiliary class should be written in. * @param methodAccessorFactory A factory for accessor methods. * @return A dynamically created type representing this auxiliary type. */ DynamicType make(String auxiliaryTypeName, ClassFileVersion classFileVersion, MethodAccessorFactory methodAccessorFactory); /** * Representation of a naming strategy for an auxiliary type. */ interface NamingStrategy { /** * Names an auxiliary type. * * @param instrumentedType The instrumented type for which an auxiliary type is registered. * @return The fully qualified name for the given auxiliary type. */ String name(TypeDescription instrumentedType); /** * A naming strategy for an auxiliary type which returns the instrumented type's name with a fixed extension * and a random number as a suffix. All generated names will be in the same package as the instrumented type. */ @EqualsAndHashCode(of = "suffix") class SuffixingRandom implements NamingStrategy { /** * The suffix to append to the instrumented type for creating names for the auxiliary types. */ private final String suffix; /** * An instance for creating random values. */ private final RandomString randomString; /** * Creates a new suffixing random naming strategy. * * @param suffix The suffix to extend to the instrumented type. */ public SuffixingRandom(String suffix) { this.suffix = suffix; randomString = new RandomString(); } @Override public String name(TypeDescription instrumentedType) { return String.format("%s$%s$%s", instrumentedType.getName(), suffix, randomString.nextString()); } } } /** * A marker to indicate that an auxiliary type is part of the instrumented types signature. This information can be used to load a type before * the instrumented type such that reflection on the instrumented type does not cause a {@link NoClassDefFoundError}. */ @Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) @interface SignatureRelevant { /* empty */ } }