blob: 30983e38f08055154bdad78fc120b7077e943efa [file] [log] [blame]
/* *******************************************************************
* Copyright (c) 2005 Contributors.
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://eclipse.org/legal/epl-v10.html
* ******************************************************************/
package org.aspectj.weaver.reflect;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.weaver.BoundedReferenceType;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.TypeFactory;
import org.aspectj.weaver.TypeVariable;
import org.aspectj.weaver.TypeVariableReferenceType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
/**
* Handles the translation of java.lang.reflect.Type objects into AspectJ UnresolvedTypes.
*
* @author Adrian Colyer
*/
public class JavaLangTypeToResolvedTypeConverter {
// Used to prevent recursion - we record what we are working on and return it if asked again *whilst* working on it
private Map<Type, TypeVariableReferenceType> typeVariablesInProgress = new HashMap<Type, TypeVariableReferenceType>();
private final World world;
public JavaLangTypeToResolvedTypeConverter(World aWorld) {
this.world = aWorld;
}
private World getWorld() {
return this.world;
}
public ResolvedType fromType(Type type) {
if (type instanceof Class) {
Class clazz = (Class) type;
String name = clazz.getName();
/**
* getName() can return:
*
* 1. If this class object represents a reference type that is not an
* array type then the binary name of the class is returned
* 2. If this class object represents a primitive type or void, then
* the name returned is a String equal to the Java language keyword
* corresponding to the primitive type or void.
* 3. If this class object represents a class of arrays, then the internal
* form of the name consists of the name of the element type preceded by
* one or more '[' characters representing the depth of the array nesting.
*/
if (clazz.isArray()) {
UnresolvedType ut = UnresolvedType.forSignature(name.replace('.', '/'));
return getWorld().resolve(ut);
} else {
return getWorld().resolve(name);
}
} else if (type instanceof ParameterizedType) {
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=509327
// TODO should deal with the ownerType if it set, indicating this is possibly an inner type of a parameterized type
Type ownerType = ((ParameterizedType) type).getOwnerType();
ParameterizedType parameterizedType = (ParameterizedType) type;
ResolvedType baseType = fromType(parameterizedType.getRawType());
Type[] typeArguments = parameterizedType.getActualTypeArguments();
if (baseType.isSimpleType() && typeArguments.length == 0 && ownerType != null) {
// 'type' is an inner type of some outer parameterized type
// For now just return the base type - in future create the parameterized form of the outer
// and use it with the inner. We return the base type to be compatible with what the
// code does that accesses the info from the bytecode (unlike this code which accesses it
// reflectively).
return baseType;
}
ResolvedType[] resolvedTypeArguments = fromTypes(typeArguments);
return TypeFactory.createParameterizedType(baseType, resolvedTypeArguments, getWorld());
} else if (type instanceof java.lang.reflect.TypeVariable) {
TypeVariableReferenceType inprogressVar = typeVariablesInProgress.get(type);
if (inprogressVar != null) {
return inprogressVar;
}
java.lang.reflect.TypeVariable tv = (java.lang.reflect.TypeVariable) type;
TypeVariable rt_tv = new TypeVariable(tv.getName());
TypeVariableReferenceType tvrt = new TypeVariableReferenceType(rt_tv, getWorld());
typeVariablesInProgress.put(type, tvrt); // record what we are working on, for recursion case
Type[] bounds = tv.getBounds();
ResolvedType[] resBounds = fromTypes(bounds);
ResolvedType upperBound = resBounds[0];
ResolvedType[] additionalBounds = new ResolvedType[0];
if (resBounds.length > 1) {
additionalBounds = new ResolvedType[resBounds.length - 1];
System.arraycopy(resBounds, 1, additionalBounds, 0, additionalBounds.length);
}
rt_tv.setUpperBound(upperBound);
rt_tv.setAdditionalInterfaceBounds(additionalBounds);
typeVariablesInProgress.remove(type); // we have finished working on it
return tvrt;
} else if (type instanceof WildcardType) {
WildcardType wildType = (WildcardType) type;
Type[] lowerBounds = wildType.getLowerBounds();
Type[] upperBounds = wildType.getUpperBounds();
ResolvedType bound = null;
boolean isExtends = lowerBounds.length == 0;
if (isExtends) {
bound = fromType(upperBounds[0]);
} else {
bound = fromType(lowerBounds[0]);
}
return new BoundedReferenceType((ReferenceType) bound, isExtends, getWorld());
} else if (type instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) type;
Type componentType = genericArrayType.getGenericComponentType();
return UnresolvedType.makeArray(fromType(componentType), 1).resolve(getWorld());
}
return ResolvedType.MISSING;
}
public ResolvedType[] fromTypes(Type[] types) {
ResolvedType[] ret = new ResolvedType[types.length];
for (int i = 0; i < ret.length; i++) {
ret[i] = fromType(types[i]);
}
return ret;
}
}