/**
* 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.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.processing.Processor;
import javax.tools.Diagnostic.Kind;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import org.junit.runners.model.FrameworkMethod;
import org.mapstruct.ap.MappingProcessor;
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
import org.mapstruct.ap.testutil.compilation.model.DiagnosticDescriptor;
/**
* Statement that uses the JDK compiler to compile.
*
* @author Andreas Gudian
*/
class JdkCompilingStatement extends CompilingStatement {
private static final List<File> COMPILER_CLASSPATH_FILES = asFiles( TEST_COMPILATION_CLASSPATH );
private static final ClassLoader DEFAULT_PROCESSOR_CLASSLOADER =
new ModifiableURLClassLoader( new FilteringParentClassLoader( "org.mapstruct." ) )
.withPaths( PROCESSOR_CLASSPATH );
JdkCompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
super( method, compilationCache );
}
@Override
protected CompilationOutcomeDescriptor compileWithSpecificCompiler(CompilationRequest compilationRequest,
String sourceOutputDir,
String classOutputDir,
String additionalCompilerClasspath) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
Iterable<? extends JavaFileObject> compilationUnits =
fileManager.getJavaFileObjectsFromFiles( getSourceFiles( compilationRequest.getSourceClasses() ) );
try {
fileManager.setLocation( StandardLocation.CLASS_PATH, COMPILER_CLASSPATH_FILES );
fileManager.setLocation( StandardLocation.CLASS_OUTPUT, Arrays.asList( new File( classOutputDir ) ) );
fileManager.setLocation( StandardLocation.SOURCE_OUTPUT, Arrays.asList( new File( sourceOutputDir ) ) );
}
catch ( IOException e ) {
throw new RuntimeException( e );
}
ClassLoader processorClassloader;
if ( additionalCompilerClasspath == null ) {
processorClassloader = DEFAULT_PROCESSOR_CLASSLOADER;
}
else {
processorClassloader = new ModifiableURLClassLoader(
new FilteringParentClassLoader( "org.mapstruct." ) )
.withPaths( PROCESSOR_CLASSPATH )
.withPath( additionalCompilerClasspath )
.withOriginsOf( compilationRequest.getServices().values() );
}
CompilationTask task =
compiler.getTask(
null,
fileManager,
diagnostics,
compilationRequest.getProcessorOptions(),
null,
compilationUnits );
task.setProcessors(
Arrays.asList( (Processor) loadAndInstantiate( processorClassloader, MappingProcessor.class ) ) );
boolean compilationSuccessful = task.call();
return CompilationOutcomeDescriptor.forResult(
SOURCE_DIR,
compilationSuccessful,
diagnostics.getDiagnostics() );
}
private static List<File> asFiles(List<String> paths) {
List<File> classpath = new ArrayList<File>();
for ( String path : paths ) {
classpath.add( new File( path ) );
}
return classpath;
}
/**
* The JDK compiler only reports the first message of kind ERROR that is reported for one source file line, so we
* filter out the surplus diagnostics. The input list is already sorted by file name and line number, with the order
* for the diagnostics in the same line being kept at the order as given in the test.
*/
@Override
protected List<DiagnosticDescriptor> filterExpectedDiagnostics(List<DiagnosticDescriptor> expectedDiagnostics) {
List<DiagnosticDescriptor> filtered = new ArrayList<DiagnosticDescriptor>( expectedDiagnostics.size() );
DiagnosticDescriptor previous = null;
for ( DiagnosticDescriptor diag : expectedDiagnostics ) {
if ( diag.getKind() != Kind.ERROR
|| previous == null
|| !previous.getSourceFileName().equals( diag.getSourceFileName() )
|| !previous.getLine().equals( diag.getLine() ) ) {
filtered.add( diag );
previous = diag;
}
}
return filtered;
}
@Override
protected String getPathSuffix() {
return "_jdk";
}
}