1 package net.florianschoppmann.java.reflect; 2 3 import javax.annotation.Nullable; 4 import javax.lang.model.type.TypeKind; 5 import javax.lang.model.type.TypeVariable; 6 import javax.lang.model.type.TypeVisitor; 7 import java.util.Objects; 8 9 final class TypeVariableImpl extends AnnotatedConstructImpl implements ReflectionTypeMirror, TypeVariable { 10 private boolean frozen = false; 11 12 private final TypeParameterElementImpl typeParameterElement; 13 @Nullable private final WildcardTypeImpl capturedTypeArgument; 14 @Nullable private ReflectionTypeMirror upperBound; 15 @Nullable private ReflectionTypeMirror lowerBound; 16 17 TypeVariableImpl(TypeParameterElementImpl typeParameterElement, @Nullable WildcardTypeImpl capturedTypeArgument) { 18 Objects.requireNonNull(typeParameterElement); 19 20 this.typeParameterElement = typeParameterElement; 21 this.capturedTypeArgument = capturedTypeArgument; 22 } 23 24 @Override 25 public boolean equals(@Nullable Object otherObject) { 26 if (this == otherObject) { 27 return true; 28 } else if (otherObject == null || getClass() != otherObject.getClass()) { 29 return false; 30 } 31 32 requireFrozen(); 33 assert upperBound != null && lowerBound != null : "must be non-null when frozen"; 34 35 TypeVariableImpl other = (TypeVariableImpl) otherObject; 36 return typeParameterElement.equals(other.typeParameterElement) 37 && Objects.equals(capturedTypeArgument, other.capturedTypeArgument) 38 && upperBound.equals(other.upperBound) 39 && lowerBound.equals(other.lowerBound); 40 } 41 42 @Override 43 public int hashCode() { 44 requireFrozen(); 45 46 return Objects.hash(typeParameterElement, capturedTypeArgument, upperBound, lowerBound); 47 } 48 49 @Override 50 public <R, P> R accept(TypeVisitor<R, P> visitor, @Nullable P parameter) { 51 return visitor.visitTypeVariable(this, parameter); 52 } 53 54 @Override 55 public String toString() { 56 return ReflectionTypes.getInstance().toString(this); 57 } 58 59 void requireUnfrozen() { 60 if (frozen) { 61 throw new IllegalStateException(String.format( 62 "Tried to modify instance of %s after it became effectively immutable.", getClass() 63 )); 64 } 65 } 66 67 void requireFrozen() { 68 if (!frozen) { 69 throw new IllegalStateException(String.format( 70 "Instance of %s used before object construction finished.", getClass() 71 )); 72 } 73 } 74 75 @Override 76 public TypeParameterElementImpl asElement() { 77 return typeParameterElement; 78 } 79 80 @Override 81 public ReflectionTypeMirror getUpperBound() { 82 requireFrozen(); 83 assert upperBound != null : "must be non-null when frozen"; 84 return upperBound; 85 } 86 87 @Override 88 public ReflectionTypeMirror getLowerBound() { 89 requireFrozen(); 90 assert lowerBound != null : "must be non-null when frozen"; 91 return lowerBound; 92 } 93 94 void setUpperAndLowerBounds(ReflectionTypeMirror newUpperBound, ReflectionTypeMirror newLowerBound) { 95 requireUnfrozen(); 96 Objects.requireNonNull(newUpperBound); 97 Objects.requireNonNull(newLowerBound); 98 99 upperBound = newUpperBound; 100 lowerBound = newLowerBound; 101 frozen = true; 102 } 103 104 @Override 105 public TypeKind getKind() { 106 return TypeKind.TYPEVAR; 107 } 108 109 @Nullable 110 WildcardTypeImpl getCapturedTypeArgument() { 111 return capturedTypeArgument; 112 } 113 }