TypeVariableImpl.java
package net.florianschoppmann.java.reflect;
import javax.annotation.Nullable;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.TypeVisitor;
import java.util.Objects;
final class TypeVariableImpl extends AnnotatedConstructImpl implements ReflectionTypeMirror, TypeVariable {
private boolean frozen = false;
private final TypeParameterElementImpl typeParameterElement;
@Nullable private final WildcardTypeImpl capturedTypeArgument;
@Nullable private ReflectionTypeMirror upperBound;
@Nullable private ReflectionTypeMirror lowerBound;
TypeVariableImpl(TypeParameterElementImpl typeParameterElement, @Nullable WildcardTypeImpl capturedTypeArgument) {
Objects.requireNonNull(typeParameterElement);
this.typeParameterElement = typeParameterElement;
this.capturedTypeArgument = capturedTypeArgument;
}
@Override
public boolean equals(@Nullable Object otherObject) {
if (this == otherObject) {
return true;
} else if (otherObject == null || getClass() != otherObject.getClass()) {
return false;
}
requireFrozen();
assert upperBound != null && lowerBound != null : "must be non-null when frozen";
TypeVariableImpl other = (TypeVariableImpl) otherObject;
return typeParameterElement.equals(other.typeParameterElement)
&& Objects.equals(capturedTypeArgument, other.capturedTypeArgument)
&& upperBound.equals(other.upperBound)
&& lowerBound.equals(other.lowerBound);
}
@Override
public int hashCode() {
requireFrozen();
return Objects.hash(typeParameterElement, capturedTypeArgument, upperBound, lowerBound);
}
@Override
public <R, P> R accept(TypeVisitor<R, P> visitor, @Nullable P parameter) {
return visitor.visitTypeVariable(this, parameter);
}
@Override
public String toString() {
return ReflectionTypes.getInstance().toString(this);
}
void requireUnfrozen() {
if (frozen) {
throw new IllegalStateException(String.format(
"Tried to modify instance of %s after it became effectively immutable.", getClass()
));
}
}
void requireFrozen() {
if (!frozen) {
throw new IllegalStateException(String.format(
"Instance of %s used before object construction finished.", getClass()
));
}
}
@Override
public TypeParameterElementImpl asElement() {
return typeParameterElement;
}
@Override
public ReflectionTypeMirror getUpperBound() {
requireFrozen();
assert upperBound != null : "must be non-null when frozen";
return upperBound;
}
@Override
public ReflectionTypeMirror getLowerBound() {
requireFrozen();
assert lowerBound != null : "must be non-null when frozen";
return lowerBound;
}
void setUpperAndLowerBounds(ReflectionTypeMirror newUpperBound, ReflectionTypeMirror newLowerBound) {
requireUnfrozen();
Objects.requireNonNull(newUpperBound);
Objects.requireNonNull(newLowerBound);
upperBound = newUpperBound;
lowerBound = newLowerBound;
frozen = true;
}
@Override
public TypeKind getKind() {
return TypeKind.TYPEVAR;
}
@Nullable
WildcardTypeImpl getCapturedTypeArgument() {
return capturedTypeArgument;
}
}