Java tutorial
/* * Copyright 2013-2016 Grzegorz Slowikowski (gslowikowski at gmail dot com) * * 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 com.google.code.sbt.compiler.plugin; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.DirectoryScanner; import com.google.code.sbt.compiler.api.Compiler; import com.google.code.sbt.compiler.api.CompilerConfiguration; import com.google.code.sbt.compiler.api.CompilerException; import com.google.code.sbt.compiler.api.Compilers; import com.google.code.sbt.compiler.api.SourcePositionMapper; /** * Abstract base class for SBT compilation mojos. * * @author <a href="mailto:gslowikowski@gmail.com">Grzegorz Slowikowski</a> */ public abstract class AbstractSBTCompileMojo extends AbstractMojo { /** * Scala artifacts "groupId". */ private static final String SCALA_GROUPID = "org.scala-lang"; /** * Scala library "artifactId". */ private static final String SCALA_LIBRARY_ARTIFACTID = "scala-library"; /** * Scala compiler "artifactId". */ private static final String SCALA_COMPILER_ARTIFACTID = "scala-compiler"; /** * SBT artifacts "groupId". */ private static final String SBT_GROUP_ID = "com.typesafe.sbt"; /** * SBT compile interface "artifactId". */ private static final String COMPILER_INTERFACE_ARTIFACT_ID = "compiler-interface"; /** * SBT compile interface sources "classifier". */ private static final String COMPILER_INTERFACE_CLASSIFIER = "sources"; /** * SBT interface "artifactId". */ private static final String XSBTI_ARTIFACT_ID = "sbt-interface"; /** * Forced Scala version.<br> * <br> * If specified, this version of Scala compiler is used for compilation.<br> * If not specified, version of project's {@code org.scala-lang:scala-library} dependency is used.<br> * If there is no {@code org.scala-lang:scala-library} dependency in the project (in Java only projects), * selected compiler's {@link Compiler#getDefaultScalaVersion()} is used. * * @since 1.0.0 */ @Parameter(property = "scala.version") protected String scalaVersion; /** * Forced SBT version.<br> * <br> * Used to automatically select one of the "well known" SBT compilers if no compiler added explicitly as plugin's dependency. * There are three cases possible: * <ul> * <li> * If {@link #sbtVersion} is specified, compatible {@link Compiler} implementation * is selected and configured to use {@link #sbtVersion} SBT version for compilation. * </li> * <li> * If {@link #sbtVersion} is not specified, and {@link #playVersion} is specified * {@link #playVersion} parameter value is used to indirectly select compatible {@link Compiler} implementation * and it's {@link Compiler#getDefaultSbtVersion()} SBT version used for compilation. * </li> * <li> * If both {@link #sbtVersion} and {@link #playVersion} are not specified * the most recent {@link Compiler} implementation is selected * and it's {@link Compiler#getDefaultSbtVersion()} SBT version used for compilation. * </li> * </ul> * * @since 1.0.0 */ @Parameter(property = "sbt.version") protected String sbtVersion; /** * Forced Play! Framework version. * <br> * <br> * Used to select SBT version in Play! Framework projects based on framework version used. * See {@link #sbtVersion} for more details. * * @since 1.0.0 */ @Parameter(property = "play2.version") protected String playVersion; /** * Scala and Java source files encoding. * <br> * <br> * If not specified, the encoding value will be the value of the {@code file.encoding} system property. * <br> * <br> * {@code -encoding} option in {@link #scalacOptions} or {@link #javacOptions} * overrides this parameter for Scala or Java compiler respectively. * * @since 1.0.0 */ @Parameter(property = "project.build.sourceEncoding") protected String sourceEncoding; /** * Additional parameters for Java compiler. * <br> * <br> * Space-separated list of parameters. Parameters containing spaces can be enclosed in apostrophes or quotes. * * @since 1.0.0 */ @Parameter(property = "sbt.javacOptions", defaultValue = "-g") protected String javacOptions; /** * Additional parameters for Scala compiler. * <br> * <br> * Space-separated list of parameters. Parameters containing spaces can be enclosed in apostrophes or quotes. * * @since 1.0.0 */ @Parameter(property = "sbt.scalacOptions", defaultValue = "-deprecation -unchecked") protected String scalacOptions; /** * Additional parameters for Scala compiler. * <br> * For internal use only. */ @Parameter(property = "sbt._scalacOptions", defaultValue = "", readonly = true) protected String _scalacOptions; /** * Scala compiler plugins. * <br> * <br> * Space-separated list of plugin definitions in {@code groupId:artifactId:version} format. * * @since 1.0.0 */ @Parameter(property = "sbt.scalacPlugins", defaultValue = "") protected String scalacPlugins; /** * Scala compiler plugins. * <br> * For internal use only. */ @Parameter(property = "sbt._scalacPlugins", defaultValue = "", readonly = true) protected String _scalacPlugins; /** * Source position mappers. * <br> * <br> * Space-separated list of source position mapper definitions in {@code groupId:artifactId:version} format. * * @since 1.0.0 */ @Parameter(property = "sbt.sourcePositionMappers", defaultValue = "", readonly = true) protected String sourcePositionMappers; /** * Source position mappers. * <br> * For internal use only. */ @Parameter(property = "sbt._sourcePositionMappers", defaultValue = "", readonly = true) protected String _sourcePositionMappers; /** * Maven project to interact with. */ @Parameter(defaultValue = "${project}", readonly = true, required = true) protected MavenProject project; /** * All Maven projects in the reactor. */ @Parameter(defaultValue = "${reactorProjects}", required = true, readonly = true) protected List<MavenProject> reactorProjects; /** * Artifact factory used to look up artifacts in the remote repository. */ @Component protected ArtifactFactory factory; /** * Artifact resolver used to resolve artifacts. */ @Component protected ArtifactResolver resolver; /** * Location of the local repository. */ @Parameter(property = "localRepository", readonly = true, required = true) protected ArtifactRepository localRepo; /** * Remote repositories used by the resolver */ @Parameter(property = "project.remoteArtifactRepositories", readonly = true, required = true) protected List<ArtifactRepository> remoteRepos; /** * For retrieval of artifact's metadata. */ @Component protected ArtifactMetadataSource metadataSource; /** * Plugin's groupId used for well known providers resolution */ @Parameter(property = "plugin.groupId", readonly = true, required = true) private String pluginGroupId; /** * Plugin's version used for well known providers resolution */ @Parameter(property = "plugin.version", readonly = true, required = true) private String pluginVersion; /** * Map of compiler implementations. For now only zero or one allowed. */ @Component(role = Compiler.class) private Map<String, Compiler> compilers; /** * Performs compilation. * * @throws MojoExecutionException if unexpected problem occurs * @throws MojoFailureException if expected problem (such as compilation failure) occurs */ @Override public void execute() throws MojoExecutionException, MojoFailureException { if (!"pom".equals(project.getPackaging())) { long ts = System.currentTimeMillis(); try { internalExecute(); } finally { long te = System.currentTimeMillis(); getLog().debug(String.format("Mojo execution time: %d ms", te - ts)); } } } /** * Performs compilation. * * @throws MojoExecutionException if unexpected problem occurs * @throws MojoFailureException if expected problem (such as compilation failure) occurs */ protected void internalExecute() throws MojoExecutionException, MojoFailureException { List<String> compileSourceRoots = getCompileSourceRoots(); if (compileSourceRoots.isEmpty())// ? { getLog().info("No sources to compile"); return; } List<File> sourceRootDirs = new ArrayList<File>(compileSourceRoots.size()); for (String compileSourceRoot : compileSourceRoots) { sourceRootDirs.add(new File(compileSourceRoot)); } List<File> sourceFiles = getSourceFiles(sourceRootDirs); if (sourceFiles.isEmpty()) { getLog().info("No sources to compile"); return; } try { Compiler sbtCompiler = getSbtCompiler(); String resolvedScalaVersion = getScalaVersion(sbtCompiler); Artifact scalaLibraryArtifact = getResolvedArtifact(SCALA_GROUPID, SCALA_LIBRARY_ARTIFACTID, resolvedScalaVersion); if (scalaLibraryArtifact == null) { throw new MojoExecutionException(String.format("Required %s:%s:%s:jar artifact not found", SCALA_GROUPID, SCALA_LIBRARY_ARTIFACTID, resolvedScalaVersion)); } Artifact scalaCompilerArtifact = getResolvedArtifact(SCALA_GROUPID, SCALA_COMPILER_ARTIFACTID, resolvedScalaVersion); if (scalaCompilerArtifact == null) { throw new MojoExecutionException(String.format("Required %s:%s:%s:jar artifact not found", SCALA_GROUPID, SCALA_COMPILER_ARTIFACTID, resolvedScalaVersion)); } List<File> scalaExtraJars = getCompilerDependencies(scalaCompilerArtifact, scalaLibraryArtifact); String resolvedSbtVersion = sbtCompiler.getDefaultSbtVersion(); Artifact xsbtiArtifact = getResolvedArtifact(SBT_GROUP_ID, XSBTI_ARTIFACT_ID, resolvedSbtVersion); if (xsbtiArtifact == null) { throw new MojoExecutionException(String.format("Required %s:%s:%s:jar dependency not found", SBT_GROUP_ID, XSBTI_ARTIFACT_ID, resolvedSbtVersion)); } Artifact compilerInterfaceSrc = getResolvedArtifact(SBT_GROUP_ID, COMPILER_INTERFACE_ARTIFACT_ID, resolvedSbtVersion, COMPILER_INTERFACE_CLASSIFIER); if (compilerInterfaceSrc == null) { throw new MojoExecutionException( String.format("Required %s:%s:%s:%s:jar dependency not found", SBT_GROUP_ID, COMPILER_INTERFACE_ARTIFACT_ID, resolvedSbtVersion, COMPILER_INTERFACE_CLASSIFIER)); } List<String> classpathElements = getClasspathElements(); classpathElements.remove(getOutputDirectory().getAbsolutePath()); List<File> classpathFiles = new ArrayList<File>(classpathElements.size()); for (String path : classpathElements) { classpathFiles.add(new File(path)); } String resolvedScalacOptions = scalacOptions.trim(); if (_scalacOptions != null && _scalacOptions.length() > 0) { resolvedScalacOptions = resolvedScalacOptions + ' ' + _scalacOptions; } if ((scalacPlugins != null && scalacPlugins.trim().length() > 0) || (_scalacPlugins != null && _scalacPlugins.trim().length() > 0)) { List<Artifact> resolvedScalaCompilerPluginArtifacts = new ArrayList<Artifact>(); resolveArtifacts(resolvedScalaCompilerPluginArtifacts, scalacPlugins); resolveArtifacts(resolvedScalaCompilerPluginArtifacts, _scalacPlugins); for (Artifact artifact : resolvedScalaCompilerPluginArtifacts) { String arg = "-Xplugin:" + artifact.getFile().getAbsolutePath(); if (arg.indexOf(' ') >= 0) { arg = '\"' + arg + '\"'; } resolvedScalacOptions = resolvedScalacOptions + ' ' + arg; } } SourcePositionMapper sourcePositionMapper = null; if (sbtCompiler.supportsSourcePositionMappers()) { if ((sourcePositionMappers != null && sourcePositionMappers.trim().length() > 0) || (_sourcePositionMappers != null && _sourcePositionMappers.trim().length() > 0)) { List<Artifact> resolvedSourcePositionMapperArtifacts = new ArrayList<Artifact>(); resolveArtifacts(resolvedSourcePositionMapperArtifacts, sourcePositionMappers); resolveArtifacts(resolvedSourcePositionMapperArtifacts, _sourcePositionMappers); if (!resolvedSourcePositionMapperArtifacts.isEmpty()) { Set<Artifact> resolvedSourcePositionMapperArtifactSet = getAllDependencies( new HashSet<Artifact>(resolvedSourcePositionMapperArtifacts), null /* filter */ ); List<SourcePositionMapper> resolvedSourcePositionMappers = resolveSourcePositionMappers( resolvedSourcePositionMapperArtifactSet); if (resolvedSourcePositionMappers != null) { sourcePositionMapper = new SourcePositionMapperCollection( resolvedSourcePositionMappers); sourcePositionMapper.setCharsetName(sourceEncoding); } } } } CompilerConfiguration configuration = new CompilerConfiguration(); configuration.setSourceFiles(sourceFiles); configuration.setScalaLibraryFile(scalaLibraryArtifact.getFile()); configuration.setScalaCompilerFile(scalaCompilerArtifact.getFile()); configuration.setScalaExtraJarFiles(scalaExtraJars); configuration.setXsbtiFile(xsbtiArtifact.getFile()); configuration.setCompilerInterfaceSrcFile(compilerInterfaceSrc.getFile()); configuration.setClasspathFiles(classpathFiles); configuration.setLogger(new MavenCompilerLogger(getLog())); configuration.setOutputDirectory(getOutputDirectory()); configuration.setSourceEncoding(sourceEncoding); configuration.setJavacOptions(javacOptions); configuration.setScalacOptions(resolvedScalacOptions); configuration.setAnalysisCacheFile(getAnalysisCacheFile()); configuration.setAnalysisCacheMap(getAnalysisCacheMap()); configuration.setSourcePositionMapper(sourcePositionMapper); sbtCompiler.performCompile(configuration); } catch (CompilerException e) { throw new MojoFailureException("Scala compilation failed", e); } catch (ArtifactNotFoundException e) { throw new MojoExecutionException("Scala compilation failed", e); } catch (ArtifactResolutionException e) { throw new MojoExecutionException("Scala compilation failed", e); } catch (MalformedURLException e) { throw new MojoExecutionException("Scala compilation failed", e); } } /** * Returns compilation classpath elements. * * @return classpath elements */ protected abstract List<String> getClasspathElements(); /** * Returns compilation source roots. * * @return source roots */ protected abstract List<String> getCompileSourceRoots(); /** * Returns source inclusion filters for the compiler. * * @return source inclusion filters */ protected abstract Set<String> getSourceIncludes(); /** * Returns source exclusion filters for the compiler. * * @return source exclusion filters */ protected abstract Set<String> getSourceExcludes(); /** * Returns output directory. * * @return output directory */ protected abstract File getOutputDirectory(); /** * Returns SBT incremental compilation analysis cache file location for this project. * * @return analysis cache file */ protected abstract File getAnalysisCacheFile(); /** * Returns SBT incremental compilation analysis cache file locations map for all reactor projects. * * @return analysis cache files map */ protected abstract Map<File, File> getAnalysisCacheMap(); private Artifact getDependencyArtifact(Collection<?> classPathArtifacts, String groupId, String artifactId, String type) { Artifact result = null; for (Iterator<?> iter = classPathArtifacts.iterator(); iter.hasNext();) { Artifact artifact = (Artifact) iter.next(); if (groupId.equals(artifact.getGroupId()) && artifactId.equals(artifact.getArtifactId()) && type.equals(artifact.getType())) { result = artifact; break; } } return result; } private List<File> getSourceFiles(List<File> sourceRootDirs) { List<File> sourceFiles = new ArrayList<File>(); Set<String> sourceIncludes = getSourceIncludes(); if (sourceIncludes.isEmpty()) { sourceIncludes.add("**/*.java"); sourceIncludes.add("**/*.scala"); } Set<String> sourceExcludes = getSourceExcludes(); DirectoryScanner scanner = new DirectoryScanner(); scanner.setIncludes(sourceIncludes.toArray(new String[sourceIncludes.size()])); if (!sourceExcludes.isEmpty()) { scanner.setExcludes(sourceExcludes.toArray(new String[sourceExcludes.size()])); } scanner.addDefaultExcludes(); for (File dir : sourceRootDirs) { if (dir.isDirectory()) { scanner.setBasedir(dir); scanner.scan(); String[] includedFileNames = scanner.getIncludedFiles(); for (String includedFileName : includedFileNames) { File tmpAbsFile = new File(dir, includedFileName).getAbsoluteFile(); // ? sourceFiles.add(tmpAbsFile); } } } // scalac is sensible to scala file order, file system can't guarantee file order => unreproductible build error // across platform // to guarantee reproductible command line we order file by path (os dependend). // Collections.sort( sourceFiles ); return sourceFiles; } private String getScalaVersion(Compiler sbtCompiler) { String result = scalaVersion; if (result == null || result.length() == 0) { Artifact scalaLibraryArtifact = getDependencyArtifact(project.getArtifacts(), SCALA_GROUPID, SCALA_LIBRARY_ARTIFACTID, "jar"); if (scalaLibraryArtifact != null) { result = scalaLibraryArtifact.getVersion(); } else { result = sbtCompiler.getDefaultScalaVersion(); } } return result; } /** * Returns SBT incremental main compilation analysis cache file location for a project. * * @param p Maven project * @return analysis cache file location */ protected File defaultAnalysisCacheFile(MavenProject p) { File classesDirectory = new File(p.getBuild().getOutputDirectory()); return new File(Compilers.getCacheDirectory(classesDirectory), "compile"); } /** * Returns SBT incremental test compilation analysis cache file location for a project. * * @param p Maven project * @return analysis cache file location */ protected File defaultTestAnalysisCacheFile(MavenProject p) { File testClassesDirectory = new File(p.getBuild().getTestOutputDirectory()); return new File(Compilers.getCacheDirectory(testClassesDirectory), "test-compile"); } // Private utility methods private Artifact getResolvedArtifact(String groupId, String artifactId, String version) throws ArtifactNotFoundException, ArtifactResolutionException { Artifact artifact = factory.createArtifact(groupId, artifactId, version, Artifact.SCOPE_RUNTIME, "jar"); resolver.resolve(artifact, remoteRepos, localRepo); return artifact; } private Artifact getResolvedArtifact(String groupId, String artifactId, String version, String classifier) throws ArtifactNotFoundException, ArtifactResolutionException { Artifact artifact = factory.createArtifactWithClassifier(groupId, artifactId, version, "jar", classifier); resolver.resolve(artifact, remoteRepos, localRepo); return artifact; } private List<File> getCompilerDependencies(Artifact scalaCompilerArtifact, Artifact scalaLibraryArtifact) throws ArtifactNotFoundException, ArtifactResolutionException { ArtifactFilter scalaLibraryFilter = new ExcludesArtifactFilter(Collections .singletonList(scalaLibraryArtifact.getGroupId() + ":" + scalaLibraryArtifact.getArtifactId())); List<File> d = new ArrayList<File>(); for (Artifact artifact : getAllDependencies(scalaCompilerArtifact, scalaLibraryFilter)) { if (!scalaCompilerArtifact.getGroupId().equals(artifact.getGroupId()) || !scalaCompilerArtifact.getArtifactId().equals(artifact.getArtifactId())) { d.add(artifact.getFile()); // don't add scalaCompilerArtifact file } } return d; } private Set<Artifact> getAllDependencies(Artifact artifact, ArtifactFilter filter) throws ArtifactNotFoundException, ArtifactResolutionException { return getAllDependencies(Collections.singleton(artifact), filter); } private Set<Artifact> getAllDependencies(Set<Artifact> artifacts, ArtifactFilter filter) throws ArtifactNotFoundException, ArtifactResolutionException { Artifact originatingArtifact = factory.createBuildArtifact("dummy", "dummy", "1.0", "jar"); ArtifactResolutionResult resolutionResult = resolver.resolveTransitively(artifacts, originatingArtifact, localRepo, remoteRepos, metadataSource, filter); return resolutionResult.getArtifacts(); } // Cached classloaders private static final ConcurrentHashMap<String, ClassLoader> cachedClassLoaders = new ConcurrentHashMap<String, ClassLoader>( 2); private static ClassLoader getCachedClassLoader(String compilerId) { return cachedClassLoaders.get(compilerId); } private static void setCachedClassLoader(String compilerId, ClassLoader classLoader) { cachedClassLoaders.put(compilerId, classLoader); } private Compiler getSbtCompiler() throws MojoExecutionException { Compiler sbtCompiler = null; if (!compilers.isEmpty()) { sbtCompiler = getDeclaredSbtCompiler(); } else { sbtCompiler = getWellKnownSbtCompiler(); } return sbtCompiler; } private Compiler getDeclaredSbtCompiler() throws MojoExecutionException { if (compilers.size() > 1) { throw new MojoExecutionException("Too many compiles defined. A maximum of one allowed."); } Map.Entry<String, Compiler> compilerEntry = compilers.entrySet().iterator().next(); String compilerId = compilerEntry.getKey(); Compiler sbtCompiler = compilerEntry.getValue(); getLog().debug(String.format("Using declared compiler \"%s\".", compilerId)); return sbtCompiler; } private Compiler getWellKnownSbtCompiler() throws MojoExecutionException { try { String compilerId = Compilers.getDefaultCompilerId(sbtVersion, playVersion); ClassLoader compilerClassLoader = getCachedClassLoader(compilerId); if (compilerClassLoader == null) { getLog().debug(String.format("Cached classloader for compiler \"%s\" not available.", compilerId)); } else { if (compilerClassLoader.getParent() == Thread.currentThread().getContextClassLoader()) { getLog().debug(String.format("Using cached classloader for compiler \"%s\".", compilerId)); } else { getLog().debug(String.format( "Invalidated cached classloader for compiler \"%s\". Parent classloader changed from %d to %d.", compilerId, Integer.valueOf(compilerClassLoader.getParent().hashCode()), Integer.valueOf(Thread.currentThread().getContextClassLoader().hashCode()))); compilerClassLoader = null; } } if (compilerClassLoader == null) { Artifact compilerArtifact = getResolvedArtifact(pluginGroupId, "sbt-compiler-" + compilerId, pluginVersion); Set<Artifact> compilerDependencies = getAllDependencies(compilerArtifact, null); List<File> classPathFiles = new ArrayList<File>(compilerDependencies.size() + 1); // classPathFiles.add( compilerArtifact.getFile() ); for (Artifact dependencyArtifact : compilerDependencies) { classPathFiles.add(dependencyArtifact.getFile()); } String javaHome = System.getProperty("java.home"); classPathFiles.add(new File(javaHome, "../lib/tools.jar")); List<URL> classPathUrls = new ArrayList<URL>(classPathFiles.size()); for (File classPathFile : classPathFiles) { classPathUrls.add(new URL(classPathFile.toURI().toASCIIString())); } compilerClassLoader = new URLClassLoader(classPathUrls.toArray(new URL[classPathUrls.size()]), Thread.currentThread().getContextClassLoader()); getLog().debug( String.format("Setting cached classloader for compiler \"%s\" with parent classloader %d", compilerId, Integer.valueOf(compilerClassLoader.getParent().hashCode()))); setCachedClassLoader(compilerId, compilerClassLoader); } ServiceLoader<Compiler> compilerServiceLoader = ServiceLoader.load(Compiler.class, compilerClassLoader); // get first (there should be exactly one) Compiler sbtCompiler = compilerServiceLoader.iterator().next(); getLog().debug(String.format("Using autodetected compiler \"%s\".", compilerId)); return sbtCompiler; } catch (ArtifactNotFoundException e) { throw new MojoExecutionException("Compiler autodetection failed", e); } catch (ArtifactResolutionException e) { throw new MojoExecutionException("Compiler autodetection failed", e); } catch (MalformedURLException e) { throw new MojoExecutionException("Compiler autodetection failed", e); } } // "artifactGAVs" in format "groupId1:artifactId1:version1 groupId2:artifactId2:version2" private void resolveArtifacts(List<Artifact> artifacts, String artifactGAVs) throws ArtifactNotFoundException, ArtifactResolutionException { if (artifactGAVs != null && artifactGAVs.trim().length() > 0) { String[] scalacPluginsGAVs = artifactGAVs.trim().split(" "); for (String scalacPluginGAV : scalacPluginsGAVs) { String[] gav = scalacPluginGAV.split(":"); String groupId = gav[0]; String artifactId = gav[1]; String version = gav[2]; Artifact scalacPluginArtifact = getResolvedArtifact(groupId, artifactId, version); if (scalacPluginArtifact != null) { artifacts.add(scalacPluginArtifact); } } } } private List<SourcePositionMapper> resolveSourcePositionMappers( Set<Artifact> resolvedSourcePositionMapperArtifacts) throws MalformedURLException { List<SourcePositionMapper> result = null; List<URL> classPathUrls = new ArrayList<URL>(resolvedSourcePositionMapperArtifacts.size()); for (Artifact artifact : resolvedSourcePositionMapperArtifacts) { classPathUrls.add(new URL(artifact.getFile().toURI().toASCIIString())); } ClassLoader tmpMappersClassLoader = new URLClassLoader(classPathUrls.toArray(new URL[classPathUrls.size()]), Thread.currentThread().getContextClassLoader()); ServiceLoader<SourcePositionMapper> spmServiceLoader = ServiceLoader.load(SourcePositionMapper.class, tmpMappersClassLoader); Iterator<SourcePositionMapper> spmIterator = spmServiceLoader.iterator(); if (spmIterator.hasNext()) { result = new ArrayList<SourcePositionMapper>(); while (spmIterator.hasNext()) { result.add(spmIterator.next()); } } return result; } }