All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ui4j.bytebuddy.NamingStrategy Maven / Gradle / Ivy

The newest version!
package com.ui4j.bytebuddy;

import com.ui4j.bytebuddy.instrumentation.ModifierContributor;
import com.ui4j.bytebuddy.instrumentation.type.TypeDescription;
import com.ui4j.bytebuddy.modifier.EnumerationState;
import com.ui4j.bytebuddy.modifier.SyntheticState;
import com.ui4j.bytebuddy.modifier.TypeManifestation;
import com.ui4j.bytebuddy.modifier.Visibility;
import com.ui4j.bytebuddy.utility.ByteBuddyCommons;
import com.ui4j.bytebuddy.utility.RandomString;
import com.ui4j.bytebuddy.jar.asm.Opcodes;

import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.List;

/**
 * A naming strategy for finding a fully qualified name for a Java type.
 * 

 

* Note that subclasses that lie within the same package as their superclass have improved access to overriding * package-private methods of their super type. */ public interface NamingStrategy { /** * Generates a fully qualified name for a Java type. The resulting should not lie within the {@code java.lang} * package since such types cannot be loaded using a normal class loader. Also, the name should not yet be taken * by another type since this would cause conflicts in the name space. Therefore, it is recommendable to include * a random sequence within the name. * * @param unnamedType An unnamed type that is to be named. * @return A valid identifier for a Java type. */ String name(UnnamedType unnamedType); /** * An description of a type which is to be named. */ static interface UnnamedType { /** * Returns this unnamed type's super class. * * @return A description of the super class of the type to be named. */ TypeDescription getSuperClass(); /** * Returns a collection of descriptions of this unnamed type's directly implemented interfaces. * * @return A collection of implemented interfaces. */ Collection getDeclaredInterfaces(); /** * Returns the visibility of this unnamed type. * * @return The visibility of this unnamed type. */ Visibility getVisibility(); /** * Returns the manifestation of this unnamed type. * * @return The manifestation of this unnamed type. */ TypeManifestation getTypeManifestation(); /** * Returns the manifestation of this unnamed type. * * @return The manifestation of this unnamed type. */ SyntheticState getSyntheticState(); /** * Returns the enumeration state of this unnamed type. * * @return The enumeration state of this unnamed type. */ EnumerationState getEnumerationState(); /** * Returns the class file version of this unnamed type. * * @return The class file version of this unnamed type. */ ClassFileVersion getClassFileVersion(); /** * An unnamed type which is to be named by a naming strategy. */ static class Default implements UnnamedType { /** * The unnamed type's super class. */ private final TypeDescription superClass; /** * The unnamed type's interfaces. */ private final List interfaces; /** * The unnamed type's modifiers. */ private final int modifiers; /** * The class file version of the unnamed type. */ private final ClassFileVersion classFileVersion; /** * Creates a new unnamed type. * * @param superClass The unnamed type's super class. * @param interfaces The unnamed type's interfaces. * @param modifiers The unnamed type's modifiers. * @param classFileVersion The class file version of the unnamed type. */ public Default(TypeDescription superClass, List interfaces, int modifiers, ClassFileVersion classFileVersion) { this.superClass = superClass; this.interfaces = interfaces; this.modifiers = modifiers; this.classFileVersion = classFileVersion; } @Override public TypeDescription getSuperClass() { return superClass; } @Override public List getDeclaredInterfaces() { return interfaces; } @Override public Visibility getVisibility() { switch (modifiers & ByteBuddyCommons.VISIBILITY_MODIFIER_MASK) { case Opcodes.ACC_PUBLIC: return Visibility.PUBLIC; case Opcodes.ACC_PROTECTED: return Visibility.PROTECTED; case Opcodes.ACC_PRIVATE: return Visibility.PRIVATE; case ModifierContributor.EMPTY_MASK: return Visibility.PACKAGE_PRIVATE; default: throw new IllegalStateException("Ambiguous modifier: " + modifiers); } } @Override public TypeManifestation getTypeManifestation() { if ((modifiers & Modifier.FINAL) != 0) { return TypeManifestation.FINAL; // Note: Interfaces are abstract, the interface condition needs to be checked before abstraction. } else if ((modifiers & Opcodes.ACC_INTERFACE) != 0) { return TypeManifestation.INTERFACE; } else if ((modifiers & Opcodes.ACC_ABSTRACT) != 0) { return TypeManifestation.ABSTRACT; } else { return TypeManifestation.PLAIN; } } @Override public EnumerationState getEnumerationState() { return EnumerationState.is((modifiers & Opcodes.ACC_ENUM) != 0); } @Override public SyntheticState getSyntheticState() { return SyntheticState.is((modifiers & Opcodes.ACC_SYNTHETIC) != 0); } @Override public ClassFileVersion getClassFileVersion() { return classFileVersion; } @Override public boolean equals(Object other) { if (this == other) return true; if (other == null || getClass() != other.getClass()) return false; Default aDefault = (Default) other; return modifiers == aDefault.modifiers && classFileVersion.equals(aDefault.classFileVersion) && interfaces.equals(aDefault.interfaces) && superClass.equals(aDefault.superClass); } @Override public int hashCode() { int result = superClass.hashCode(); result = 31 * result + interfaces.hashCode(); result = 31 * result + modifiers; result = 31 * result + classFileVersion.hashCode(); return result; } @Override public String toString() { return "NamingStrategy.UnnamedType.Default{" + "superClass=" + superClass + ", interfaces=" + interfaces + ", modifiers=" + modifiers + ", classFileVersion=" + classFileVersion + '}'; } } } /** * An unbound {@link com.ui4j.bytebuddy.NamingStrategy} where the actual naming strategy is still to be determined * in dependency of whether a type is to be subclasses, redefined or rebased. */ static interface Unbound { /** * Returns a naming strategy for subclassing a type. * * @param typeDescription The type that the user specified to be subclasses. * @return A naming strategy for naming the generated subclass. */ NamingStrategy subclass(TypeDescription typeDescription); /** * Returns a naming strategy for redefining a type. * * @param typeDescription The type that the user specified to be subclasses. * @return A naming strategy for naming the redefined class. */ NamingStrategy redefine(TypeDescription typeDescription); /** * Returns a naming strategy for rebasing a type. * * @param typeDescription The type that the user specified to be subclasses. * @return A naming strategy for naming the rebased class. */ NamingStrategy rebase(TypeDescription typeDescription); /** * A default unbound {@link com.ui4j.bytebuddy.NamingStrategy} where rebased or redefined classes keep * their original name and where subclasses are named using a {@link com.ui4j.bytebuddy.NamingStrategy.SuffixingRandom} * strategy. */ static class Default implements Unbound { /** * The suffix to apply for generated subclasses. */ private final String suffix; /** * Creates a default unbound naming strategy. * * @param suffix The suffix to apply for generated subclasses */ public Default(String suffix) { this.suffix = suffix; } @Override public NamingStrategy subclass(TypeDescription typeDescription) { return new SuffixingRandom(suffix, new SuffixingRandom.BaseNameResolver.ForGivenType(typeDescription)); } @Override public NamingStrategy redefine(TypeDescription typeDescription) { return new Fixed(typeDescription.getName()); } @Override public NamingStrategy rebase(TypeDescription typeDescription) { return new Fixed(typeDescription.getName()); } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && suffix.equals(((Default) other).suffix); } @Override public int hashCode() { return suffix.hashCode(); } @Override public String toString() { return "NamingStrategy.Unbound.Default{" + "suffix='" + suffix + '\'' + '}'; } } /** * A unified unbound naming strategy which always applies a given naming strategy. */ static class Unified implements Unbound { /** * The unified naming strategy. */ private final NamingStrategy namingStrategy; /** * Creates a new unified naming strategy. * * @param namingStrategy The unified naming strategy. */ public Unified(NamingStrategy namingStrategy) { this.namingStrategy = namingStrategy; } @Override public NamingStrategy subclass(TypeDescription typeDescription) { return namingStrategy; } @Override public NamingStrategy redefine(TypeDescription typeDescription) { return namingStrategy; } @Override public NamingStrategy rebase(TypeDescription typeDescription) { return namingStrategy; } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && namingStrategy.equals(((Unified) other).namingStrategy); } @Override public int hashCode() { return namingStrategy.hashCode(); } @Override public String toString() { return "NamingStrategy.Unbound.Unified{" + "namingStrategy=" + namingStrategy + '}'; } } } /** * A naming strategy that creates a name by concatenating: *
    *
  1. The super classes package and name
  2. *
  3. A given suffix string
  4. *
  5. A random number
  6. *
* Between all these elements, a {@code $} sign is included into the name to improve readability. As an exception, * types that subclass classes from the {@code java.**} packages are prefixed with a given package. This is * necessary as it is illegal to define non-bootstrap classes in this name space. The same strategy is applied * when subclassing a signed type which is equally illegal. */ static class SuffixingRandom implements NamingStrategy { /** * The default package for defining types that are renamed to not be contained in the * {@link com.ui4j.bytebuddy.NamingStrategy.SuffixingRandom#JAVA_PACKAGE} package. */ public static final String BYTE_BUDDY_RENAME_PACKAGE = "com.ui4j.bytebuddy.renamed"; /** * The package prefix of the {@code java.**} packages for which the definition of non-bootstrap types is * illegal. */ private static final String JAVA_PACKAGE = "java."; /** * The suffix to attach to a super type name. */ private final String suffix; /** * The renaming location for types of the {@link com.ui4j.bytebuddy.NamingStrategy.SuffixingRandom#JAVA_PACKAGE}. */ private final String javaLangPackagePrefix; /** * An instance for creating random seed values. */ private final RandomString randomString; /** * A resolver for the base name for naming the unnamed type. */ private final BaseNameResolver baseNameResolver; /** * Creates an immutable naming strategy with a given suffix but moves types that subclass types within * the {@code java.lang} package into Byte Buddy's package namespace. All names are derived from the * unnamed type's super type. * * @param suffix The suffix for the generated class. */ public SuffixingRandom(String suffix) { this(suffix, BaseNameResolver.ForUnnamedType.INSTANCE, BYTE_BUDDY_RENAME_PACKAGE); } /** * Creates an immutable naming strategy with a given suffix but moves types that subclass types within * the {@code java.lang} package into Byte Buddy's package namespace. * * @param suffix The suffix for the generated class. * @param baseNameResolver The base name resolver that is queried for locating the base name. */ public SuffixingRandom(String suffix, BaseNameResolver baseNameResolver) { this(suffix, baseNameResolver, BYTE_BUDDY_RENAME_PACKAGE); } /** * Creates an immutable naming strategy with a given suffix but moves types that subclass types within * the {@code java.lang} package into a given namespace. * * @param suffix The suffix for the generated class. * @param baseNameResolver The base name resolver that is queried for locating the base name. * @param javaLangPackagePrefix The fallback namespace for type's that subclass types within the * {@code java.lang} namespace. */ public SuffixingRandom(String suffix, BaseNameResolver baseNameResolver, String javaLangPackagePrefix) { this.suffix = suffix; this.baseNameResolver = baseNameResolver; this.javaLangPackagePrefix = javaLangPackagePrefix; randomString = new RandomString(); } @Override public String name(UnnamedType unnamedType) { String baseName = baseNameResolver.resolve(unnamedType); if (baseName.startsWith(JAVA_PACKAGE)) { baseName = javaLangPackagePrefix + "." + baseName; } return String.format("%s$%s$%s", baseName, suffix, randomString.nextString()); } @Override public boolean equals(Object other) { if (this == other) return true; if (other == null || getClass() != other.getClass()) return false; SuffixingRandom that = (SuffixingRandom) other; return javaLangPackagePrefix.equals(that.javaLangPackagePrefix) && suffix.equals(that.suffix) && baseNameResolver.equals(that.baseNameResolver); } @Override public int hashCode() { int result = suffix.hashCode(); result = 31 * result + javaLangPackagePrefix.hashCode(); result = 31 * result + baseNameResolver.hashCode(); return result; } @Override public String toString() { return "NamingStrategy.SuffixingRandom{" + "suffix='" + suffix + '\'' + ", javaLangPackagePrefix='" + javaLangPackagePrefix + '\'' + ", baseNameResolver=" + baseNameResolver + ", randomString=" + randomString + '}'; } /** * A base name resolver is responsible for resolving a name onto which the suffix is appended. */ public static interface BaseNameResolver { /** * Returns the resolved name. * * @param unnamedType The unnamed type which is to be named. * @return The resolved name. */ String resolve(UnnamedType unnamedType); /** * Uses the unnamed type's super type's name as the resolved name. */ static enum ForUnnamedType implements BaseNameResolver { /** * The singleton instance. */ INSTANCE; @Override public String resolve(UnnamedType unnamedType) { return unnamedType.getSuperClass().getName(); } } /** * Uses a specific type's name as the resolved name. */ static class ForGivenType implements BaseNameResolver { /** * The type description which represents the resolved name. */ private final TypeDescription typeDescription; /** * Creates a new base name resolver that resolves a using the name of a given type. * * @param typeDescription The type description which represents the resolved name. */ public ForGivenType(TypeDescription typeDescription) { this.typeDescription = typeDescription; } @Override public String resolve(UnnamedType unnamedType) { return typeDescription.getName(); } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && typeDescription.equals(((ForGivenType) other).typeDescription); } @Override public int hashCode() { return typeDescription.hashCode(); } @Override public String toString() { return "NamingStrategy.SuffixingRandom.BaseNameResolver.ForGivenType{" + "typeDescription=" + typeDescription + '}'; } } } } /** * A naming strategy that creates a name by prefixing a given class and its package with another package and * by appending a random number to the class's simple name. */ static class PrefixingRandom implements NamingStrategy { /** * The package to prefix. */ private final String prefix; /** * A seed generator. */ private final RandomString randomString; /** * Creates a new prefixing random naming strategy. * * @param prefix The prefix to append. */ public PrefixingRandom(String prefix) { this.prefix = prefix; randomString = new RandomString(); } @Override public String name(UnnamedType unnamedType) { return String.format("%s.%s$%s", prefix, unnamedType.getSuperClass().getName(), randomString.nextString()); } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && prefix.equals(((PrefixingRandom) other).prefix); } @Override public int hashCode() { return prefix.hashCode(); } @Override public String toString() { return "NamingStrategy.PrefixingRandom{" + "prefix='" + prefix + '\'' + ", randomString=" + randomString + '}'; } } /** * A naming strategy that applies a fixed name. *

 

* This strategy should only be used for one shot type generators since they will otherwise create types that * impose naming conflicts. */ static class Fixed implements NamingStrategy { /** * The fixed type name. */ private final String name; /** * Creates an immutable fixed naming strategy. * * @param name The name for the created type. */ public Fixed(String name) { this.name = name; } @Override public String name(UnnamedType unnamedType) { return name; } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && name.equals(((Fixed) other).name); } @Override public int hashCode() { return name.hashCode(); } @Override public String toString() { return "NamingStrategy.Fixed{name='" + name + '\'' + '}'; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy