1
1
package scalafix .interfaces ;
2
2
3
3
import coursierapi .Repository ;
4
+
4
5
import scalafix .internal .interfaces .ScalafixCoursier ;
5
6
import scalafix .internal .interfaces .ScalafixInterfacesClassloader ;
6
7
import scalafix .internal .interfaces .ScalafixProperties ;
11
12
import java .lang .reflect .InvocationTargetException ;
12
13
import java .net .URL ;
13
14
import java .net .URLClassLoader ;
15
+ import java .util .Iterator ;
14
16
import java .util .List ;
15
17
import java .util .Properties ;
18
+ import java .util .ServiceLoader ;
16
19
17
20
/**
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.
19
23
* <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()}.
21
26
*
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.
24
30
*/
25
31
public interface Scalafix {
26
32
@@ -102,44 +108,17 @@ public interface Scalafix {
102
108
String scala3Next ();
103
109
104
110
/**
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.
120
112
*/
113
+ @ Deprecated
121
114
static Scalafix fetchAndClassloadInstance (String requestedScalaVersion ) throws ScalafixException {
122
115
return fetchAndClassloadInstance (requestedScalaVersion , Repository .defaults ());
123
116
}
124
117
125
118
/**
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.
142
120
*/
121
+ @ Deprecated
143
122
static Scalafix fetchAndClassloadInstance (String requestedScalaVersion , List <Repository > repositories )
144
123
throws ScalafixException {
145
124
@@ -164,36 +143,34 @@ static Scalafix fetchAndClassloadInstance(String requestedScalaVersion, List<Rep
164
143
}
165
144
166
145
/**
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.
185
147
*/
148
+ @ Deprecated
186
149
static Scalafix classloadInstance (ClassLoader classLoader ) throws ScalafixException {
187
150
try {
188
151
Class <?> cls = classLoader .loadClass ("scalafix.internal.interfaces.ScalafixImpl" );
189
152
Constructor <?> ctor = cls .getDeclaredConstructor ();
190
153
ctor .setAccessible (true );
191
154
return (Scalafix ) ctor .newInstance ();
192
- } catch (ClassNotFoundException | NoSuchMethodException |
193
- IllegalAccessException | InvocationTargetException |
194
- InstantiationException ex ) {
155
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException
156
+ | InstantiationException ex ) {
195
157
throw new ScalafixException (
196
158
"Failed to reflectively load Scalafix with classloader " + classLoader .toString (), ex );
197
159
}
198
160
}
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
+ }
199
176
}
0 commit comments