/*
* JBoss, Home of Professional Open Source
* Copyright 2012, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.
*/
package org.jboss.weld.util.reflection;
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.Map;
public class TypeResolver {
private final Map<TypeVariable<?>, Type> resolvedTypeVariables;
public TypeResolver(Map<TypeVariable<?>, Type> resolvedTypeVariables) {
this.resolvedTypeVariables = resolvedTypeVariables;
}
/**
* Resolves a given type variable. This is achieved by a lookup in the {@link #resolvedTypeVariables} map.
*/
public Type resolveType(TypeVariable<?> variable) {
Type resolvedType = this.resolvedTypeVariables.get(variable);
if (resolvedType == null) {
return variable; // we are not able to resolve
}
return resolvedType;
}
/**
* Resolves a given parameterized type. If the parameterized type contains no type variables it is returned untouched.
* Otherwise, a new {@link ParameterizedType} instance is returned in which each type variable is resolved using
* {@link #resolveType(TypeVariable)}.
*/
public Type resolveType(ParameterizedType type) {
Type[] unresolvedTypeArguments = type.getActualTypeArguments();
/*
* Indicates whether we managed to resolve any of type arguments. If we did not then there is no need to create a new
* ParameterizedType with the old parameters. Instead, we return the original type.
*/
boolean modified = false;
Type[] resolvedTypeArguments = new Type[unresolvedTypeArguments.length];
for (int i = 0; i < unresolvedTypeArguments.length; i++) {
Type resolvedType = unresolvedTypeArguments[i];
if (resolvedType instanceof TypeVariable<?>) {
resolvedType = resolveType((TypeVariable<?>) resolvedType);
}
if (resolvedType instanceof ParameterizedType) {
resolvedType = resolveType((ParameterizedType) resolvedType);
}
resolvedTypeArguments[i] = resolvedType;
// This identity check is intentional. A different identity indicates that the type argument was resolved within #resolveType().
if (unresolvedTypeArguments[i] != resolvedType) {
modified = true;
}
}
if (modified) {
return new ParameterizedTypeImpl(type.getRawType(), resolvedTypeArguments, type.getOwnerType());
} else {
return type;
}
}
public Type resolveType(GenericArrayType type) {
Type genericComponentType = type.getGenericComponentType();
// try to resolve the type
Type resolvedType = genericComponentType;
if (genericComponentType instanceof TypeVariable<?>) {
resolvedType = resolveType((TypeVariable<?>) genericComponentType);
}
if (genericComponentType instanceof ParameterizedType) {
resolvedType = resolveType((ParameterizedType) genericComponentType);
}
if (genericComponentType instanceof GenericArrayType) {
resolvedType = resolveType((GenericArrayType) genericComponentType);
}
/*
* If the generic component type resolved to a class (e.g. String) we return [Ljava.lang.String; (the class representing the
* array) instead of GenericArrayType with String as its generic component type.
*/
if (resolvedType instanceof Class<?>) {
Class<?> componentClass = (Class<?>) resolvedType;
return Array.newInstance(componentClass, 0).getClass();
}
/*
* This identity check is intentional. If the identity is different it indicates that we succeeded in resolving the type
* and a new GenericArrayType with resolved generic component type is returned. Otherwise, we were not able to resolve
* the type and therefore we do not create a new GenericArrayType.
*/
if (resolvedType == genericComponentType) {
return type;
} else {
return new GenericArrayTypeImpl(resolvedType);
}
}
public Type resolveType(Type type) {
if (type instanceof ParameterizedType) {
return resolveType((ParameterizedType) type);
}
if (type instanceof TypeVariable<?>) {
return resolveType((TypeVariable<?>) type);
}
if (type instanceof GenericArrayType) {
return resolveType((GenericArrayType) type);
}
return type;
}
public Map<TypeVariable<?>, Type> getResolvedTypeVariables() {
return resolvedTypeVariables;
}
}