package scouter.bytebuddy.description.enumeration; import scouter.bytebuddy.description.NamedElement; import scouter.bytebuddy.description.type.TypeDescription; import java.util.ArrayList; import java.util.List; /** * Describes an enumeration value. Note that the {@link java.lang.Object#toString} method always returns the * value as if the method was not overridden, i.e. the name of the enumeration constant. */ public interface EnumerationDescription extends NamedElement { /** * Returns the name of this instance's enumeration value. * * @return The name of this enumeration constant. */ String getValue(); /** * Returns the type of this enumeration. * * @return The type of this enumeration. */ TypeDescription getEnumerationType(); /** * Prepares this enumeration value to be loaded. * * @param type A type constant representing the enumeration value. * @param <T> The enumeration type. * @return The loaded enumeration constant corresponding to this value. */ <T extends Enum<T>> T load(Class<T> type); /** * An adapter implementation of an enumeration description. */ abstract class AbstractBase implements EnumerationDescription { @Override public String getActualName() { return getValue(); } @Override public boolean equals(Object other) { return other == this || other instanceof EnumerationDescription && (((EnumerationDescription) other)).getEnumerationType().equals(getEnumerationType()) && (((EnumerationDescription) other)).getValue().equals(getValue()); } @Override public int hashCode() { return getValue().hashCode() + 31 * getEnumerationType().hashCode(); } @Override public String toString() { return getValue(); } } /** * An enumeration description representing a loaded enumeration. */ class ForLoadedEnumeration extends AbstractBase { /** * The loaded enumeration value. */ private final Enum<?> value; /** * Creates a new enumeration value representation for a loaded enumeration. * * @param value The value to represent. */ public ForLoadedEnumeration(Enum<?> value) { this.value = value; } /** * Enlists a given array of loaded enumerations as enumeration values. * * @param enumerations The enumerations to represent. * @return A list of the given enumerations. */ public static List<EnumerationDescription> asList(Enum<?>[] enumerations) { List<EnumerationDescription> result = new ArrayList<EnumerationDescription>(enumerations.length); for (Enum<?> enumeration : enumerations) { result.add(new ForLoadedEnumeration(enumeration)); } return result; } @Override public String getValue() { return value.name(); } @Override public TypeDescription getEnumerationType() { return new TypeDescription.ForLoadedType(value.getDeclaringClass()); } @Override @SuppressWarnings("unchecked") public <T extends Enum<T>> T load(Class<T> type) { return value.getDeclaringClass() == type ? (T) value : Enum.valueOf(type, value.name()); } } /** * A latent description of an enumeration value. */ class Latent extends AbstractBase { /** * The type of the enumeration. */ private final TypeDescription enumerationType; /** * The value of the enumeration. */ private final String value; /** * Creates a latent description of an enumeration value. * * @param enumerationType The enumeration type. * @param value The value of the enumeration. */ public Latent(TypeDescription enumerationType, String value) { this.enumerationType = enumerationType; this.value = value; } @Override public String getValue() { return value; } @Override public TypeDescription getEnumerationType() { return enumerationType; } @Override public <T extends Enum<T>> T load(Class<T> type) { if (!enumerationType.represents(type)) { throw new IllegalArgumentException(type + " does not represent " + enumerationType); } return Enum.valueOf(type, value); } } }