/** * Copyright (C) 2010-2017 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 <http://www.gnu.org/licenses/>. */ package org.evosuite.stubs; import java.io.InputStream; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import org.evosuite.PackageInfo; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.util.TraceClassVisitor; public class TestStubbingClassLoader extends ClassLoader { private final ClassLoader classLoader; private final Map<String, Class<?>> classes = new HashMap<String, Class<?>>(); public TestStubbingClassLoader() { classLoader = TestStubbingClassLoader.class.getClassLoader(); } public static String[] getPackagesShouldNotBeInstrumented() { //explicitly blocking client projects such as specmate is only a //temporary solution, TODO allow the user to specify //packages that should not be instrumented return new String[] { "java.", "javax.", "sun.", PackageInfo.getEvoSuitePackage(), "org.exsyst", "de.unisb.cs.st.testcarver", "de.unisb.cs.st.evosuite", "org.uispec4j", "de.unisb.cs.st.specmate", "org.xml", "org.w3c", "testing.generation.evosuite", "com.yourkit", "com.vladium.emma.", "daikon.", // Need to have these in here to avoid trouble with UnsatisfiedLinkErrors on Mac OS X and Java/Swing apps "apple.", "com.apple.", "com.sun", "org.junit", "junit.framework", "org.apache.xerces.dom3", "de.unisl.cs.st.bugex", "corina.cross.Single" // I really don't know what is wrong with this class, but we need to exclude it }; } public static boolean checkIfCanInstrument(String className) { for (String s : getPackagesShouldNotBeInstrumented()) { if (className.startsWith(s)) { return false; } } return true; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { if (!checkIfCanInstrument(name)) { Class<?> result = findLoadedClass(name); if (result != null) { return result; } result = classLoader.loadClass(name); return result; } else { Class<?> result = findLoadedClass(name); if (result != null) { return result; } else { result = classes.get(name); if (result != null) { return result; } else { Class<?> instrumentedClass = instrumentClass(name); return instrumentedClass; } } } } private Class<?> instrumentClass(String fullyQualifiedTargetClass) throws ClassNotFoundException { try { String className = fullyQualifiedTargetClass.replace('.', '/'); InputStream is = ClassLoader.getSystemResourceAsStream(className + ".class"); if (is == null) { throw new ClassNotFoundException("Class '" + className + ".class" + "' should be in target project, but could not be found!"); } ClassReader reader = new ClassReader(is); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES); TraceClassVisitor tc = new TraceClassVisitor(writer, new PrintWriter(System.err)); // CheckClassAdapter ca = new CheckClassAdapter(tc); StubClassVisitor visitor = new StubClassVisitor(tc, fullyQualifiedTargetClass); reader.accept(visitor, ClassReader.SKIP_FRAMES); byte[] byteBuffer = writer.toByteArray(); Class<?> result = defineClass(fullyQualifiedTargetClass, byteBuffer, 0, byteBuffer.length); classes.put(fullyQualifiedTargetClass, result); return result; } catch (Throwable t) { throw new ClassNotFoundException(t.getMessage(), t); } } }