11package scalafix .interfaces ;
22
33import coursierapi .Repository ;
4+
45import scalafix .internal .interfaces .ScalafixCoursier ;
56import scalafix .internal .interfaces .ScalafixInterfacesClassloader ;
67import scalafix .internal .interfaces .ScalafixProperties ;
1112import java .lang .reflect .InvocationTargetException ;
1213import java .net .URL ;
1314import java .net .URLClassLoader ;
15+ import java .util .Iterator ;
1416import java .util .List ;
1517import java .util .Properties ;
18+ import java .util .ServiceLoader ;
1619
1720/**
18- * Public API for reflectively invoking Scalafix from a build tool or IDE integration.
21+ * Public API for reflectively invoking Scalafix from a build tool or IDE
22+ * integration.
1923 * <p>
20- * To obtain an instance of Scalafix, use one of the static factory methods.
24+ * To obtain an instance of Scalafix, classload
25+ * <code>ch.epfl.scala:scalafix-loader</code> and use {@link #get()}.
2126 *
22- * @implNote This interface is not intended to be extended, the only implementation of this interface
23- * should live in the Scalafix repository.
27+ * @implNote This interface is not intended to be extended, the only
28+ * implementation of this interface should live in the Scalafix
29+ * repository.
2430 */
2531public interface Scalafix {
2632
@@ -97,44 +103,17 @@ public interface Scalafix {
97103 String scala3Next ();
98104
99105 /**
100- * Fetch JARs containing an implementation of {@link Scalafix} using Coursier and classload an instance of it via
101- * runtime reflection.
102- * <p>
103- * The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and
104- * classload external rules must have the classloader of the returned instance as ancestor to share a common
105- * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala version.
106- *
107- * @param requestedScalaVersion A full Scala version (i.e. "3.3.4") or a major.minor one (i.e. "3.3") to infer
108- * the major.minor Scala version that should be available in the classloader of the
109- * returned instance. To be able to run advanced semantic rules using the Scala
110- * Presentation Compiler such as ExplicitResultTypes, this must be source-compatible
111- * with the version that the target classpath is built with, as provided with
112- * {@link ScalafixArguments#withScalaVersion}.
113- * @return An implementation of the {@link Scalafix} interface.
114- * @throws ScalafixException in case of errors during artifact resolution/fetching.
106+ * @deprecated Use {@link #get()} instead.
115107 */
108+ @ Deprecated
116109 static Scalafix fetchAndClassloadInstance (String requestedScalaVersion ) throws ScalafixException {
117110 return fetchAndClassloadInstance (requestedScalaVersion , Repository .defaults ());
118111 }
119112
120113 /**
121- * Fetch JARs containing an implementation of {@link Scalafix} from the provided repositories using Coursier and
122- * classload an instance of it via runtime reflection.
123- * <p>
124- * The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and
125- * classload external rules must have the classloader of the returned instance as ancestor to share a common
126- * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala version.
127- *
128- * @param requestedScalaVersion A full Scala version (i.e. "3.3.4") or a major.minor one (i.e. "3.3") to infer
129- * the major.minor Scala version that should be available in the classloader of the
130- * returned instance. To be able to run advanced semantic rules using the Scala
131- * Presentation Compiler such as ExplicitResultTypes, this must be source-compatible
132- * with the version that the target classpath is built with, as provided with
133- * {@link ScalafixArguments#withScalaVersion}.
134- * @param repositories Maven/Ivy repositories to fetch the JARs from.
135- * @return An implementation of the {@link Scalafix} interface.
136- * @throws ScalafixException in case of errors during artifact resolution/fetching.
114+ * @deprecated Use {@link #get()} instead.
137115 */
116+ @ Deprecated
138117 static Scalafix fetchAndClassloadInstance (String requestedScalaVersion , List <Repository > repositories )
139118 throws ScalafixException {
140119
@@ -159,36 +138,34 @@ static Scalafix fetchAndClassloadInstance(String requestedScalaVersion, List<Rep
159138 }
160139
161140 /**
162- * JVM runtime reflection method helper to classload an instance of {@link Scalafix}.
163- * <p>
164- * The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and
165- * classload external rules must have the provided classloader as ancestor to share a common loaded instance
166- * of `scalafix-core`, and therefore must have been compiled against the same Scala binary version as
167- * the one in the classLoader provided here.
168- * <p>
169- * Unless you have an advanced use-case, prefer the high-level overloads that cannot cause runtime errors
170- * due to an invalid classloader hierarchy.
171- *
172- * @param classLoader Classloader containing the full Scalafix classpath, including the scalafix-cli module. To be
173- * able to run advanced semantic rules using the Scala Presentation Compiler such as
174- * ExplicitResultTypes, this Scala binary version in that classloader should match the one that
175- * the target classpath was built with, as provided with
176- * {@link ScalafixArguments#withScalaVersion}.
177- * @return An implementation of the {@link Scalafix} interface.
178- * @throws ScalafixException in case of errors during classloading, most likely caused
179- * by an incorrect classloader argument.
141+ * @deprecated Use {@link #get()} instead.
180142 */
143+ @ Deprecated
181144 static Scalafix classloadInstance (ClassLoader classLoader ) throws ScalafixException {
182145 try {
183146 Class <?> cls = classLoader .loadClass ("scalafix.internal.interfaces.ScalafixImpl" );
184147 Constructor <?> ctor = cls .getDeclaredConstructor ();
185148 ctor .setAccessible (true );
186149 return (Scalafix ) ctor .newInstance ();
187- } catch (ClassNotFoundException | NoSuchMethodException |
188- IllegalAccessException | InvocationTargetException |
189- InstantiationException ex ) {
150+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException
151+ | InstantiationException ex ) {
190152 throw new ScalafixException (
191153 "Failed to reflectively load Scalafix with classloader " + classLoader .toString (), ex );
192154 }
193155 }
156+
157+ /**
158+ * Obtains an implementation of Scalafix using the current classpath.
159+ *
160+ * @return the first available implementation advertised as a service provider.
161+ */
162+ static Scalafix get () {
163+ ServiceLoader <Scalafix > loader = ServiceLoader .load (Scalafix .class );
164+ Iterator <Scalafix > iterator = loader .iterator ();
165+ if (iterator .hasNext ()) {
166+ return iterator .next ();
167+ } else {
168+ throw new IllegalStateException ("No implementation found" );
169+ }
170+ }
194171}
0 commit comments