All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalafix.interfaces.Scalafix Maven / Gradle / Ivy

There is a newer version: 2.3.0-RC1
Show newest version
package scalafix.interfaces;

import coursierapi.Repository;
import scalafix.internal.interfaces.ScalafixCoursier;
import scalafix.internal.interfaces.ScalafixInterfacesClassloader;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Properties;

/**
 * Public API for reflectively invoking Scalafix from a build tool or IDE integration.
 * 

* To obtain an instance of Scalafix, use one of the static factory methods. * * @implNote This interface is not intended to be extended, the only implementation of this interface * should live in the Scalafix repository. */ public interface Scalafix { /** * @return Construct a new instance of {@link ScalafixArguments}. */ ScalafixArguments newArguments(); /** * Get --help message for running the Scalafix command-line interface. * * @param screenWidth The width of the screen, used for wrapping long sentences * into multiple lines. * @return The help message as a string. */ String mainHelp(int screenWidth); /** * The release version of the current Scalafix API instance. */ String scalafixVersion(); /** * The recommended Scalameta version to match the current Scalafix API instance. */ String scalametaVersion(); /** * The exact Scala versions that are supported by the recommended {@link #scalametaVersion()} */ String[] supportedScalaVersions(); /** * The most recent Scala 2.11 version in {@link #supportedScalaVersions()} */ String scala211(); /** * The most recent Scala 2.12 version in {@link #supportedScalaVersions()} */ String scala212(); /** * The most recent Scala 2.13 version in {@link #supportedScalaVersions()} */ String scala213(); /** * Fetch JARs containing an implementation of {@link Scalafix} using Coursier and classload an instance of it via * runtime reflection. *

* The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and * classload external rules must have the classloader of the returned instance as ancestor to share a common * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala binary version. * * @param scalaBinaryVersion The Scala binary version ("2.13" for example) available in the classloader of the * returned instance. To be able to run advanced semantic rules using the Scala * Presentation Compiler such as ExplicitResultTypes, this must match the binary * version that the target classpath was built with, as provided with * {@link ScalafixArguments#withScalaVersion}. * @return An implementation of the {@link Scalafix} interface. * @throws ScalafixException in case of errors during artifact resolution/fetching. */ static Scalafix fetchAndClassloadInstance(String scalaBinaryVersion) throws ScalafixException { return fetchAndClassloadInstance(scalaBinaryVersion, Repository.defaults()); } /** * Fetch JARs containing an implementation of {@link Scalafix} from the provided repositories using Coursier and * classload an instance of it via runtime reflection. *

* The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and * classload external rules must have the classloader of the returned instance as ancestor to share a common * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala binary version. * * @param scalaBinaryVersion The Scala binary version ("2.13" for example) available in the classloader of the * returned instance. To be able to run advanced semantic rules using the Scala * Presentation Compiler such as ExplicitResultTypes, this must match the binary * version that the target classpath was built with, as provided with * {@link ScalafixArguments#withScalaVersion}. * @param repositories Maven/Ivy repositories to fetch the JARs from. * @return An implementation of the {@link Scalafix} interface. * @throws ScalafixException in case of errors during artifact resolution/fetching. */ static Scalafix fetchAndClassloadInstance(String scalaBinaryVersion, List repositories) throws ScalafixException { String scalaVersionKey; switch (scalaBinaryVersion) { case "2.11": scalaVersionKey = "scala211"; break; case "2.12": scalaVersionKey = "scala212"; break; case "2.13": scalaVersionKey = "scala213"; break; default: throw new IllegalArgumentException("Unsupported scala version " + scalaBinaryVersion); } Properties properties = new Properties(); String propertiesPath = "scalafix-interfaces.properties"; InputStream stream = Scalafix.class.getClassLoader().getResourceAsStream(propertiesPath); try { properties.load(stream); } catch (IOException | NullPointerException e) { throw new ScalafixException("Failed to load '" + propertiesPath + "' to lookup versions", e); } String scalafixVersion = properties.getProperty("scalafixVersion"); String scalaVersion = properties.getProperty(scalaVersionKey); if (scalafixVersion == null || scalaVersion == null) throw new ScalafixException("Failed to lookup versions from '" + propertiesPath + "'"); List jars = ScalafixCoursier.scalafixCliJars(repositories, scalafixVersion, scalaVersion); ClassLoader parent = new ScalafixInterfacesClassloader(Scalafix.class.getClassLoader()); return classloadInstance(new URLClassLoader(jars.stream().toArray(URL[]::new), parent)); } /** * JVM runtime reflection method helper to classload an instance of {@link Scalafix}. *

* The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and * classload external rules must have the provided classloader as ancestor to share a common loaded instance * of `scalafix-core`, and therefore must have been compiled against the same Scala binary version as * the one in the classLoader provided here. *

* Unless you have an advanced use-case, prefer the high-level overloads that cannot cause runtime errors * due to an invalid classloader hierarchy. * * @param classLoader Classloader containing the full Scalafix classpath, including the scalafix-cli module. To be * able to run advanced semantic rules using the Scala Presentation Compiler such as * ExplicitResultTypes, this Scala binary version in that classloader should match the one that * the target classpath was built with, as provided with * {@link ScalafixArguments#withScalaVersion}. * @return An implementation of the {@link Scalafix} interface. * @throws ScalafixException in case of errors during classloading, most likely caused * by an incorrect classloader argument. */ static Scalafix classloadInstance(ClassLoader classLoader) throws ScalafixException { try { Class cls = classLoader.loadClass("scalafix.internal.interfaces.ScalafixImpl"); Constructor ctor = cls.getDeclaredConstructor(); ctor.setAccessible(true); return (Scalafix) ctor.newInstance(); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException ex) { throw new ScalafixException( "Failed to reflectively load Scalafix with classloader " + classLoader.toString(), ex); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy