diff --git a/src/main/java/spoon/SpoonException.java b/src/main/java/spoon/SpoonException.java
index 5089cf25fab..d4ee81ba30e 100644
--- a/src/main/java/spoon/SpoonException.java
+++ b/src/main/java/spoon/SpoonException.java
@@ -28,7 +28,7 @@ public SpoonException(String msg) {
 	public SpoonException(Throwable e) {
 		super(e);
 	}
-	public SpoonException(String msg, Exception e) {
+	public SpoonException(String msg, Throwable e) {
 		super(msg, e);
 	}
 }
diff --git a/src/main/java/spoon/SpoonTask.java b/src/main/java/spoon/SpoonTask.java
index 4053bc71b19..f22049c8c5b 100644
--- a/src/main/java/spoon/SpoonTask.java
+++ b/src/main/java/spoon/SpoonTask.java
@@ -16,17 +16,17 @@
  */
 package spoon;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Vector;
-
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.taskdefs.Java;
 import org.apache.tools.ant.types.FileSet;
 import org.apache.tools.ant.types.Path;
 import org.apache.tools.ant.types.Reference;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
 /**
  * This class implements an Ant task for Spoon that encapsulates
  * {@link spoon.Launcher}.
diff --git a/src/main/java/spoon/compiler/Environment.java b/src/main/java/spoon/compiler/Environment.java
index 845d895761c..aeda0594bb8 100644
--- a/src/main/java/spoon/compiler/Environment.java
+++ b/src/main/java/spoon/compiler/Environment.java
@@ -1,4 +1,4 @@
-/** 
+/**
  * Copyright (C) 2006-2016 INRIA and contributors
  * Spoon - http://spoon.gforge.inria.fr/
  *
@@ -210,12 +210,15 @@ void report(Processor<?> processor, Level level,
 	int getWarningCount();
 
 	/**
-	 * Gets the class loader used to compile/process the input source code.
+	 * Returns the {@code ClassLoader} which is used by JDT and to resolve classes from references.
+	 *
+	 * By default, returns a class loader able to load classes from the
+	 * Spoon-specific class path set with  {@link #setSourceClasspath(String[])}
 	 */
 	ClassLoader getInputClassLoader();
 
 	/**
-	 * Sets the class loader used to compile/process the input source code.
+	 * Sets a specific classloader for JDT and reference resolution
 	 */
 	void setInputClassLoader(ClassLoader classLoader);
 
@@ -246,9 +249,9 @@ void report(Processor<?> processor, Level level,
 	void setSourceClasspath(String[] sourceClasspath);
 
 	/**
-	 * Returns a {@code ClassLoader} which is able to load classes from the
-	 * class path returned by {@link #getSourceClasspath()}
+	 * Use {@link #getInputClassLoader()}
 	 */
+	@Deprecated
 	ClassLoader getClassLoader();
 
 	/**
diff --git a/src/main/java/spoon/compiler/builder/ClasspathOptions.java b/src/main/java/spoon/compiler/builder/ClasspathOptions.java
index 0df03ffce2b..31e8fcf36b0 100644
--- a/src/main/java/spoon/compiler/builder/ClasspathOptions.java
+++ b/src/main/java/spoon/compiler/builder/ClasspathOptions.java
@@ -17,8 +17,6 @@
 package spoon.compiler.builder;
 
 import java.io.File;
-import java.net.URL;
-import java.net.URLClassLoader;
 
 public class ClasspathOptions<T extends ClasspathOptions<T>> extends Options<T> {
 	public ClasspathOptions() {
@@ -41,25 +39,6 @@ public T classpath(String... classpaths) {
 		return classpath(join(File.pathSeparator, classpaths));
 	}
 
-	public T classpathFromListOrClassLoader(String... classpaths) {
-		return (classpaths != null && classpaths.length > 0) ? classpath(classpaths) : classpathFromCurrentClassLoader();
-	}
-
-	public T classpathFromCurrentClassLoader() {
-		ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
-		if (currentClassLoader instanceof URLClassLoader) {
-			final URL[] urls = ((URLClassLoader) currentClassLoader).getURLs();
-			if (urls != null && urls.length > 0) {
-				String classpath = ".";
-				for (URL url : urls) {
-					classpath += File.pathSeparator + url.getFile();
-				}
-				classpath(classpath);
-			}
-		}
-		return myself;
-	}
-
 	public T bootclasspath(String bootclasspath) {
 		if (bootclasspath == null) {
 			return myself;
diff --git a/src/main/java/spoon/support/StandardEnvironment.java b/src/main/java/spoon/support/StandardEnvironment.java
index 43df2742b32..65d02627788 100644
--- a/src/main/java/spoon/support/StandardEnvironment.java
+++ b/src/main/java/spoon/support/StandardEnvironment.java
@@ -16,23 +16,9 @@
  */
 package spoon.support;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
 import org.xml.sax.SAXException;
-
 import spoon.Launcher;
 import spoon.SpoonException;
 import spoon.compiler.Environment;
@@ -53,6 +39,20 @@
 import spoon.support.compiler.FileSystemFolder;
 import spoon.support.processing.XmlProcessorProperties;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
 /**
  * This class implements a simple Spoon environment that reports messages in the
  * standard output stream (Java-compliant).
@@ -84,8 +84,6 @@ public class StandardEnvironment implements Serializable, Environment {
 
 	private String[] sourceClasspath = null;
 
-	private URLClassLoader classLoader = null;
-
 	private boolean preserveLineNumbers = false;
 
 	private boolean copyResources = true;
@@ -383,12 +381,35 @@ public void setTabulationSize(int tabulationSize) {
 		this.tabulationSize = tabulationSize;
 	}
 
+	private ClassLoader classloader;
+
 	@Override
-	public ClassLoader getClassLoader() {
-		if (classLoader == null) {
-			classLoader = new URLClassLoader(urlClasspath(), Thread.currentThread().getContextClassLoader());
+	public void setInputClassLoader(ClassLoader aClassLoader) {
+		if (aClassLoader instanceof URLClassLoader) {
+			final URL[] urls = ((URLClassLoader) aClassLoader).getURLs();
+			if (urls != null && urls.length > 0) {
+				List<String> classpath = new ArrayList<>();
+				for (URL url : urls) {
+					classpath.add(url.toString());
+				}
+				setSourceClasspath(classpath.toArray(new String[0]));
+			}
+			return;
 		}
-		return classLoader;
+		this.classloader = aClassLoader;
+	}
+
+	@Override
+	public ClassLoader getInputClassLoader() {
+		if (classloader != null) {
+			return classloader;
+		}
+		return new URLClassLoader(urlClasspath(), Thread.currentThread().getContextClassLoader());
+	}
+
+	@Override
+	public ClassLoader getClassLoader() {
+		return getInputClassLoader();
 	}
 
 	/**
@@ -417,7 +438,6 @@ public String[] getSourceClasspath() {
 	public void setSourceClasspath(String[] sourceClasspath) {
 		verifySourceClasspath(sourceClasspath);
 		this.sourceClasspath = sourceClasspath;
-		this.classLoader = null;
 	}
 
 	private void verifySourceClasspath(String[] sourceClasspath) throws InvalidClassPathException {
@@ -449,22 +469,6 @@ public int getWarningCount() {
 		return warningCount;
 	}
 
-	private ClassLoader inputClassLoader;
-
-	@Override
-	public ClassLoader getInputClassLoader() {
-		if (inputClassLoader == null) {
-			return Thread.currentThread().getContextClassLoader();
-		} else {
-			return this.inputClassLoader;
-		}
-	}
-
-	@Override
-	public void setInputClassLoader(ClassLoader classLoader) {
-		this.inputClassLoader = classLoader;
-	}
-
 	@Override
 	public boolean isPreserveLineNumbers() {
 		return preserveLineNumbers;
diff --git a/src/main/java/spoon/support/compiler/jdt/CompilerClassLoader.java b/src/main/java/spoon/support/compiler/jdt/CompilerClassLoader.java
deleted file mode 100644
index 484b5c721df..00000000000
--- a/src/main/java/spoon/support/compiler/jdt/CompilerClassLoader.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright (C) 2006-2016 INRIA and contributors
- * Spoon - http://spoon.gforge.inria.fr/
- *
- * This software is governed by the CeCILL-C License under French law and
- * abiding by the rules of distribution of free software. You can use, modify
- * and/or redistribute the software under the terms of the CeCILL-C license as
- * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
- *
- * This program 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 CeCILL-C License for more details.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL-C license and that you accept its terms.
- */
-package spoon.support.compiler.jdt;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-
-public class CompilerClassLoader extends URLClassLoader {
-	public CompilerClassLoader(URL[] urls, ClassLoader parent) {
-		super(urls, parent);
-	}
-}
diff --git a/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java b/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java
index 71dac31af2e..cb070f6e09d 100644
--- a/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java
+++ b/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java
@@ -46,9 +46,9 @@
 import spoon.reflect.declaration.CtPackage;
 import spoon.reflect.declaration.CtType;
 import spoon.reflect.factory.Factory;
+import spoon.reflect.visitor.AstParentConsistencyChecker;
 import spoon.reflect.visitor.DefaultJavaPrettyPrinter;
 import spoon.reflect.visitor.Filter;
-import spoon.reflect.visitor.AstParentConsistencyChecker;
 import spoon.reflect.visitor.PrettyPrinter;
 import spoon.reflect.visitor.Query;
 import spoon.support.QueueProcessingManager;
@@ -59,7 +59,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -134,7 +133,6 @@ private void checkModel() {
 
 	@Override
 	public boolean compile(InputType... types) {
-		initInputClassLoader();
 		factory.getEnvironment().debugMessage("compiling sources: " + factory.CompilationUnit().getMap().keySet());
 		long t = System.currentTimeMillis();
 		javaCompliance = factory.getEnvironment().getComplianceLevel();
@@ -143,7 +141,7 @@ public boolean compile(InputType... types) {
 
 
 		final String[] args = new JDTBuilderImpl() //
-				.classpathOptions(new ClasspathOptions().encoding(this.encoding).classpathFromListOrClassLoader(getSourceClasspath()).binaries(getBinaryOutputDirectory())) //
+				.classpathOptions(new ClasspathOptions().encoding(this.encoding).classpath(getSourceClasspath()).binaries(getBinaryOutputDirectory())) //
 				.complianceOptions(new ComplianceOptions().compliance(javaCompliance)) //
 				.annotationProcessingOptions(new AnnotationProcessingOptions().compileProcessors()) //
 				.advancedOptions(new AdvancedOptions().preserveUnusedVars().continueExecution().enableJavadoc()) //
@@ -161,8 +159,6 @@ public boolean compile(InputType... types) {
 
 	@Override
 	public void instantiateAndProcess(List<String> processors) {
-		initInputClassLoader();
-
 		// processing (consume all the processors)
 		ProcessingManager processing = new QueueProcessingManager(factory);
 		for (String processorName : processors) {
@@ -175,8 +171,6 @@ public void instantiateAndProcess(List<String> processors) {
 
 	@Override
 	public void process(Collection<Processor<? extends CtElement>> processors) {
-		initInputClassLoader();
-
 		// processing (consume all the processors)
 		ProcessingManager processing = new QueueProcessingManager(factory);
 		for (Processor<? extends CtElement> processorName : processors) {
@@ -194,7 +188,6 @@ public void generateProcessedSourceFiles(OutputType outputType) {
 
 	@Override
 	public void generateProcessedSourceFiles(OutputType outputType, Filter<CtType<?>> typeFilter) {
-		initInputClassLoader();
 		switch (outputType) {
 		case CLASSES:
 			generateProcessedSourceFilesUsingTypes(typeFilter);
@@ -351,12 +344,11 @@ protected boolean buildSources(JDTBuilder jdtBuilder) {
 		if (sources.getAllJavaFiles().isEmpty()) {
 			return true;
 		}
-		initInputClassLoader();
 		JDTBatchCompiler batchCompiler = createBatchCompiler(InputType.FILES);
 		String[] args;
 		if (jdtBuilder == null) {
 			args = new JDTBuilderImpl() //
-					.classpathOptions(new ClasspathOptions().encoding(this.encoding).classpathFromListOrClassLoader(getSourceClasspath())) //
+					.classpathOptions(new ClasspathOptions().encoding(this.encoding).classpath(getSourceClasspath())) //
 					.complianceOptions(new ComplianceOptions().compliance(javaCompliance)) //
 					.advancedOptions(new AdvancedOptions().preserveUnusedVars().continueExecution().enableJavadoc()) //
 					.sources(new SourceOptions().sources(sources.getAllJavaFiles())) //
@@ -653,47 +645,6 @@ protected InputStream getCompilationUnitInputStream(String path) {
 		return new ByteArrayInputStream(printer.getResult().toString().getBytes());
 	}
 
-	private CompilerClassLoader getCompilerClassLoader(ClassLoader initialClassLoader) {
-		while (initialClassLoader != null) {
-			if (initialClassLoader instanceof CompilerClassLoader) {
-				return (CompilerClassLoader) initialClassLoader;
-			}
-			initialClassLoader = initialClassLoader.getParent();
-		}
-		return null;
-	}
-
-	private boolean hasClassLoader(ClassLoader initialClassLoader, ClassLoader classLoader) {
-		while (initialClassLoader != null) {
-			if (initialClassLoader == classLoader) {
-				return true;
-			}
-			initialClassLoader = initialClassLoader.getParent();
-		}
-		return false;
-	}
-
-	protected void initInputClassLoader() {
-		ClassLoader cl = Thread.currentThread().getContextClassLoader();
-		if (buildOnlyOutdatedFiles && getBinaryOutputDirectory() != null) {
-			CompilerClassLoader ccl = getCompilerClassLoader(cl);
-			if (ccl == null) {
-				try {
-					Launcher.LOGGER.debug("setting classloader for " + getBinaryOutputDirectory().toURI().toURL());
-					Thread.currentThread().setContextClassLoader(new CompilerClassLoader(new URL[] {
-									getBinaryOutputDirectory().toURI().toURL()
-							}, factory.getEnvironment().getInputClassLoader()));
-				} catch (Exception e) {
-					Launcher.LOGGER.error(e.getMessage(), e);
-				}
-			}
-		} else {
-			if (!hasClassLoader(Thread.currentThread().getContextClassLoader(), factory.getEnvironment().getInputClassLoader())) {
-				Thread.currentThread().setContextClassLoader(factory.getEnvironment().getInputClassLoader());
-			}
-		}
-	}
-
 	protected Environment getEnvironment() {
 		return getFactory().getEnvironment();
 	}
diff --git a/src/main/java/spoon/support/compiler/jdt/JDTSnippetCompiler.java b/src/main/java/spoon/support/compiler/jdt/JDTSnippetCompiler.java
index 8e96c3c34af..df3b154c742 100644
--- a/src/main/java/spoon/support/compiler/jdt/JDTSnippetCompiler.java
+++ b/src/main/java/spoon/support/compiler/jdt/JDTSnippetCompiler.java
@@ -16,12 +16,8 @@
  */
 package spoon.support.compiler.jdt;
 
-import java.io.File;
-import java.util.Arrays;
-
 import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-
 import spoon.SpoonException;
 import spoon.compiler.Environment;
 import spoon.compiler.builder.AdvancedOptions;
@@ -34,6 +30,9 @@
 import spoon.support.compiler.SnippetCompilationError;
 import spoon.support.compiler.VirtualFile;
 
+import java.io.File;
+import java.util.Arrays;
+
 public class JDTSnippetCompiler extends JDTBasedSpoonCompiler {
 
 	public JDTSnippetCompiler(Factory factory, String contents) {
@@ -74,7 +73,7 @@ protected boolean buildSources(JDTBuilder jdtBuilder) {
 		if (jdtBuilder == null) {
 			String[] sourceClasspath = getSourceClasspath();
 			args = new JDTBuilderImpl() //
-					.classpathOptions(new ClasspathOptions().encoding(this.encoding).classpathFromListOrClassLoader(sourceClasspath)) //
+					.classpathOptions(new ClasspathOptions().encoding(this.encoding).classpath(sourceClasspath)) //
 					.complianceOptions(new ComplianceOptions().compliance(javaCompliance)) //
 					.advancedOptions(new AdvancedOptions().preserveUnusedVars().continueExecution().enableJavadoc()) //
 					.sources(new SourceOptions().sources(source.getPath())) //
diff --git a/src/main/java/spoon/support/reflect/reference/CtTypeReferenceImpl.java b/src/main/java/spoon/support/reflect/reference/CtTypeReferenceImpl.java
index 5f5500251fc..eee91dc1e81 100644
--- a/src/main/java/spoon/support/reflect/reference/CtTypeReferenceImpl.java
+++ b/src/main/java/spoon/support/reflect/reference/CtTypeReferenceImpl.java
@@ -16,20 +16,6 @@
  */
 package spoon.support.reflect.reference;
 
-import static spoon.reflect.ModelElementContainerDefaultCapacities.TYPE_TYPE_PARAMETERS_CONTAINER_DEFAULT_CAPACITY;
-
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 import spoon.Launcher;
 import spoon.reflect.declaration.CtClass;
 import spoon.reflect.declaration.CtPackage;
@@ -49,6 +35,20 @@
 import spoon.support.util.QualifiedNameBasedSortedSet;
 import spoon.support.util.RtHelper;
 
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static spoon.reflect.ModelElementContainerDefaultCapacities.TYPE_TYPE_PARAMETERS_CONTAINER_DEFAULT_CAPACITY;
+
 public class CtTypeReferenceImpl<T> extends CtReferenceImpl implements CtTypeReference<T> {
 	private static final long serialVersionUID = 1L;
 
@@ -131,16 +131,26 @@ public Class<T> getActualClass() {
 	}
 
 	/**
-	 * Finds the class requested in {@link #getActualClass()}, using the
-	 * {@code ClassLoader} of the {@code Environment}
+	 * Finds the class requested in {@link #getActualClass()}.
+	 *
+	 * Looks for the class in the standard Java classpath, but also in the sourceClassPath given as option.
 	 */
 	@SuppressWarnings("unchecked")
 	protected Class<T> findClass() {
+		// first try the simple way
+		try {
+			return (Class<T>) Class.forName(getQualifiedName());
+		} catch (Throwable ignore) {
+		}
+
+		// then we also look into the sourceclasspth entries given
 		try {
+			// creating a classloader on the fly is not the most efficient
+			// but it decreases the amount of state to maintain
+			// since getActualClass is only used in rare cases, that's OK.
 			return (Class<T>) getFactory().getEnvironment().getClassLoader().loadClass(getQualifiedName());
-		} catch (java.lang.ClassNotFoundException cnfe) {
-			throw new SpoonClassNotFoundException("cannot load class: " + getQualifiedName() + " with class loader "
-					+ Thread.currentThread().getContextClassLoader(), cnfe);
+		} catch (Throwable e) {
+			throw new SpoonClassNotFoundException("cannot load class: " + getQualifiedName(), e);
 		}
 	}
 
diff --git a/src/main/java/spoon/support/reflect/reference/SpoonClassNotFoundException.java b/src/main/java/spoon/support/reflect/reference/SpoonClassNotFoundException.java
index 9c7f2d6377a..19bf58cbf7b 100644
--- a/src/main/java/spoon/support/reflect/reference/SpoonClassNotFoundException.java
+++ b/src/main/java/spoon/support/reflect/reference/SpoonClassNotFoundException.java
@@ -18,9 +18,11 @@
 
 import spoon.SpoonException;
 
-/** Spoon-specific ClassNotFoundException (simply encapsulates a ClassNotFoundException as a runtime exception) */
+/** Spoon-specific ClassNotFoundException (mostly encapsulates a ClassNotFoundException or a NoClassDefFoundError
+ * as a runtime exception)
+ */
 public class SpoonClassNotFoundException extends SpoonException {
-	public SpoonClassNotFoundException(String msg, java.lang.ClassNotFoundException cnfe) {
+	public SpoonClassNotFoundException(String msg, Throwable cnfe) {
 		super(msg, cnfe);
 	}
 
diff --git a/src/test/java/spoon/test/compilation/CompilationTest.java b/src/test/java/spoon/test/compilation/CompilationTest.java
index bb4b9993a05..9f8f2fcd0b4 100644
--- a/src/test/java/spoon/test/compilation/CompilationTest.java
+++ b/src/test/java/spoon/test/compilation/CompilationTest.java
@@ -1,19 +1,8 @@
 package spoon.test.compilation;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.List;
-
 import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
 import org.junit.Assert;
 import org.junit.Test;
-
 import spoon.Launcher;
 import spoon.compiler.SpoonCompiler;
 import spoon.reflect.code.BinaryOperatorKind;
@@ -27,9 +16,23 @@
 import spoon.reflect.factory.CodeFactory;
 import spoon.reflect.factory.CoreFactory;
 import spoon.reflect.factory.Factory;
+import spoon.reflect.reference.CtTypeReference;
+import spoon.reflect.visitor.CtScanner;
 import spoon.reflect.visitor.filter.TypeFilter;
 import spoon.support.compiler.jdt.FileCompiler;
 import spoon.support.compiler.jdt.JDTBasedSpoonCompiler;
+import spoon.support.reflect.reference.SpoonClassNotFoundException;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 public class CompilationTest {
 
@@ -45,7 +48,7 @@ public void compileCommandLineTest() throws Exception {
 
 		Launcher launcher = new Launcher();
 
-		launcher.run(new String[] {
+		launcher.run(new String[]{
 				"-i", sourceFile,
 				"-o", "target/spooned",
 				"--compile",
@@ -86,9 +89,9 @@ public void compileTest() throws Exception {
 		CtReturn aReturn = core.createReturn();
 
 		CtBinaryOperator binaryOperator = code.createBinaryOperator(
-						code.createLiteral(10),
-						code.createLiteral(32),
-						BinaryOperatorKind.PLUS);
+				code.createLiteral(10),
+				code.createLiteral(32),
+				BinaryOperatorKind.PLUS);
 		aReturn.setReturnedExpression(binaryOperator);
 
 		// return 10 + 32;
@@ -99,7 +102,7 @@ public void compileTest() throws Exception {
 
 		launcher.getModelBuilder().compile();
 
-		final URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { outputBinDirectory.toURL() });
+		final URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{outputBinDirectory.toURL()});
 
 		Class<?> aClass = urlClassLoader.loadClass("Simple");
 		Method m = aClass.getMethod("m");
@@ -111,14 +114,14 @@ public void testNewInstance() throws Exception {
 		// contract: a ctclass can be instantiated, and each modification results in a new valid object
 		Factory factory = new Launcher().getFactory();
 		CtClass<Ifoo> c = factory.Code().createCodeSnippetStatement(
-							"class X implements spoon.test.compilation.Ifoo { public int foo() {int i=0; return i;} }").compile();
+				"class X implements spoon.test.compilation.Ifoo { public int foo() {int i=0; return i;} }").compile();
 		c.addModifier(ModifierKind.PUBLIC); // required otherwise java.lang.IllegalAccessException at runtime when instantiating
 
 		CtBlock body = c.getElements(new TypeFilter<>(CtBlock.class)).get(1);
 		Ifoo o = c.newInstance();
 		assertEquals(0, o.foo());
-		for (int i=1; i<=10; i++) {
-			body.getStatement(0).replace(factory.Code().createCodeSnippetStatement("int i = "+i+";"));
+		for (int i = 1; i <= 10; i++) {
+			body.getStatement(0).replace(factory.Code().createCodeSnippetStatement("int i = " + i + ";"));
 			o = c.newInstance();
 			// each time this is a new class
 			// each time the behavior has changed!
@@ -157,7 +160,7 @@ public CompilationUnit[] getCompilationUnits() {
 		launcher.buildModel();
 
 		// we indeed only have types declared in a file called *Foo*
-		for(CtType<?> t : launcher.getFactory().getModel().getAllTypes()) {
+		for (CtType<?> t : launcher.getFactory().getModel().getAllTypes()) {
 
 			assertTrue(t.getPosition().getFile().getAbsolutePath().contains("Foo"));
 		}
@@ -195,10 +198,66 @@ public CompilationUnit[] getCompilationUnits() {
 		launcher.buildModel();
 
 		// we indeed only have types declared in a file in package reference
-		for(CtType<?> t : launcher.getFactory().getModel().getAllTypes()) {
+		for (CtType<?> t : launcher.getFactory().getModel().getAllTypes()) {
 			assertTrue(t.getQualifiedName().contains("reference"));
 		}
 
 	}
 
-}
+	@Test
+	public void testClassLoader() throws Exception {
+		// contract: the environment exposes a classloader configured by the spoonclass path
+		Launcher launcher = new Launcher();
+
+		// not in the classpath
+		try {
+			Class.forName("spoontest.a.ClassA");
+			fail();
+		} catch (ClassNotFoundException expected) {
+		}
+
+		// not in the spoon classpath before setting it
+		try {
+			launcher.getEnvironment().getInputClassLoader().loadClass("spoontest.a.ClassA");
+			fail();
+		} catch (ClassNotFoundException expected) {
+		}
+
+		launcher.getEnvironment().setSourceClasspath(new String[]{"src/test/resources/reference-test-2/ReferenceTest2.jar"});
+
+		Class c = launcher.getEnvironment().getInputClassLoader().loadClass("spoontest.a.ClassA");
+		assertEquals("spoontest.a.ClassA", c.getName());
+	}
+
+	@Test
+	public void testExoticClassLoader() throws Exception {
+		// contract: Spoon uses the exotic class loader
+
+		final List<String> l = new ArrayList<>();
+		class MyClassLoader extends ClassLoader {
+			@Override
+			protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+				l.add(name);
+				return super.loadClass(name, resolve);
+			}
+		}
+
+		Launcher launcher = new Launcher();
+		launcher.getEnvironment().setInputClassLoader(new MyClassLoader());
+		launcher.getEnvironment().setNoClasspath(true);
+		launcher.addInputResource("src/test/resources/reference-test/Foo.java");
+		launcher.buildModel();
+		launcher.getModel().getRootPackage().accept(new CtScanner() {
+			@Override
+			public <T> void visitCtTypeReference(CtTypeReference<T> reference) {
+				try {
+					// forcing loading it
+					reference.getTypeDeclaration();
+				} catch (SpoonClassNotFoundException ignore) {}
+			}
+		});
+
+		assertEquals(1, l.size());
+		assertEquals("KJHKY", l.get(0));
+	}
+}
\ No newline at end of file
diff --git a/src/test/resources/reference-test/Foo.java b/src/test/resources/reference-test/Foo.java
new file mode 100644
index 00000000000..25ac90078c6
--- /dev/null
+++ b/src/test/resources/reference-test/Foo.java
@@ -0,0 +1,4 @@
+public class Foo {
+  KJHKY l;
+}
+