blob: 46996a5b45ee70fbf8f640d9fa3de9148db28e33 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.harmony.lang.reflect.support;
import java.lang.reflect.Type;
import java.lang.TypeNotPresentException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.WildcardType;
import java.lang.reflect.TypeVariable;
import org.apache.harmony.lang.reflect.parser.InterimParameterizedType;
import org.apache.harmony.lang.reflect.parser.InterimTypeVariable;
import org.apache.harmony.lang.reflect.parser.InterimGenericArrayType;
import org.apache.harmony.lang.reflect.support.AuxiliaryChecker;
import org.apache.harmony.lang.reflect.support.AuxiliaryFinder;
import org.apache.harmony.lang.reflect.repository.*;
import org.apache.harmony.lang.reflect.parser.*;
import org.apache.harmony.lang.reflect.implementation.*;
/**
* @author Serguei S. Zapreyev
*/
/**
* Finder provides kinds of finding.
*/
public final class AuxiliaryCreator {
/**
* This method creates generic array type.
*
* @param ppType a parsered information produced from a generic array type signature.
* @param startPoint an instance of the Class, Method, Constructor or Field type to start the search
* of a type variable declaration place.
* @return a Type object representing a generic array type.
*/
public static Type createGenericArrayType(InterimGenericArrayType ppType, Object startPoint) {
InterimType nextLayer = ppType.nextLayer;
if (nextLayer instanceof InterimParameterizedType) {
ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) nextLayer, startPoint);
if (pType == null) {
try {
AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) nextLayer, startPoint);
} catch(Throwable e) {
throw new TypeNotPresentException(((InterimParameterizedType) nextLayer).rawType.classTypeName.substring(1).replace('/', '.'), e);
}
// check the correspondence of the formal parameter number and the actual argument number:
AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) nextLayer, startPoint); //the MalformedParameterizedTypeException may raise here
try {
pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) nextLayer, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) nextLayer, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) nextLayer, startPoint));
} catch(ClassNotFoundException e) {
throw new TypeNotPresentException(e.getMessage(), e);
}
ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) nextLayer, ((InterimParameterizedType)nextLayer).signature, startPoint);
}
return new GenericArrayTypeImpl((Type) pType);
} else if (nextLayer instanceof InterimTypeVariable) {
String tvName = ((InterimTypeVariable) nextLayer).typeVariableName;
TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint);
if (variable == null) {
variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint);
if (variable == null) {
return (Type) null; // compatible behaviour
}
}
return new GenericArrayTypeImpl((Type) variable);
} else if (nextLayer instanceof InterimClassType) {
Type cType;
try {
cType = (Type) AuxiliaryLoader.findClass(((InterimClassType)nextLayer).classTypeName.substring((((InterimClassType)nextLayer).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.'), startPoint);
} catch(ClassNotFoundException e) {
throw new TypeNotPresentException(((InterimClassType)nextLayer).classTypeName.substring((((InterimClassType)nextLayer).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.'), e);
}
return new GenericArrayTypeImpl(cType);
} else { // GenericArrayType again
return new GenericArrayTypeImpl(AuxiliaryCreator.createGenericArrayType((InterimGenericArrayType)nextLayer, startPoint));
}
}
/**
* This method creates the owner's type for a parameterized type.
*
* @param ppType a parsered information produced from a parameterized type signature.
* @param startPoint an instance of the Class, Method, Constructor or Field type to start the search
* of a type variable declaration place.
* @return a created owner's type.
*/
public static Type createOwnerType(InterimParameterizedType ppType, Object startPoint) throws ClassNotFoundException {
// raise to owner level:
InterimType nextppType = ppType.ownerType; // XXX:???Can it be of InterimTypeVariable/InterimClassType type
if (nextppType == null) {
return null;
}
// create owner type
if (nextppType instanceof InterimParameterizedType) {
ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) nextppType, startPoint);
if (pType == null) {
try {
AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) nextppType, startPoint);
} catch(Throwable e) {
throw new TypeNotPresentException(((InterimParameterizedType) nextppType).rawType.classTypeName.substring(1).replace('/', '.'), e);
}
// check the correspondence of the formal parameter number and the actual argument number:
AuxiliaryChecker.checkArgsNumber((InterimParameterizedType)nextppType, startPoint); // the MalformedParameterizedTypeException may raise here
try {
pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) nextppType, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) nextppType, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) nextppType, startPoint));
} catch(ClassNotFoundException e) {
throw new TypeNotPresentException(e.getMessage(), e);
}
ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) nextppType, ((InterimParameterizedType)nextppType).signature, startPoint);
}
return (Type) pType;
} else { //ClassType
return AuxiliaryLoader.findClass(((InterimClassType) nextppType).classTypeName.substring(1).replace('/', '.'), startPoint); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one?
}
}
/**
* This method creates the raw type for a parameterized type.
*
* @param ppType a parsered information produced from a parameterized type signature.
* @param startPoint an instance of the Class, Method, Constructor or Field type to start the search
* of a type variable declaration place.
* @return a created raw type.
*/
public static Type createRawType(InterimParameterizedType ppType, Object startPoint) throws ClassNotFoundException {
return (Type) AuxiliaryFinder.findGenericClassDeclarationForParameterizedType(ppType, startPoint); // it may be null
}
/**
* This method creates Type object representing the actual type argument.
*
* @param pType a parsered information of actual parameter.
* @param startPoint an instance of the Class, Method, Constructor or Field type to start the search
* of a type variable declaration place.
* @return a Type object representing the actual type argument.
*/
public static Type createTypeArg(InterimType pType, Object startPoint) throws ClassNotFoundException {
Type res;
if (pType instanceof InterimParameterizedType) {
ParameterizedType cType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) pType, startPoint);
if (cType == null) {
try {
AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) pType, startPoint);
} catch(Throwable e) {
throw new TypeNotPresentException(((InterimParameterizedType) pType).rawType.classTypeName.substring(1).replace('/', '.'), e);
}
// check the correspondence of the formal parameter number and the actual argument number:
AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) pType, startPoint); // the MalformedParameterizedTypeException may raise here
cType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) pType, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) pType, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) pType, startPoint));
ParameterizedTypeRepository.registerParameterizedType(cType, (InterimParameterizedType) pType, ((InterimParameterizedType)pType).signature, startPoint);
}
res = (Type) cType;
} else if (pType instanceof InterimTypeVariable) {
String tvName = ((InterimTypeVariable) pType).typeVariableName;
TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint);
if (variable == null) {
variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint);
if (variable == null) {
return (Type) null;
}
}
res = (Type) variable;
} else if (pType instanceof InterimWildcardType) {
WildcardType wType = WildcardTypeRepository.findWildcardType((InterimWildcardType) pType, WildcardTypeRepository.recoverWildcardSignature((InterimWildcardType) pType), startPoint);
if (wType == null) {
// The MalformedParameterizedTypeException and TypeNotPresentException should not be raised yet.
// These ones can be produced only via WildcardType.getUpperBounds() or WildcardType.getLowerBounds.
wType = new WildcardTypeImpl((InterimWildcardType) pType, startPoint);
WildcardTypeRepository.registerWildcardType(wType, (InterimWildcardType) pType, WildcardTypeRepository.recoverWildcardSignature((InterimWildcardType) pType), startPoint);
}
res = (Type) wType;
} else if (pType instanceof InterimGenericArrayType) {
res = AuxiliaryCreator.createGenericArrayType((InterimGenericArrayType)pType, startPoint);
} else { // ClassType
String className = ((InterimClassType)
pType).classTypeName.substring(1).replace('/', '.');
res = (Type) AuxiliaryLoader.findClass(className, startPoint); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one?
}
return res;
}
/**
* This method creates an array of Type objects representing the actual type arguments to this type.
*
* @param ppType a parsered information produced from a parameterized type signature.
* @param startPoint an instance of the Class, Method, Constructor or Field type to start the search
* of a type variable declaration place.
* @return an array of Type objects representing the actual type arguments to this type.
*/
public static Type[] createTypeArgs(InterimParameterizedType ppType, Object startPoint) {
InterimType args[] = ppType.parameters;
if (args == null) {
return new Type[0];
}
int len = args.length;
Type res[] = new Type[len];
for (int i = 0; i < len; i++) {
try {
res[i] = createTypeArg(args[i], startPoint);
} catch(ClassNotFoundException e) {
throw new TypeNotPresentException(((InterimClassType)args[i]).classTypeName.substring(1).replace('/', '.'), e); // ClassNotFoundException may appear here only for InterimClassType, see AuxiliaryCreator.createTypeArg.
}
}
return res;
}
}