/** * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) * and/or other contributors as indicated by the @authors tag. See the * copyright.txt file in the distribution for a full listing of all * contributors. * * Licensed 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.mapstruct.ap.testutil.runner; import java.io.File; import java.util.List; import java.util.Set; import org.codehaus.plexus.compiler.CompilerConfiguration; import org.codehaus.plexus.compiler.CompilerException; import org.codehaus.plexus.compiler.CompilerResult; import org.codehaus.plexus.logging.console.ConsoleLogger; import org.eclipse.tycho.compiler.jdt.JDTCompiler; import org.junit.runners.model.FrameworkMethod; import org.mapstruct.ap.MappingProcessor; import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor; /** * Statement that uses the Eclipse JDT compiler to compile. * * @author Andreas Gudian */ class EclipseCompilingStatement extends CompilingStatement { private static final List<String> ECLIPSE_COMPILER_CLASSPATH = buildEclipseCompilerClasspath(); private static final ClassLoader DEFAULT_ECLIPSE_COMPILER_CLASSLOADER = new ModifiableURLClassLoader( newFilteringClassLoaderForEclipse() ) .withPaths( ECLIPSE_COMPILER_CLASSPATH ) .withPaths( PROCESSOR_CLASSPATH ) .withOriginOf( ClassLoaderExecutor.class ); EclipseCompilingStatement(FrameworkMethod method, CompilationCache compilationCache) { super( method, compilationCache ); } @Override protected CompilationOutcomeDescriptor compileWithSpecificCompiler(CompilationRequest compilationRequest, String sourceOutputDir, String classOutputDir, String additionalCompilerClasspath) { ClassLoader compilerClassloader; if ( additionalCompilerClasspath == null ) { compilerClassloader = DEFAULT_ECLIPSE_COMPILER_CLASSLOADER; } else { ModifiableURLClassLoader loader = new ModifiableURLClassLoader( newFilteringClassLoaderForEclipse() .hidingClasses( compilationRequest.getServices().values() ) ); compilerClassloader = loader.withPaths( ECLIPSE_COMPILER_CLASSPATH ) .withPaths( PROCESSOR_CLASSPATH ) .withOriginOf( ClassLoaderExecutor.class ) .withPath( additionalCompilerClasspath ) .withOriginsOf( compilationRequest.getServices().values() ); } ClassLoaderHelper clHelper = (ClassLoaderHelper) loadAndInstantiate( compilerClassloader, ClassLoaderExecutor.class ); return clHelper.compileInOtherClassloader( compilationRequest, TEST_COMPILATION_CLASSPATH, getSourceFiles( compilationRequest.getSourceClasses() ), SOURCE_DIR, sourceOutputDir, classOutputDir ); } private static FilteringParentClassLoader newFilteringClassLoaderForEclipse() { return new FilteringParentClassLoader( // reload eclipse compiler classes "org.eclipse.", // reload mapstruct processor classes "org.mapstruct.ap.internal.", "org.mapstruct.ap.spi.", "org.mapstruct.ap.MappingProcessor") .hidingClass( ClassLoaderExecutor.class ); } public interface ClassLoaderHelper { CompilationOutcomeDescriptor compileInOtherClassloader(CompilationRequest compilationRequest, List<String> testCompilationClasspath, Set<File> sourceFiles, String sourceDir, String sourceOutputDir, String classOutputDir); } public static final class ClassLoaderExecutor implements ClassLoaderHelper { @Override public CompilationOutcomeDescriptor compileInOtherClassloader(CompilationRequest compilationRequest, List<String> testCompilationClasspath, Set<File> sourceFiles, String sourceDir, String sourceOutputDir, String classOutputDir) { JDTCompiler compiler = new JDTCompiler(); compiler.enableLogging( new ConsoleLogger( 5, "JDT-Compiler" ) ); CompilerConfiguration config = new CompilerConfiguration(); config.setClasspathEntries( testCompilationClasspath ); config.setOutputLocation( classOutputDir ); config.setGeneratedSourcesDirectory( new File( sourceOutputDir ) ); config.setAnnotationProcessors( new String[] { MappingProcessor.class.getName() } ); config.setSourceFiles( sourceFiles ); config.setShowWarnings( false ); config.setSourceVersion( "1.8" ); config.setTargetVersion( "1.8" ); for ( String option : compilationRequest.getProcessorOptions() ) { config.addCompilerCustomArgument( option, null ); } CompilerResult compilerResult; try { compilerResult = compiler.performCompile( config ); } catch ( CompilerException e ) { throw new RuntimeException( e ); } return CompilationOutcomeDescriptor.forResult( sourceDir, compilerResult ); } } private static List<String> buildEclipseCompilerClasspath() { String[] whitelist = new String[] { "tycho-compiler", "org.eclipse.jdt.", "plexus-compiler-api", "plexus-component-annotations" }; return filterBootClassPath( whitelist ); } @Override protected String getPathSuffix() { return "_eclipse"; } }