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

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

/**
 * 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.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.List;

import org.evosuite.TestGenerationContext;
import org.evosuite.setup.TestClusterUtils;
import org.evosuite.setup.TestUsageChecker;
import org.evosuite.testcase.variable.VariableReference;

import com.googlecode.gentyref.GenericTypeReflector;
import org.evosuite.utils.LoggingUtils;

/**
 * @author Gordon Fraser
 *
 */
public class GenericConstructor extends GenericAccessibleObject {

	private static final long serialVersionUID = 1361882947700615341L;

	private transient Constructor constructor;

	public GenericConstructor(Constructor constructor, Class clazz) {
		super(new GenericClass(clazz));
		this.constructor = constructor;
	}

	public GenericConstructor(Constructor constructor, GenericClass owner) {
		super(new GenericClass(owner));
		this.constructor = constructor;
	}

	public GenericConstructor(Constructor constructor, Type type) {
		super(new GenericClass(type));
		this.constructor = constructor;
	}

	@Override
	public void changeClassLoader(ClassLoader loader) {
		super.changeClassLoader(loader);
		try {
			Class oldClass = constructor.getDeclaringClass();
			Class newClass = loader.loadClass(oldClass.getName());
			for (Constructor newConstructor : TestClusterUtils.getConstructors(newClass)) {
				boolean equals = true;
				Class[] oldParameters = this.constructor.getParameterTypes();
				Class[] newParameters = newConstructor.getParameterTypes();
				if (oldParameters.length != newParameters.length)
					continue;

				for (int i = 0; i < newParameters.length; i++) {
					if (!oldParameters[i].getName().equals(newParameters[i].getName())) {
						equals = false;
						break;
					}
				}
				if (equals) {
					this.constructor = newConstructor;
					this.constructor.setAccessible(true);
					break;
				}
			}
		} catch (ClassNotFoundException e) {
			LoggingUtils.getEvoLogger().info("Class not found - keeping old class loader ",
			                                 e);
		} catch (SecurityException e) {
			LoggingUtils.getEvoLogger().info("Class not found - keeping old class loader ",
			                                 e);
		}
	}

	@Override
	public GenericConstructor copy() {
		GenericConstructor copy = new GenericConstructor(constructor, new GenericClass(
		        owner));
		copyTypeVariables(copy);
		return copy;
	}

	@Override
	public GenericConstructor copyWithNewOwner(GenericClass newOwner) {
		GenericConstructor copy = new GenericConstructor(constructor, newOwner);
		copyTypeVariables(copy);
		return copy;
	}

	@Override
	public GenericConstructor copyWithOwnerFromReturnType(GenericClass returnType) {
		GenericConstructor copy = new GenericConstructor(constructor, returnType);
		copyTypeVariables(copy);
		return copy;
	}

	public Constructor getConstructor() {
		return constructor;
	}

	/* (non-Javadoc)
	 * @see org.evosuite.utils.GenericAccessibleObject#getAccessibleObject()
	 */
	@Override
	public AccessibleObject getAccessibleObject() {
		return constructor;
	}

	/* (non-Javadoc)
	 * @see org.evosuite.utils.GenericAccessibleObject#getDeclaringClass()
	 */
	@Override
	public Class getDeclaringClass() {
		return constructor.getDeclaringClass();
	}

	/**
	 * Returns the exact parameter types of the given method in the given type.
	 * This may be different from m.getGenericParameterTypes() when the
	 * method was declared in a superclass, or type has a type
	 * parameter that is used in one of the parameters, or type is a
	 * raw type.
	 */
	public Type[] getExactParameterTypes(Constructor m, Type type) {
		Type[] parameterTypes = m.getGenericParameterTypes();
		Type exactDeclaringType = GenericTypeReflector.getExactSuperType(GenericTypeReflector.capture(type),
		                                                                 m.getDeclaringClass());
		if (exactDeclaringType == null) { // capture(type) is not a subtype of m.getDeclaringClass()
			throw new IllegalArgumentException("The constructor " + m
			        + " is not a member of type " + type);
		}

		Type[] result = new Type[parameterTypes.length];
		for (int i = 0; i < parameterTypes.length; i++) {
			result[i] = mapTypeParameters(parameterTypes[i], exactDeclaringType);
		}
		return result;
	}

	public Type[] getGenericParameterTypes() {
		return constructor.getGenericParameterTypes();
	}

	@Override
	public Type getGeneratedType() {
		return getReturnType();
	}

	@Override
	public Class getRawGeneratedType() {
		return constructor.getDeclaringClass();
	}

	@Override
	public Type getGenericGeneratedType() {
		return getRawGeneratedType();
	}

	/* (non-Javadoc)
	 * @see org.evosuite.utils.GenericAccessibleObject#getName()
	 */
	@Override
	public String getName() {
		return constructor.getName();
	}

	public String getNameWithDescriptor() {
		return "" + org.objectweb.asm.Type.getConstructorDescriptor(constructor);
	}

	public String getDescriptor() {
		return org.objectweb.asm.Type.getConstructorDescriptor(constructor);
	}

	@Override
	public int getNumParameters() {
		return constructor.getGenericParameterTypes().length;
	}

	public Type[] getParameterTypes() {
		Type[] types = getExactParameterTypes(constructor, owner.getType());
		Type[] rawTypes = constructor.getParameterTypes();

		// Generic member classes should have the enclosing instance as a parameter
		// but don't for some reason
		if (rawTypes.length != types.length && owner.isParameterizedType()) {
			Type[] actualTypes = new Type[rawTypes.length];
			actualTypes[0] = owner.getOwnerType().getType();
			int pos = 1;
			for (Type parameterType : types) {
				actualTypes[pos++] = parameterType;
			}
			return actualTypes;
		}
		return types;
	}

	public Type[] getRawParameterTypes() {
		return constructor.getParameterTypes();
	}

	public Type getReturnType() {
		return owner.getType();
	}

	@Override
	public TypeVariable[] getTypeParameters() {
		return constructor.getTypeParameters();
	}

	@Override
	public boolean isAccessible() {
		return TestUsageChecker.canUse(constructor);
	}

	/* (non-Javadoc)
	 * @see org.evosuite.utils.GenericAccessibleObject#isConstructor()
	 */
	@Override
	public boolean isConstructor() {
		return true;
	}

	@Override
	public boolean isStatic() {
		return Modifier.isStatic(constructor.getModifiers());
	}

	public boolean isOverloaded(List parameters) {
		Class declaringClass = constructor.getDeclaringClass();
		Class[] parameterTypes = constructor.getParameterTypes();
		boolean isExact = true;
		Class[] parameterClasses = new Class[parameters.size()];
		int num = 0;
		for (VariableReference parameter : parameters) {
			parameterClasses[num] = parameter.getVariableClass();
			if (!parameterClasses[num].equals(parameterTypes[num])) {
				isExact = false;
				break;
			}
		}
		if (isExact)
			return false;
		try {
			for(java.lang.reflect.Constructor otherConstructor: declaringClass.getConstructors()) {
				if (otherConstructor.equals(constructor))
					continue;

				// If the number of parameters is different we can uniquely identify the constructor
				if(parameterTypes.length != otherConstructor.getParameterCount())
					continue;

				// Only if the parameters are assignable to both constructors do we need to care about overloading
				boolean parametersEqual = true;
				Class[] otherParameterTypes = otherConstructor.getParameterTypes();
				for(int i = 0; i < parameterClasses.length; i++) {
					if(parameters.get(i).isAssignableTo(parameterTypes[i]) !=
					   parameters.get(i).isAssignableTo(otherParameterTypes[i])) {
						parametersEqual = false;
						break;
					}
				}
				if(parametersEqual) {
					return true;
				}
			}
		} catch (SecurityException e) {
		}

		return false;
	}

	// assumes "static java.util.Date aDate;" declared
	private void readObject(ObjectInputStream ois) throws ClassNotFoundException,
	        IOException {
		ois.defaultReadObject();

		// Read/initialize additional fields
		Class constructorClass = TestGenerationContext.getInstance().getClassLoaderForSUT().loadClass((String) ois.readObject());
		String constructorDesc = (String) ois.readObject();
		for (Constructor constructor : constructorClass.getDeclaredConstructors()) {
			if (org.objectweb.asm.Type.getConstructorDescriptor(constructor).equals(constructorDesc)) {
				this.constructor = constructor;
				return;
			}
		}

		throw new IllegalStateException("Unknown constructor in class " + constructorClass.getCanonicalName());
	}

	/* (non-Javadoc)
	 * @see org.evosuite.utils.GenericAccessibleObject#toString()
	 */
	@Override
	public String toString() {
		return constructor.toGenericString();
	}

	private void writeObject(ObjectOutputStream oos) throws IOException {
		oos.defaultWriteObject();
		// Write/save additional fields
		oos.writeObject(constructor.getDeclaringClass().getName());
		oos.writeObject(org.objectweb.asm.Type.getConstructorDescriptor(constructor));
	}

	@Override
	public boolean isPublic() { return Modifier.isPublic(constructor.getModifiers()); }

	@Override
	public boolean isPrivate() { return Modifier.isPrivate(constructor.getModifiers()); }

	@Override
	public boolean isProtected() { return Modifier.isProtected(constructor.getModifiers()); }

	@Override
	public boolean isDefault() { return !isPublic() && !isPrivate() && !isProtected(); }

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((constructor == null) ? 0 : constructor.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		GenericConstructor other = (GenericConstructor) obj;
		if (constructor == null) {
			if (other.constructor != null)
				return false;
		} else if (!constructor.equals(other.constructor))
			return false;
		return true;
	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy