All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.evosuite.utils.generic.GenericUtils Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 *
 * This file is part of EvoSuite.
 *
 * EvoSuite is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3.0 of the License, or
 * (at your option) any later version.
 *
 * EvoSuite is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EvoSuite. If not, see .
 */
package org.evosuite.utils.generic;

import java.lang.annotation.Annotation;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.reflect.TypeUtils;
import org.evosuite.utils.ParameterizedTypeImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GenericUtils {

	/** Constant to represent @NotNull annotation */
	public final static String NONNULL = "Nonnull";

	public static boolean isAssignable(Type type, TypeVariable typeVariable) {
		boolean isAssignable = true;
		for (Type boundType : typeVariable.getBounds()) {
			// Have to resolve the type because a typevariable may have a reference to itself
			// in its bounds
			Type resolvedBoundType = GenericUtils.replaceTypeVariable(boundType,
			                                                          typeVariable, type);
			if (!GenericClass.isAssignable(resolvedBoundType, type)) {
				isAssignable = false;
				break;
			}
		}
		return isAssignable;
	}

	private static final Logger logger = LoggerFactory.getLogger(GenericUtils.class);

	public static Type replaceTypeVariables(Type targetType,
	        Map, Type> typeMap) {
		Type returnType = targetType;
		for(Entry, Type> entry : typeMap.entrySet()) {
			returnType = replaceTypeVariable(returnType, entry.getKey(), entry.getValue());
		}
//		for (TypeVariable var : typeMap.keySet()) {
//			//logger.debug("Current variable: "+var+" of type "+typeMap.get(var)+" in "+returnType);
//			returnType = replaceTypeVariable(returnType, var, typeMap.get(var));
//		}

		return returnType;
	}

	public static Type replaceTypeVariablesWithWildcards(Type targetType) {
		if (targetType instanceof TypeVariable) {
			TypeVariable typeVariable = (TypeVariable) targetType;
			return new WildcardTypeImpl(typeVariable.getBounds(), new Type[] {});
		} else if (targetType instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) targetType;
			Type owner = null;
			if (parameterizedType.getOwnerType() != null)
				owner = replaceTypeVariablesWithWildcards(parameterizedType.getOwnerType());
			Type[] currentParameters = parameterizedType.getActualTypeArguments();
			Type[] parameters = new Type[currentParameters.length];
			for (int i = 0; i < parameters.length; i++) {
				parameters[i] = replaceTypeVariablesWithWildcards(currentParameters[i]);
			}
			return new ParameterizedTypeImpl((Class) parameterizedType.getRawType(),
			        parameters, owner);
		}
		return targetType;
	}

	public static Type replaceTypeVariable(Type targetType, TypeVariable variable,
	        Type variableType) {
		if (targetType instanceof Class)
			return targetType;
		else if (targetType instanceof GenericArrayType) {
			GenericArrayType gType = (GenericArrayType) targetType;
			Type componentType = replaceTypeVariable(gType.getGenericComponentType(),
			                                         variable, variableType);
			return GenericArrayTypeImpl.createArrayType(componentType);

		} else if (targetType instanceof ParameterizedType) {
			ParameterizedType pType = (ParameterizedType) targetType;
			Type ownerType = null;
			if (pType.getOwnerType() != null) {
				ownerType = replaceTypeVariable(pType.getOwnerType(), variable,
				                                variableType);
			}
			Type[] originalParameterTypes = pType.getActualTypeArguments();
			Type[] parameterTypes = new Type[originalParameterTypes.length];
			for (int i = 0; i < originalParameterTypes.length; i++) {
				parameterTypes[i] = replaceTypeVariable(originalParameterTypes[i],
				                                        variable, variableType);
			}

			/*
			if (variableType instanceof ParameterizedType) {
				ParameterizedType parameterizedVars = (ParameterizedType) variableType;
				Map, Type> subTypes = TypeUtils.getTypeArguments(parameterizedVars);
				for (Entry, Type> subTypeEntry : subTypes.entrySet()) {
					if (pType.getOwnerType() != null) {
						ownerType = replaceTypeVariable(pType.getOwnerType(),
						                                subTypeEntry.getKey(),
						                                subTypeEntry.getValue());
					}
					for (int i = 0; i < originalParameterTypes.length; i++) {
						parameterTypes[i] = replaceTypeVariable(originalParameterTypes[i],
						                                        subTypeEntry.getKey(),
						                                        subTypeEntry.getValue());
					}

				}
			}
			*/

			return new ParameterizedTypeImpl((Class) pType.getRawType(),
			        parameterTypes, ownerType);

		} else if (targetType instanceof WildcardType) {
			WildcardType wType = (WildcardType) targetType;
			Type[] originalUpperBounds = wType.getUpperBounds();
			Type[] originalLowerBounds = wType.getLowerBounds();
			Type[] upperBounds = new Type[originalUpperBounds.length];
			Type[] lowerBounds = new Type[originalLowerBounds.length];

			for (int i = 0; i < originalUpperBounds.length; i++) {
				upperBounds[i] = replaceTypeVariable(originalUpperBounds[i], variable,
				                                     variableType);
			}
			for (int i = 0; i < originalLowerBounds.length; i++) {
				lowerBounds[i] = replaceTypeVariable(originalLowerBounds[i], variable,
				                                     variableType);
			}

			return new WildcardTypeImpl(upperBounds, lowerBounds);
		} else if (targetType instanceof TypeVariable) {
			if (targetType.equals(variable)) {
				//logger.debug("Do equal: " + variable + "/" + targetType);
				return variableType;
			} else {
				//logger.debug("Do not equal: " + variable + "/" + targetType);
				//logger.debug("Do not equal: " + variable.getGenericDeclaration() + "/"
				//        + ((TypeVariable) targetType).getGenericDeclaration());
				return targetType;
			}
		} else {
			//logger.debug("Unknown type of class " + targetType.getClass() + ": "
			//        + targetType);
			return targetType;
		}
	}

	public Map, Type> getMatchingTypeParameters(GenericArrayType p1,
	        GenericArrayType p2) {
		if (p1.getGenericComponentType() instanceof ParameterizedType
		        && p2.getGenericComponentType() instanceof ParameterizedType) {
			return getMatchingTypeParameters((ParameterizedType) p1.getGenericComponentType(),
			                                 (ParameterizedType) p2.getGenericComponentType());
		} else {
			Map, Type> map = new HashMap, Type>();
			return map;
		}
	}

	/**
	 * TODO: Try to match p2 superclasses? 
	 * 
	 * @param p1 Desired TypeVariable assignment
	 * @param p2 Generic type with the TypeVariables that need assignment
	 * @return
	 */
	public static Map, Type> getMatchingTypeParameters(
	        ParameterizedType p1, ParameterizedType p2) {
		logger.debug("Matching generic types between "+p1+" and "+p2);
		Map, Type> map = new HashMap, Type>();
		if (!p1.getRawType().equals(p2.getRawType())) {
			logger.debug("Raw types do not match!");
			
			GenericClass ownerClass = new GenericClass(p2);
			
			if(GenericClass.isSubclass(p1.getRawType(), p2.getRawType())) {
				logger.debug(p1 +" is a super type of "+p2);
				Map, Type> commonsMap = TypeUtils.determineTypeArguments((Class)p2.getRawType(), p1);
				logger.debug("Adding to map: "+commonsMap);
				// TODO: Now we would need to iterate over the type parameters, and update the map?
				//map.putAll(commonsMap);
				
				for(TypeVariable t : map.keySet()) {
					logger.debug(t+": "+t.getGenericDeclaration());
				}
				
				// For each type variable of the raw type, map the parameter type to that type
				Type[] p2TypesA = ((Class)p2.getRawType()).getTypeParameters();
				Type[] p2TypesB = p2.getActualTypeArguments();
				for(int i = 0 ; i < p2TypesA.length; i++) {
					Type a = p2TypesA[i];
					Type b = p2TypesB[i];
					logger.debug("Should be mapping "+a+" and "+b);
					if(a instanceof TypeVariable) {
						logger.debug(a+" is a type variable: "+((TypeVariable)a).getGenericDeclaration());
						if(b instanceof TypeVariable) {
							logger.debug(b+" is a type variable: "+((TypeVariable)b).getGenericDeclaration());
							if(commonsMap.containsKey((TypeVariable)a) && !(commonsMap.get((TypeVariable)a) instanceof WildcardType) && !(commonsMap.get((TypeVariable)a) instanceof TypeVariable))
								map.put((TypeVariable)b, commonsMap.get((TypeVariable)a));
							//else
							//	map.put((TypeVariable)a, b);
						}
					}
					
//					if(b instanceof TypeVariable) {
//						if(map.containsKey(a))
//							map.put((TypeVariable)b, map.get(a));
//						//else
//						//	map.put((TypeVariable)b, a);
//					}
				
					logger.debug("Updated map: "+map);
				}
				
			}

			
			for(GenericClass interfaceClass : ownerClass.getInterfaces()) {
				if(interfaceClass.isParameterizedType())
					map.putAll(getMatchingTypeParameters(p1, (ParameterizedType)interfaceClass.getType()));
				else
					logger.debug("Interface "+interfaceClass+" is not parameterized");
			}
			if(ownerClass.getRawClass().getSuperclass() != null) {
				GenericClass ownerSuperClass = ownerClass.getSuperClass();
				if(ownerSuperClass.isParameterizedType()) 
					map.putAll(getMatchingTypeParameters(p1, (ParameterizedType)ownerSuperClass.getType()));
				else
					logger.debug("Super type "+ownerSuperClass+" is not parameterized");
			}
			return map;
		}

		for (int i = 0; i < p1.getActualTypeArguments().length; i++) {
			Type t1 = p1.getActualTypeArguments()[i];
			Type t2 = p2.getActualTypeArguments()[i];
			if(t1 == t2)
				continue;
			logger.debug("First match: " + t1 + " - " + t2);
			if (t1 instanceof TypeVariable) {
				map.put((TypeVariable) t1, t2);
			}
			if (t2 instanceof TypeVariable) {
				map.put((TypeVariable) t2, t1);
			} else if (t2 instanceof ParameterizedType && t1 instanceof ParameterizedType) {
				map.putAll(getMatchingTypeParameters((ParameterizedType) t1,
				                                     (ParameterizedType) t2));
			}
			logger.debug("Updated map: "+map);

		}

		if (p1.getOwnerType() != null && p1.getOwnerType() instanceof ParameterizedType
		        && p2.getOwnerType() instanceof ParameterizedType) {
			map.putAll(getMatchingTypeParameters((ParameterizedType) p1.getOwnerType(),
			                                     (ParameterizedType) p2.getOwnerType()));
		}

		return map;
	}

	/**
	 * Returns true if the annotation is present in the annotationList, false otherwise.
	 * 
	 * @param annotationList
	 * @param annotationTypeName
	 * @return boolean
	 */
	public static boolean isAnnotationTypePresent(Annotation[] annotationList, String annotationTypeName) {
		for (Annotation annotation : annotationList) {

			if ((null != annotationTypeName)
					&& annotationTypeName.equalsIgnoreCase(annotation.annotationType().getSimpleName())) {
				return true;
			}
		}
		return false;
	}


	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy