package net.bytebuddy.dynamic.scaffold; import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationList; import net.bytebuddy.description.annotation.AnnotationValue; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.field.FieldList; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.method.ParameterDescription; import net.bytebuddy.description.modifier.ModifierContributor; import net.bytebuddy.description.type.PackageDescription; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeList; import net.bytebuddy.description.type.TypeVariableToken; import net.bytebuddy.dynamic.Transformer; import net.bytebuddy.implementation.LoadedTypeInitializer; import net.bytebuddy.implementation.bytecode.ByteCodeAppender; import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.utility.CompoundList; import java.lang.annotation.ElementType; import java.util.*; import static net.bytebuddy.matcher.ElementMatchers.is; /** * Implementations of this interface represent an instrumented type that is subject to change. Implementations * should however be immutable and return new instance when its builder methods are invoked. */ public interface InstrumentedType extends TypeDescription { /** * Creates a new instrumented type that includes a new field. * * @param token A token that represents the field's shape. This token must represent types in their detached state. * @return A new instrumented type that is equal to this instrumented type but with the additional field. */ InstrumentedType withField(FieldDescription.Token token); /** * Creates a new instrumented type that includes a new method or constructor. * * @param token A token that represents the method's shape. This token must represent types in their detached state. * @return A new instrumented type that is equal to this instrumented type but with the additional method. */ InstrumentedType withMethod(MethodDescription.Token token); /** * Creates a new instrumented type with changed modifiers. * * @param modifiers The instrumented type's modifiers. * @return A new instrumented type that is equal to this instrumented type but with the given modifiers. */ InstrumentedType withModifiers(int modifiers); /** * Creates a new instrumented type with the given interfaces implemented. * * @param interfaceTypes The interface types to implement. * @return A new instrumented type that is equal to this instrumented type but with the given interfaces implemented. */ InstrumentedType withInterfaces(TypeList.Generic interfaceTypes); /** * Creates a new instrumented type with the given type variable defined. * * @param typeVariable The type variable to declare. * @return A new instrumented type that is equal to this instrumented type but with the given type variable declared. */ InstrumentedType withTypeVariable(TypeVariableToken typeVariable); /** * Creates a new instrumented type with the given annotations. * * @param annotationDescriptions The annotations to add to the instrumented type. * @return A new instrumented type that is equal to this instrumented type but annotated with the given annotations */ InstrumentedType withAnnotations(List<? extends AnnotationDescription> annotationDescriptions); /** * Creates a new instrumented type that includes the given {@link net.bytebuddy.implementation.LoadedTypeInitializer}. * * @param loadedTypeInitializer The type initializer to include. * @return A new instrumented type that is equal to this instrumented type but with the additional type initializer. */ InstrumentedType withInitializer(LoadedTypeInitializer loadedTypeInitializer); /** * Creates a new instrumented type that executes the given initializer in the instrumented type's * type initializer. * * @param byteCodeAppender The byte code to add to the type initializer. * @return A new instrumented type that is equal to this instrumented type but with the given stack manipulation * attached to its type initializer. */ InstrumentedType withInitializer(ByteCodeAppender byteCodeAppender); /** * Returns the {@link net.bytebuddy.implementation.LoadedTypeInitializer}s that were registered * for this instrumented type. * * @return The registered loaded type initializers for this instrumented type. */ LoadedTypeInitializer getLoadedTypeInitializer(); /** * Returns this instrumented type's type initializer. * * @return This instrumented type's type initializer. */ TypeInitializer getTypeInitializer(); /** * Validates the instrumented type to define a legal Java type. * * @return This instrumented type as a non-modifiable type description. */ TypeDescription validated(); /** * Implementations represent an {@link InstrumentedType} with a flexible name. */ interface WithFlexibleName extends InstrumentedType { @Override WithFlexibleName withField(FieldDescription.Token token); @Override WithFlexibleName withMethod(MethodDescription.Token token); @Override WithFlexibleName withModifiers(int modifiers); @Override WithFlexibleName withInterfaces(TypeList.Generic interfaceTypes); @Override WithFlexibleName withTypeVariable(TypeVariableToken typeVariable); @Override WithFlexibleName withAnnotations(List<? extends AnnotationDescription> annotationDescriptions); @Override WithFlexibleName withInitializer(LoadedTypeInitializer loadedTypeInitializer); @Override WithFlexibleName withInitializer(ByteCodeAppender byteCodeAppender); /** * Creates a new instrumented type with a changed name. * * @param name The name of the instrumented type. * @return A new instrumented type that has the given name. */ WithFlexibleName withName(String name); /** * Applies a transformation onto all existing type variables of this instrumented type. A transformation is potentially unsafe * and it is the responsibility of the supplier to return a valid type variable token from the transformer. * * @param matcher The matcher to decide what type variables to transform. * @param transformer The transformer to apply on all matched type variables. * @return A new instrumented type with all matched type variables transformed. */ WithFlexibleName withTypeVariables(ElementMatcher<? super Generic> matcher, Transformer<TypeVariableToken> transformer); } /** * Implementations are able to prepare an {@link InstrumentedType}. */ interface Prepareable { /** * Prepares a given instrumented type. * * @param instrumentedType The instrumented type in its current form. * @return The prepared instrumented type. */ InstrumentedType prepare(InstrumentedType instrumentedType); } /** * A factory for creating an {@link InstrumentedType}. */ interface Factory { /** * Creates an instrumented type that represents the provided type. * * @param typeDescription The type to represent. * @return An appropriate instrumented type. */ InstrumentedType.WithFlexibleName represent(TypeDescription typeDescription); /** * Creates a new instrumented type as a subclass. * * @param name The type's name. * @param modifiers The type's modifiers. * @param superClass The type's super class. * @return A new instrumented type representing a subclass of the given parameters. */ InstrumentedType.WithFlexibleName subclass(String name, int modifiers, TypeDescription.Generic superClass); /** * Default implementations of instrumented type factories. */ enum Default implements Factory { /** * A factory for an instrumented type that allows to modify represented types. */ MODIFIABLE { @Override public InstrumentedType.WithFlexibleName represent(TypeDescription typeDescription) { return new InstrumentedType.Default(typeDescription.getName(), typeDescription.getModifiers(), typeDescription.getSuperClass(), typeDescription.getTypeVariables().asTokenList(is(typeDescription)), typeDescription.getInterfaces().accept(Generic.Visitor.Substitutor.ForDetachment.of(typeDescription)), typeDescription.getDeclaredFields().asTokenList(is(typeDescription)), typeDescription.getDeclaredMethods().asTokenList(is(typeDescription)), typeDescription.getDeclaredAnnotations(), TypeInitializer.None.INSTANCE, LoadedTypeInitializer.NoOp.INSTANCE, typeDescription.getDeclaringType(), typeDescription.getEnclosingMethod(), typeDescription.getEnclosingType(), typeDescription.getDeclaredTypes(), typeDescription.isMemberClass(), typeDescription.isAnonymousClass(), typeDescription.isLocalClass()); } }, /** * A factory for an instrumented type that does not allow to modify represented types. */ FROZEN { @Override public InstrumentedType.WithFlexibleName represent(TypeDescription typeDescription) { return new Frozen(typeDescription, LoadedTypeInitializer.NoOp.INSTANCE); } }; @Override public InstrumentedType.WithFlexibleName subclass(String name, int modifiers, TypeDescription.Generic superClass) { return new InstrumentedType.Default(name, modifiers, superClass, Collections.<TypeVariableToken>emptyList(), Collections.<Generic>emptyList(), Collections.<FieldDescription.Token>emptyList(), Collections.<MethodDescription.Token>emptyList(), Collections.<AnnotationDescription>emptyList(), TypeInitializer.None.INSTANCE, LoadedTypeInitializer.NoOp.INSTANCE, TypeDescription.UNDEFINED, MethodDescription.UNDEFINED, TypeDescription.UNDEFINED, Collections.<TypeDescription>emptyList(), false, false, false); } } } /** * A default implementation of an instrumented type. */ class Default extends AbstractBase.OfSimpleType implements InstrumentedType.WithFlexibleName { /** * A set containing all keywords of the Java programming language. */ private static final Set<String> KEYWORDS = new HashSet<String>(Arrays.asList( "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", "native", "super", "while" )); /** * The binary name of the instrumented type. */ private final String name; /** * The modifiers of the instrumented type. */ private final int modifiers; /** * The generic super type of the instrumented type. */ private final Generic superClass; /** * The instrumented type's type variables in their tokenized form. */ private final List<? extends TypeVariableToken> typeVariables; /** * A list of interfaces of the instrumented type. */ private final List<? extends Generic> interfaceTypes; /** * A list of field tokens describing the fields of the instrumented type. */ private final List<? extends FieldDescription.Token> fieldTokens; /** * A list of method tokens describing the methods of the instrumented type. */ private final List<? extends MethodDescription.Token> methodTokens; /** * A list of annotations of the annotated type. */ private final List<? extends AnnotationDescription> annotationDescriptions; /** * The type initializer of the instrumented type. */ private final TypeInitializer typeInitializer; /** * The loaded type initializer of the instrumented type. */ private final LoadedTypeInitializer loadedTypeInitializer; /** * The declaring type of the instrumented type or {@code null} if no such type exists. */ private final TypeDescription declaringType; /** * The enclosing method of the instrumented type or {@code null} if no such type exists. */ private final MethodDescription enclosingMethod; /** * The enclosing type of the instrumented type or {@code null} if no such type exists. */ private final TypeDescription enclosingType; /** * A list of types that are declared by this type. */ private final List<? extends TypeDescription> declaredTypes; /** * {@code true} if this type is a member class. */ private final boolean memberClass; /** * {@code true} if this type is a anonymous class. */ private final boolean anonymousClass; /** * {@code true} if this type is a local class. */ private final boolean localClass; /** * Creates a new instrumented type. * * @param name The binary name of the instrumented type. * @param modifiers The modifiers of the instrumented type. * @param typeVariables The instrumented type's type variables in their tokenized form. * @param superClass The generic super type of the instrumented type. * @param interfaceTypes A list of interfaces of the instrumented type. * @param fieldTokens A list of field tokens describing the fields of the instrumented type. * @param methodTokens A list of method tokens describing the methods of the instrumented type. * @param annotationDescriptions A list of annotations of the annotated type. * @param typeInitializer The type initializer of the instrumented type. * @param loadedTypeInitializer The loaded type initializer of the instrumented type. * @param declaringType The declaring type of the instrumented type or {@code null} if no such type exists. * @param enclosingMethod The enclosing method of the instrumented type or {@code null} if no such type exists. * @param enclosingType The enclosing type of the instrumented type or {@code null} if no such type exists. * @param declaredTypes A list of types that are declared by this type. * @param memberClass {@code true} if this type is a member class. * @param anonymousClass {@code true} if this type is a anonymous class. * @param localClass {@code true} if this type is a local class. */ protected Default(String name, int modifiers, Generic superClass, List<? extends TypeVariableToken> typeVariables, List<? extends Generic> interfaceTypes, List<? extends FieldDescription.Token> fieldTokens, List<? extends MethodDescription.Token> methodTokens, List<? extends AnnotationDescription> annotationDescriptions, TypeInitializer typeInitializer, LoadedTypeInitializer loadedTypeInitializer, TypeDescription declaringType, MethodDescription enclosingMethod, TypeDescription enclosingType, List<? extends TypeDescription> declaredTypes, boolean memberClass, boolean anonymousClass, boolean localClass) { this.name = name; this.modifiers = modifiers; this.typeVariables = typeVariables; this.superClass = superClass; this.interfaceTypes = interfaceTypes; this.fieldTokens = fieldTokens; this.methodTokens = methodTokens; this.annotationDescriptions = annotationDescriptions; this.typeInitializer = typeInitializer; this.loadedTypeInitializer = loadedTypeInitializer; this.declaringType = declaringType; this.enclosingMethod = enclosingMethod; this.enclosingType = enclosingType; this.declaredTypes = declaredTypes; this.memberClass = memberClass; this.anonymousClass = anonymousClass; this.localClass = localClass; } @Override public WithFlexibleName withModifiers(int modifiers) { return new Default(name, modifiers, superClass, typeVariables, interfaceTypes, fieldTokens, methodTokens, annotationDescriptions, typeInitializer, loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withField(FieldDescription.Token token) { return new Default(this.name, modifiers, superClass, typeVariables, interfaceTypes, CompoundList.of(fieldTokens, token.accept(Generic.Visitor.Substitutor.ForDetachment.of(this))), methodTokens, annotationDescriptions, typeInitializer, loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withMethod(MethodDescription.Token token) { return new Default(name, modifiers, superClass, typeVariables, interfaceTypes, fieldTokens, CompoundList.of(methodTokens, token.accept(Generic.Visitor.Substitutor.ForDetachment.of(this))), annotationDescriptions, typeInitializer, loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withInterfaces(TypeList.Generic interfaceTypes) { return new Default(name, modifiers, superClass, typeVariables, CompoundList.of(this.interfaceTypes, interfaceTypes.accept(Generic.Visitor.Substitutor.ForDetachment.of(this))), fieldTokens, methodTokens, annotationDescriptions, typeInitializer, loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withAnnotations(List<? extends AnnotationDescription> annotationDescriptions) { return new Default(name, modifiers, superClass, typeVariables, interfaceTypes, fieldTokens, methodTokens, CompoundList.of(this.annotationDescriptions, annotationDescriptions), typeInitializer, loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withTypeVariable(TypeVariableToken typeVariable) { return new Default(name, modifiers, superClass, CompoundList.of(typeVariables, typeVariable.accept(Generic.Visitor.Substitutor.ForDetachment.of(this))), interfaceTypes, fieldTokens, methodTokens, annotationDescriptions, typeInitializer, loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withName(String name) { return new Default(name, modifiers, superClass, typeVariables, interfaceTypes, fieldTokens, methodTokens, annotationDescriptions, typeInitializer, loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withTypeVariables(ElementMatcher<? super Generic> matcher, Transformer<TypeVariableToken> transformer) { List<TypeVariableToken> typeVariables = new ArrayList<TypeVariableToken>(this.typeVariables.size()); int index = 0; for (TypeVariableToken typeVariableToken : this.typeVariables) { typeVariables.add(matcher.matches(getTypeVariables().get(index++)) ? transformer.transform(this, typeVariableToken) : typeVariableToken); } return new Default(name, modifiers, superClass, typeVariables, interfaceTypes, fieldTokens, methodTokens, annotationDescriptions, typeInitializer, loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withInitializer(LoadedTypeInitializer loadedTypeInitializer) { return new Default(name, modifiers, superClass, typeVariables, interfaceTypes, fieldTokens, methodTokens, annotationDescriptions, typeInitializer, new LoadedTypeInitializer.Compound(this.loadedTypeInitializer, loadedTypeInitializer), declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public WithFlexibleName withInitializer(ByteCodeAppender byteCodeAppender) { return new Default(name, modifiers, superClass, typeVariables, interfaceTypes, fieldTokens, methodTokens, annotationDescriptions, typeInitializer.expandWith(byteCodeAppender), loadedTypeInitializer, declaringType, enclosingMethod, enclosingType, declaredTypes, memberClass, anonymousClass, localClass); } @Override public LoadedTypeInitializer getLoadedTypeInitializer() { return loadedTypeInitializer; } @Override public TypeInitializer getTypeInitializer() { return typeInitializer; } @Override public MethodDescription getEnclosingMethod() { return enclosingMethod; } @Override public TypeDescription getEnclosingType() { return enclosingType; } @Override public TypeList getDeclaredTypes() { return new TypeList.Explicit(declaredTypes); } @Override public boolean isAnonymousClass() { return anonymousClass; } @Override public boolean isLocalClass() { return localClass; } @Override public boolean isMemberClass() { return memberClass; } @Override public PackageDescription getPackage() { int packageIndex = name.lastIndexOf('.'); return packageIndex == -1 ? PackageDescription.UNDEFINED : new PackageDescription.Simple(name.substring(0, packageIndex)); } @Override public AnnotationList getDeclaredAnnotations() { return new AnnotationList.Explicit(annotationDescriptions); } @Override public TypeDescription getDeclaringType() { return declaringType; } @Override public Generic getSuperClass() { return superClass == null ? Generic.UNDEFINED : new Generic.LazyProjection.WithResolvedErasure(superClass, Generic.Visitor.Substitutor.ForAttachment.of(this)); } @Override public TypeList.Generic getInterfaces() { return new TypeList.Generic.ForDetachedTypes.WithResolvedErasure(interfaceTypes, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(this)); } @Override public FieldList<FieldDescription.InDefinedShape> getDeclaredFields() { return new FieldList.ForTokens(this, fieldTokens); } @Override public MethodList<MethodDescription.InDefinedShape> getDeclaredMethods() { return new MethodList.ForTokens(this, methodTokens); } @Override public TypeList.Generic getTypeVariables() { return TypeList.Generic.ForDetachedTypes.attachVariables(this, typeVariables); } @Override public int getModifiers() { return modifiers; } @Override public String getName() { return name; } @Override public TypeDescription validated() { if (!isValidIdentifier(getName().split("\\."))) { throw new IllegalStateException("Illegal type name: " + getName() + " for " + this); } else if ((getModifiers() & ~ModifierContributor.ForType.MASK) != EMPTY_MASK) { throw new IllegalStateException("Illegal modifiers " + getModifiers() + " for " + this); } else if (isPackageType() && getModifiers() != PackageDescription.PACKAGE_MODIFIERS) { throw new IllegalStateException("Illegal modifiers " + getModifiers() + " for package " + this); } TypeDescription.Generic superClass = getSuperClass(); if (superClass != null) { if (!superClass.accept(Generic.Visitor.Validator.SUPER_CLASS)) { throw new IllegalStateException("Illegal super class " + superClass + " for " + this); } else if (!superClass.accept(Generic.Visitor.Validator.ForTypeAnnotations.INSTANCE)) { throw new IllegalStateException("Illegal type annotations on super class " + superClass + " for " + this); } else if (!superClass.asErasure().isVisibleTo(this)) { throw new IllegalStateException("Invisible super type " + superClass + " for " + this); } } Set<TypeDescription> interfaceErasures = new HashSet<TypeDescription>(); for (TypeDescription.Generic interfaceType : getInterfaces()) { if (!interfaceType.accept(Generic.Visitor.Validator.INTERFACE)) { throw new IllegalStateException("Illegal interface " + interfaceType + " for " + this); } else if (!interfaceType.accept(Generic.Visitor.Validator.ForTypeAnnotations.INSTANCE)) { throw new IllegalStateException("Illegal type annotations on interface " + interfaceType + " for " + this); } else if (!interfaceErasures.add(interfaceType.asErasure())) { throw new IllegalStateException("Already implemented interface " + interfaceType + " for " + this); } else if (!interfaceType.asErasure().isVisibleTo(this)) { throw new IllegalStateException("Invisible interface type " + interfaceType + " for " + this); } } TypeList.Generic typeVariables = getTypeVariables(); if (!typeVariables.isEmpty() && isAssignableTo(Throwable.class)) { throw new IllegalStateException("Cannot define throwable " + this + " to be generic"); } Set<String> typeVariableNames = new HashSet<String>(); for (TypeDescription.Generic typeVariable : typeVariables) { String variableSymbol = typeVariable.getSymbol(); if (!typeVariableNames.add(variableSymbol)) { throw new IllegalStateException("Duplicate type variable symbol '" + typeVariable + "' for " + this); } else if (!isValidIdentifier(variableSymbol)) { throw new IllegalStateException("Illegal type variable name '" + typeVariable + "' for " + this); } else if (!Generic.Visitor.Validator.ForTypeAnnotations.ofFormalTypeVariable(typeVariable)) { throw new IllegalStateException("Illegal type annotation on '" + typeVariable + "' for " + this); } boolean interfaceBound = false; Set<TypeDescription.Generic> bounds = new HashSet<Generic>(); for (TypeDescription.Generic bound : typeVariable.getUpperBounds()) { if (!bound.accept(Generic.Visitor.Validator.TYPE_VARIABLE)) { throw new IllegalStateException("Illegal type variable bound " + bound + " of " + typeVariable + " for " + this); } else if (!bound.accept(Generic.Visitor.Validator.ForTypeAnnotations.INSTANCE)) { throw new IllegalStateException("Illegal type annotations on type variable " + bound + " for " + this); } else if (!bounds.add(bound)) { throw new IllegalStateException("Duplicate bound " + bound + " of " + typeVariable + " for " + this); } else if (interfaceBound && (bound.getSort().isTypeVariable() || !bound.isInterface())) { throw new IllegalStateException("Illegal interface bound " + bound + " of " + typeVariable + " for " + this); } interfaceBound = true; } if (!interfaceBound) { throw new IllegalStateException("Type variable " + typeVariable + " for " + this + " does not define at least one bound"); } } Set<TypeDescription> typeAnnotationTypes = new HashSet<TypeDescription>(); for (AnnotationDescription annotationDescription : getDeclaredAnnotations()) { if (!annotationDescription.getElementTypes().contains(ElementType.TYPE) && !(isAnnotation() && annotationDescription.getElementTypes().contains(ElementType.ANNOTATION_TYPE)) && !(isPackageType() && annotationDescription.getElementTypes().contains(ElementType.PACKAGE))) { throw new IllegalStateException("Cannot add " + annotationDescription + " on " + this); } else if (!typeAnnotationTypes.add(annotationDescription.getAnnotationType())) { throw new IllegalStateException("Duplicate annotation " + annotationDescription + " for " + this); } } Set<FieldDescription.SignatureToken> fieldSignatureTokens = new HashSet<FieldDescription.SignatureToken>(); for (FieldDescription.InDefinedShape fieldDescription : getDeclaredFields()) { String fieldName = fieldDescription.getName(); if (!fieldSignatureTokens.add(fieldDescription.asSignatureToken())) { throw new IllegalStateException("Duplicate field definition for " + fieldDescription); } else if (!isValidIdentifier(fieldName)) { throw new IllegalStateException("Illegal field name for " + fieldDescription); } else if ((fieldDescription.getModifiers() & ~ModifierContributor.ForField.MASK) != EMPTY_MASK) { throw new IllegalStateException("Illegal field modifiers " + fieldDescription.getModifiers() + " for " + fieldDescription); } Generic fieldType = fieldDescription.getType(); if (!fieldType.accept(Generic.Visitor.Validator.FIELD)) { throw new IllegalStateException("Illegal field type " + fieldType + " for " + fieldDescription); } else if (!fieldType.accept(Generic.Visitor.Validator.ForTypeAnnotations.INSTANCE)) { throw new IllegalStateException("Illegal type annotations on " + fieldType + " for " + this); } else if (!fieldDescription.isSynthetic() && !fieldType.asErasure().isVisibleTo(this)) { throw new IllegalStateException("Invisible field type " + fieldDescription.getType() + " for " + fieldDescription); } Set<TypeDescription> fieldAnnotationTypes = new HashSet<TypeDescription>(); for (AnnotationDescription annotationDescription : fieldDescription.getDeclaredAnnotations()) { if (!annotationDescription.getElementTypes().contains(ElementType.FIELD)) { throw new IllegalStateException("Cannot add " + annotationDescription + " on " + fieldDescription); } else if (!fieldAnnotationTypes.add(annotationDescription.getAnnotationType())) { throw new IllegalStateException("Duplicate annotation " + annotationDescription + " for " + fieldDescription); } } } Set<MethodDescription.SignatureToken> methodSignatureTokens = new HashSet<MethodDescription.SignatureToken>(); for (MethodDescription.InDefinedShape methodDescription : getDeclaredMethods()) { if (!methodSignatureTokens.add(methodDescription.asSignatureToken())) { throw new IllegalStateException("Duplicate method signature for " + methodDescription); } else if ((methodDescription.getModifiers() & ~ModifierContributor.ForMethod.MASK) != 0) { throw new IllegalStateException("Illegal modifiers " + methodDescription.getModifiers() + " for " + methodDescription); } Set<String> methodTypeVariableNames = new HashSet<String>(); for (TypeDescription.Generic typeVariable : methodDescription.getTypeVariables()) { String variableSymbol = typeVariable.getSymbol(); if (!methodTypeVariableNames.add(variableSymbol)) { throw new IllegalStateException("Duplicate type variable symbol '" + typeVariable + "' for " + methodDescription); } else if (!isValidIdentifier(variableSymbol)) { throw new IllegalStateException("Illegal type variable name '" + typeVariable + "' for " + methodDescription); } else if (!Generic.Visitor.Validator.ForTypeAnnotations.ofFormalTypeVariable(typeVariable)) { throw new IllegalStateException("Illegal type annotation on '" + typeVariable + "' for " + methodDescription); } boolean interfaceBound = false; Set<TypeDescription.Generic> bounds = new HashSet<Generic>(); for (TypeDescription.Generic bound : typeVariable.getUpperBounds()) { if (!bound.accept(Generic.Visitor.Validator.TYPE_VARIABLE)) { throw new IllegalStateException("Illegal type variable bound " + bound + " of " + typeVariable + " for " + methodDescription); } else if (!bound.accept(Generic.Visitor.Validator.ForTypeAnnotations.INSTANCE)) { throw new IllegalStateException("Illegal type annotations on bound " + bound + " of " + typeVariable + " for " + this); } else if (!bounds.add(bound)) { throw new IllegalStateException("Duplicate bound " + bound + " of " + typeVariable + " for " + methodDescription); } else if (interfaceBound && (bound.getSort().isTypeVariable() || !bound.isInterface())) { throw new IllegalStateException("Illegal interface bound " + bound + " of " + typeVariable + " for " + methodDescription); } interfaceBound = true; } if (!interfaceBound) { throw new IllegalStateException("Type variable " + typeVariable + " for " + methodDescription + " does not define at least one bound"); } } Generic returnType = methodDescription.getReturnType(); if (methodDescription.isTypeInitializer()) { throw new IllegalStateException("Illegal explicit declaration of a type initializer by " + this); } else if (methodDescription.isConstructor()) { if (!returnType.represents(void.class)) { throw new IllegalStateException("A constructor must return void " + methodDescription); } else if (!returnType.getDeclaredAnnotations().isEmpty()) { throw new IllegalStateException("The void non-type must not be annotated for " + methodDescription); } } else if (!isValidIdentifier(methodDescription.getInternalName())) { throw new IllegalStateException("Illegal method name " + returnType + " for " + methodDescription); } else if (!returnType.accept(Generic.Visitor.Validator.METHOD_RETURN)) { throw new IllegalStateException("Illegal return type " + returnType + " for " + methodDescription); } else if (!returnType.accept(Generic.Visitor.Validator.ForTypeAnnotations.INSTANCE)) { throw new IllegalStateException("Illegal type annotations return type " + returnType + " for " + methodDescription); } else if (!methodDescription.isSynthetic() && !methodDescription.getReturnType().asErasure().isVisibleTo(this)) { throw new IllegalStateException("Invisible return type " + methodDescription.getReturnType() + " for " + methodDescription); } Set<String> parameterNames = new HashSet<String>(); for (ParameterDescription.InDefinedShape parameterDescription : methodDescription.getParameters()) { Generic parameterType = parameterDescription.getType(); if (!parameterType.accept(Generic.Visitor.Validator.METHOD_PARAMETER)) { throw new IllegalStateException("Illegal parameter type of " + parameterDescription + " for " + methodDescription); } else if (!parameterType.accept(Generic.Visitor.Validator.ForTypeAnnotations.INSTANCE)) { throw new IllegalStateException("Illegal type annotations return type " + parameterType + " for " + methodDescription); } else if (!methodDescription.isSynthetic() && !parameterType.asErasure().isVisibleTo(this)) { throw new IllegalStateException("Invisible parameter type of " + parameterDescription + " for " + methodDescription); } if (parameterDescription.isNamed()) { String parameterName = parameterDescription.getName(); if (!parameterNames.add(parameterName)) { throw new IllegalStateException("Duplicate parameter name of " + parameterDescription + " for " + methodDescription); } else if (!isValidIdentifier(parameterName)) { throw new IllegalStateException("Illegal parameter name of " + parameterDescription + " for " + methodDescription); } } if (parameterDescription.hasModifiers() && (parameterDescription.getModifiers() & ~ModifierContributor.ForParameter.MASK) != EMPTY_MASK) { throw new IllegalStateException("Illegal modifiers of " + parameterDescription + " for " + methodDescription); } Set<TypeDescription> parameterAnnotationTypes = new HashSet<TypeDescription>(); for (AnnotationDescription annotationDescription : parameterDescription.getDeclaredAnnotations()) { if (!annotationDescription.getElementTypes().contains(ElementType.PARAMETER)) { throw new IllegalStateException("Cannot add " + annotationDescription + " on " + parameterDescription); } else if (!parameterAnnotationTypes.add(annotationDescription.getAnnotationType())) { throw new IllegalStateException("Duplicate annotation " + annotationDescription + " of " + parameterDescription + " for " + methodDescription); } } } Set<TypeDescription.Generic> exceptionTypes = new HashSet<Generic>(); for (TypeDescription.Generic exceptionType : methodDescription.getExceptionTypes()) { if (!exceptionTypes.add(exceptionType)) { throw new IllegalStateException("Duplicate exception type " + exceptionType + " for " + methodDescription); } else if (!exceptionType.accept(Generic.Visitor.Validator.EXCEPTION)) { throw new IllegalStateException("Illegal exception type " + exceptionType + " for " + methodDescription); } else if (!exceptionType.accept(Generic.Visitor.Validator.ForTypeAnnotations.INSTANCE)) { throw new IllegalStateException("Illegal type annotations on " + exceptionType + " for " + methodDescription); } else if (!methodDescription.isSynthetic() && !exceptionType.asErasure().isVisibleTo(this)) { throw new IllegalStateException("Invisible exception type " + exceptionType + " for " + methodDescription); } } Set<TypeDescription> methodAnnotationTypes = new HashSet<TypeDescription>(); for (AnnotationDescription annotationDescription : methodDescription.getDeclaredAnnotations()) { if (!annotationDescription.getElementTypes().contains(methodDescription.isMethod() ? ElementType.METHOD : ElementType.CONSTRUCTOR)) { throw new IllegalStateException("Cannot add " + annotationDescription + " on " + methodDescription); } else if (!methodAnnotationTypes.add(annotationDescription.getAnnotationType())) { throw new IllegalStateException("Duplicate annotation " + annotationDescription + " for " + methodDescription); } } AnnotationValue<?, ?> defaultValue = methodDescription.getDefaultValue(); if (defaultValue != null && !methodDescription.isDefaultValue(defaultValue)) { throw new IllegalStateException("Illegal default value " + defaultValue + "for " + methodDescription); } Generic receiverType = methodDescription.getReceiverType(); if (receiverType != null && !receiverType.accept(Generic.Visitor.Validator.RECEIVER)) { throw new IllegalStateException("Illegal receiver type " + receiverType + " for " + methodDescription); } else if (methodDescription.isStatic()) { if (receiverType != null) { throw new IllegalStateException("Static method " + methodDescription + " defines a non-null receiver " + receiverType); } } else if (methodDescription.isConstructor()) { TypeDescription enclosingType = getEnclosingType(); if (receiverType == null || !receiverType.asErasure().equals(enclosingType == null ? this : enclosingType)) { throw new IllegalStateException("Constructor " + methodDescription + " defines an illegal receiver " + receiverType); } } else if (/* methodDescription.isMethod() */ receiverType == null || !equals(receiverType.asErasure())) { throw new IllegalStateException("Method " + methodDescription + " defines an illegal receiver " + receiverType); } } return this; } /** * Checks if an array of identifiers is a valid compound Java identifier. * * @param identifier an array of potentially invalid Java identifiers. * @return {@code true} if all identifiers are valid and the array is not empty. */ private static boolean isValidIdentifier(String[] identifier) { if (identifier.length == 0) { return false; } for (String part : identifier) { if (!isValidIdentifier(part)) { return false; } } return true; } /** * Checks if a Java identifier is valid. * * @param identifier The identifier to check for validity. * @return {@code true} if the given identifier is valid. */ private static boolean isValidIdentifier(String identifier) { if (KEYWORDS.contains(identifier) || identifier.isEmpty() || !Character.isJavaIdentifierStart(identifier.charAt(0))) { return false; } else if (identifier.equals(PackageDescription.PACKAGE_CLASS_NAME)) { return true; } for (int index = 1; index < identifier.length(); index++) { if (!Character.isJavaIdentifierPart(identifier.charAt(index))) { return false; } } return true; } } /** * A frozen representation of an instrumented type of which the structure must not be modified. */ class Frozen extends AbstractBase.OfSimpleType implements InstrumentedType.WithFlexibleName { /** * The represented type description. */ private final TypeDescription typeDescription; /** * The type's loaded type initializer. */ private final LoadedTypeInitializer loadedTypeInitializer; /** * Creates a new frozen representation of an instrumented type. * * @param typeDescription The represented type description. * @param loadedTypeInitializer The type's loaded type initializer. */ protected Frozen(TypeDescription typeDescription, LoadedTypeInitializer loadedTypeInitializer) { this.typeDescription = typeDescription; this.loadedTypeInitializer = loadedTypeInitializer; } @Override public AnnotationList getDeclaredAnnotations() { return typeDescription.getDeclaredAnnotations(); } @Override public int getModifiers() { return typeDescription.getModifiers(); } @Override public TypeList.Generic getTypeVariables() { return typeDescription.getTypeVariables(); } @Override public String getName() { return typeDescription.getName(); } @Override public Generic getSuperClass() { return typeDescription.getSuperClass(); } @Override public TypeList.Generic getInterfaces() { return typeDescription.getInterfaces(); } @Override public FieldList<FieldDescription.InDefinedShape> getDeclaredFields() { return typeDescription.getDeclaredFields(); } @Override public MethodList<MethodDescription.InDefinedShape> getDeclaredMethods() { return typeDescription.getDeclaredMethods(); } @Override public boolean isAnonymousClass() { return typeDescription.isAnonymousClass(); } @Override public boolean isLocalClass() { return typeDescription.isLocalClass(); } @Override public boolean isMemberClass() { return typeDescription.isMemberClass(); } @Override public PackageDescription getPackage() { return typeDescription.getPackage(); } @Override public TypeDescription getEnclosingType() { return typeDescription.getEnclosingType(); } @Override public TypeDescription getDeclaringType() { return typeDescription.getDeclaringType(); } @Override public TypeList getDeclaredTypes() { return typeDescription.getDeclaredTypes(); } @Override public MethodDescription getEnclosingMethod() { return typeDescription.getEnclosingMethod(); } @Override public String getGenericSignature() { // Embrace use of native generic signature by direct delegation. return typeDescription.getGenericSignature(); } @Override public int getActualModifiers(boolean superFlag) { // Embrace use of native actual modifiers by direct delegation. return typeDescription.getActualModifiers(superFlag); } @Override public WithFlexibleName withField(FieldDescription.Token token) { throw new IllegalStateException("Cannot define field for frozen type: " + typeDescription); } @Override public WithFlexibleName withMethod(MethodDescription.Token token) { throw new IllegalStateException("Cannot define method for frozen type: " + typeDescription); } @Override public WithFlexibleName withModifiers(int modifiers) { throw new IllegalStateException("Cannot change modifiers for frozen type: " + typeDescription); } @Override public WithFlexibleName withInterfaces(TypeList.Generic interfaceTypes) { throw new IllegalStateException("Cannot add interfaces for frozen type: " + typeDescription); } @Override public WithFlexibleName withTypeVariable(TypeVariableToken typeVariable) { throw new IllegalStateException("Cannot define type variable for frozen type: " + typeDescription); } @Override public WithFlexibleName withAnnotations(List<? extends AnnotationDescription> annotationDescriptions) { throw new IllegalStateException("Cannot add annotation to frozen type: " + typeDescription); } @Override public WithFlexibleName withInitializer(LoadedTypeInitializer loadedTypeInitializer) { return new Frozen(typeDescription, new LoadedTypeInitializer.Compound(this.loadedTypeInitializer, loadedTypeInitializer)); } @Override public WithFlexibleName withInitializer(ByteCodeAppender byteCodeAppender) { throw new IllegalStateException("Cannot add initializer to frozen type: " + typeDescription); } @Override public WithFlexibleName withName(String name) { throw new IllegalStateException("Cannot change name of frozen type: " + typeDescription); } @Override public WithFlexibleName withTypeVariables(ElementMatcher<? super Generic> matcher, Transformer<TypeVariableToken> transformer) { throw new IllegalStateException("Cannot add type variables of frozen type: " + typeDescription); } @Override public LoadedTypeInitializer getLoadedTypeInitializer() { return loadedTypeInitializer; } @Override public TypeInitializer getTypeInitializer() { return TypeInitializer.None.INSTANCE; } @Override public TypeDescription validated() { return typeDescription; } } }