package com.fasterxml.classmate;
import java.lang.reflect.TypeVariable;
import java.util.*;
Helper class used for storing binding of local type variables to
matching resolved types, in context of a single class.
/**
* Helper class used for storing binding of local type variables to
* matching resolved types, in context of a single class.
*/
public final class TypeBindings
{
private final static String[] NO_STRINGS = new String[0];
private final static ResolvedType[] NO_TYPES = new ResolvedType[0];
private final static TypeBindings EMPTY = new TypeBindings(NO_STRINGS, NO_TYPES, null);
Array of type (type variable) names.
/**
* Array of type (type variable) names.
*/
private final String[] _names;
Types matching names
/**
* Types matching names
*/
private final ResolvedType[] _types;
Names of potentially unresolved type variables.
Since: 2.3
/**
* Names of potentially unresolved type variables.
*
* @since 2.3
*/
private final String[] _unboundVariables;
private final int _hashCode;
/*
/**********************************************************************
/* Construction
/**********************************************************************
*/
private TypeBindings(String[] names, ResolvedType[] types, String[] uvars)
{
_names = (names == null) ? NO_STRINGS : names;
_types = (types == null) ? NO_TYPES : types;
if (_names.length != _types.length) {
throw new IllegalArgumentException("Mismatching names ("+_names.length+"), types ("+_types.length+")");
}
int h = 1;
for (int i = 0, len = _types.length; i < len; ++i) {
h += _types[i].hashCode();
}
_unboundVariables = uvars;
_hashCode = h;
}
public static TypeBindings emptyBindings() {
return EMPTY;
}
Factory method for constructing bindings for given class using specified type
parameters.
/**
* Factory method for constructing bindings for given class using specified type
* parameters.
*/
public static TypeBindings create(Class<?> erasedType, List<ResolvedType> typeList)
{
ResolvedType[] types = (typeList == null || typeList.isEmpty()) ?
NO_TYPES : typeList.toArray(new ResolvedType[0]);
return create(erasedType, types);
}
public static TypeBindings create(Class<?> erasedType, ResolvedType[] types)
{
if (types == null) {
types = NO_TYPES;
}
TypeVariable<?>[] vars = erasedType.getTypeParameters();
String[] names;
if (vars == null || vars.length == 0) {
names = NO_STRINGS;
} else {
int len = vars.length;
names = new String[len];
for (int i = 0; i < len; ++i) {
names[i] = vars[i].getName();
}
}
// Check here to give better error message
if (names.length != types.length) {
throw new IllegalArgumentException("Can not create TypeBinding for class "+erasedType.getName()
+" with "+types.length+" type parameter"
+((types.length == 1) ? "" : "s")+": class expects "+names.length);
}
return new TypeBindings(names, types, null);
}
Method for creating an instance that has same bindings as this object,
plus an indicator for additional type variable that may be unbound within
this context; this is needed to resolve recursive self-references.
Since: 1.3 (renamed from "withAdditionalBinding" in 1.2)
/**
* Method for creating an instance that has same bindings as this object,
* plus an indicator for additional type variable that may be unbound within
* this context; this is needed to resolve recursive self-references.
*
* @since 1.3 (renamed from "withAdditionalBinding" in 1.2)
*/
public TypeBindings withUnboundVariable(String name)
{
int len = (_unboundVariables == null) ? 0 : _unboundVariables.length;
String[] names = (len == 0)
? new String[1] : Arrays.copyOf(_unboundVariables, len+1);
names[len] = name;
return new TypeBindings(_names, _types, names);
}
/*
/**********************************************************************
/* Accessors
/**********************************************************************
*/
Find type bound to specified name, if there is one; returns bound type if so, null if not.
/**
* Find type bound to specified name, if there is one; returns bound type if so, null if not.
*/
public ResolvedType findBoundType(String name)
{
for (int i = 0, len = _names.length; i < len; ++i) {
if (name.equals(_names[i])) {
return _types[i];
}
}
return null;
}
public boolean isEmpty() {
return (_types.length == 0);
}
Returns number of bindings contained
/**
* Returns number of bindings contained
*/
public int size() {
return _types.length;
}
public String getBoundName(int index)
{
if (index < 0 || index >= _names.length) {
return null;
}
return _names[index];
}
public ResolvedType getBoundType(int index)
{
if (index < 0 || index >= _types.length) {
return null;
}
return _types[index];
}
Accessor for getting bound types in declaration order
/**
* Accessor for getting bound types in declaration order
*/
public List<ResolvedType> getTypeParameters()
{
if (_types.length == 0) {
return Collections.emptyList();
}
return Arrays.asList(_types);
}
Since: 2.3
/**
* @since 2.3
*/
public boolean hasUnbound(String name) {
if (_unboundVariables != null) {
for (int i = _unboundVariables.length; --i >= 0; ) {
if (name.equals(_unboundVariables[i])) {
return true;
}
}
}
return false;
}
/*
/**********************************************************************
/* Standard methods
/**********************************************************************
*/
@Override public String toString()
{
if (_types.length == 0) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append('<');
for (int i = 0, len = _types.length; i < len; ++i) {
if (i > 0) {
sb.append(',');
}
sb = _types[i].appendBriefDescription(sb);
}
sb.append('>');
return sb.toString();
}
@Override public int hashCode() { return _hashCode; }
@Override public boolean equals(Object o)
{
if (o == this) return true;
if (o == null || o.getClass() != getClass()) return false;
TypeBindings other = (TypeBindings) o;
int len = _types.length;
if (len != other.size()) {
return false;
}
ResolvedType[] otherTypes = other._types;
for (int i = 0; i < len; ++i) {
if (!otherTypes[i].equals(_types[i])) {
return false;
}
}
return true;
}
/*
/**********************************************************************
/* Package accessible methods
/**********************************************************************
*/
protected ResolvedType[] typeParameterArray() {
return _types;
}
}