blob: f8d142469521100e890300a85ff077d8fffd9e0d [file] [log] [blame]
/*
* #%L
* Apache Geronimo JAX-RS Spec 2.0
* %%
* Copyright (C) 2003 - 2014 The Apache Software Foundation
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package javax.ws.rs.core;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.Stack;
public class GenericType<T> {
private final Type type;
private final Class<?> rawType;
protected GenericType() {
type = getTypeArgument(getClass(), GenericType.class);
rawType = getClass(type);
}
public GenericType(Type genericType) {
if (genericType == null) {
throw new IllegalArgumentException("Type must not be null");
}
type = genericType;
rawType = getClass(type);
}
public final Type getType() {
return type;
}
public final Class<?> getRawType() {
return rawType;
}
private static Class getClass(Type type) {
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
if (parameterizedType.getRawType() instanceof Class) {
return (Class) parameterizedType.getRawType();
}
} else if (type instanceof GenericArrayType) {
GenericArrayType array = (GenericArrayType) type;
final Class<?> componentRawType = getClass(array.getGenericComponentType());
return getArrayClass(componentRawType);
}
throw new IllegalArgumentException("Type parameter " + type.toString() + " not a class or " +
"parameterized type whose raw type is a class");
}
private static Class getArrayClass(Class c) {
try {
Object o = Array.newInstance(c, 0);
return o.getClass();
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
static Type getTypeArgument(Class<?> clazz, Class<?> baseClass) {
Stack<Type> superclasses = new Stack<Type>();
Type currentType;
Class<?> currentClass = clazz;
do {
currentType = currentClass.getGenericSuperclass();
superclasses.push(currentType);
if (currentType instanceof Class) {
currentClass = (Class) currentType;
} else if (currentType instanceof ParameterizedType) {
currentClass = (Class) ((ParameterizedType) currentType).getRawType();
}
} while (!currentClass.equals(baseClass));
TypeVariable tv = baseClass.getTypeParameters()[0];
while (!superclasses.isEmpty()) {
currentType = superclasses.pop();
if (currentType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) currentType;
Class<?> rawType = (Class) pt.getRawType();
int argIndex = Arrays.asList(rawType.getTypeParameters()).indexOf(tv);
if (argIndex > -1) {
Type typeArg = pt.getActualTypeArguments()[argIndex];
if (typeArg instanceof TypeVariable) {
tv = (TypeVariable) typeArg;
continue;
} else {
return typeArg;
}
}
}
break;
}
throw new IllegalArgumentException(currentType + " does not specify the type parameter T of GenericType<T>");
}
@Override
public boolean equals(Object obj) {
boolean result = this == obj;
if (!result && obj instanceof GenericType) {
GenericType<?> that = (GenericType<?>) obj;
return this.type.equals(that.type);
}
return result;
}
@Override
public int hashCode() {
return type.hashCode();
}
@Override
public String toString() {
return "GenericType{" + type.toString() + "}";
}
}