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
@@ -102,44 +108,17 @@ public interface Scalafix {
102108 String scala3Next ();
103109
104110 /**
105- * Fetch JARs containing an implementation of {@link Scalafix} using Coursier and classload an instance of it via
106- * runtime reflection.
107- * <p>
108- * The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and
109- * classload external rules must have the classloader of the returned instance as ancestor to share a common
110- * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala version.
111- *
112- * @param requestedScalaVersion A full Scala version (i.e. "3.3.4") or a major.minor one (i.e. "3.3") to infer
113- * the major.minor Scala version that should be available in the classloader of the
114- * returned instance. To be able to run advanced semantic rules using the Scala
115- * Presentation Compiler such as ExplicitResultTypes, this must be source-compatible
116- * with the version that the target classpath is built with, as provided with
117- * {@link ScalafixArguments#withScalaVersion}.
118- * @return An implementation of the {@link Scalafix} interface.
119- * @throws ScalafixException in case of errors during artifact resolution/fetching.
111+ * @deprecated Use {@link #get()} instead.
120112 */
113+ @ Deprecated
121114 static Scalafix fetchAndClassloadInstance (String requestedScalaVersion ) throws ScalafixException {
122115 return fetchAndClassloadInstance (requestedScalaVersion , Repository .defaults ());
123116 }
124117
125118 /**
126- * Fetch JARs containing an implementation of {@link Scalafix} from the provided repositories using Coursier and
127- * classload an instance of it via runtime reflection.
128- * <p>
129- * The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and
130- * classload external rules must have the classloader of the returned instance as ancestor to share a common
131- * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala version.
132- *
133- * @param requestedScalaVersion A full Scala version (i.e. "3.3.4") or a major.minor one (i.e. "3.3") to infer
134- * the major.minor Scala version that should be available in the classloader of the
135- * returned instance. To be able to run advanced semantic rules using the Scala
136- * Presentation Compiler such as ExplicitResultTypes, this must be source-compatible
137- * with the version that the target classpath is built with, as provided with
138- * {@link ScalafixArguments#withScalaVersion}.
139- * @param repositories Maven/Ivy repositories to fetch the JARs from.
140- * @return An implementation of the {@link Scalafix} interface.
141- * @throws ScalafixException in case of errors during artifact resolution/fetching.
119+ * @deprecated Use {@link #get()} instead.
142120 */
121+ @ Deprecated
143122 static Scalafix fetchAndClassloadInstance (String requestedScalaVersion , List <Repository > repositories )
144123 throws ScalafixException {
145124
@@ -164,36 +143,34 @@ static Scalafix fetchAndClassloadInstance(String requestedScalaVersion, List<Rep
164143 }
165144
166145 /**
167- * JVM runtime reflection method helper to classload an instance of {@link Scalafix}.
168- * <p>
169- * The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and
170- * classload external rules must have the provided classloader as ancestor to share a common loaded instance
171- * of `scalafix-core`, and therefore must have been compiled against the same Scala binary version as
172- * the one in the classLoader provided here.
173- * <p>
174- * Unless you have an advanced use-case, prefer the high-level overloads that cannot cause runtime errors
175- * due to an invalid classloader hierarchy.
176- *
177- * @param classLoader Classloader containing the full Scalafix classpath, including the scalafix-cli module. To be
178- * able to run advanced semantic rules using the Scala Presentation Compiler such as
179- * ExplicitResultTypes, this Scala binary version in that classloader should match the one that
180- * the target classpath was built with, as provided with
181- * {@link ScalafixArguments#withScalaVersion}.
182- * @return An implementation of the {@link Scalafix} interface.
183- * @throws ScalafixException in case of errors during classloading, most likely caused
184- * by an incorrect classloader argument.
146+ * @deprecated Use {@link #get()} instead.
185147 */
148+ @ Deprecated
186149 static Scalafix classloadInstance (ClassLoader classLoader ) throws ScalafixException {
187150 try {
188151 Class <?> cls = classLoader .loadClass ("scalafix.internal.interfaces.ScalafixImpl" );
189152 Constructor <?> ctor = cls .getDeclaredConstructor ();
190153 ctor .setAccessible (true );
191154 return (Scalafix ) ctor .newInstance ();
192- } catch (ClassNotFoundException | NoSuchMethodException |
193- IllegalAccessException | InvocationTargetException |
194- InstantiationException ex ) {
155+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException
156+ | InstantiationException ex ) {
195157 throw new ScalafixException (
196158 "Failed to reflectively load Scalafix with classloader " + classLoader .toString (), ex );
197159 }
198160 }
161+
162+ /**
163+ * Obtains an implementation of Scalafix using the current classpath.
164+ *
165+ * @return the first available implementation advertised as a service provider.
166+ */
167+ static Scalafix get () {
168+ ServiceLoader <Scalafix > loader = ServiceLoader .load (Scalafix .class );
169+ Iterator <Scalafix > iterator = loader .iterator ();
170+ if (iterator .hasNext ()) {
171+ return iterator .next ();
172+ } else {
173+ throw new IllegalStateException ("No implementation found" );
174+ }
175+ }
199176}
0 commit comments