Skip to content

Commit 7622471

Browse files
cushonronshapiro
authored andcommitted
Add withClasspath(Iterable<File>) to Compiler and JavaSourcesSubject and deprecate withClasspathFrom(ClassLoader)
RELNOTES=Add `withClasspath(Iterable<File>)` to `Compiler` and `JavaSourcesSubject` and deprecate `withClasspathFrom(ClassLoader)` ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=185700333
1 parent ebbc462 commit 7622471

File tree

6 files changed

+302
-30
lines changed

6 files changed

+302
-30
lines changed

src/main/java/com/google/testing/compile/Compiler.java

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,39 @@
1616
package com.google.testing.compile;
1717

1818
import static com.google.common.base.Functions.toStringFunction;
19+
import static com.google.common.collect.ImmutableList.toImmutableList;
1920
import static java.nio.charset.StandardCharsets.UTF_8;
2021
import static javax.tools.ToolProvider.getSystemJavaCompiler;
2122

2223
import com.google.auto.value.AutoValue;
23-
import com.google.common.base.Joiner;
24+
import com.google.common.annotations.VisibleForTesting;
25+
import com.google.common.base.Splitter;
2426
import com.google.common.base.StandardSystemProperty;
2527
import com.google.common.collect.FluentIterable;
2628
import com.google.common.collect.ImmutableList;
2729
import com.google.common.collect.ImmutableSet;
30+
import com.google.common.collect.Iterables;
2831
import com.google.testing.compile.Compilation.Status;
32+
import java.io.File;
33+
import java.io.IOException;
34+
import java.io.UncheckedIOException;
2935
import java.net.URL;
3036
import java.net.URLClassLoader;
3137
import java.util.LinkedHashSet;
3238
import java.util.Locale;
39+
import java.util.Optional;
3340
import java.util.Set;
3441
import javax.annotation.processing.Processor;
3542
import javax.tools.DiagnosticCollector;
3643
import javax.tools.JavaCompiler;
3744
import javax.tools.JavaCompiler.CompilationTask;
3845
import javax.tools.JavaFileObject;
46+
import javax.tools.StandardLocation;
3947

4048
/** An object that can {@link #compile} Java source files. */
4149
@AutoValue
50+
// clashes with java.lang.Compiler (which is deprecated for removal in 9)
51+
@SuppressWarnings("JavaLangClash")
4252
public abstract class Compiler {
4353

4454
/** Returns the {@code javac} compiler. */
@@ -48,7 +58,8 @@ public static Compiler javac() {
4858

4959
/** Returns a {@link Compiler} that uses a given {@link JavaCompiler} instance. */
5060
public static Compiler compiler(JavaCompiler javaCompiler) {
51-
return new AutoValue_Compiler(javaCompiler, ImmutableList.of(), ImmutableList.of());
61+
return new AutoValue_Compiler(
62+
javaCompiler, ImmutableList.of(), ImmutableList.of(), Optional.empty());
5263
}
5364

5465
abstract JavaCompiler javaCompiler();
@@ -59,6 +70,9 @@ public static Compiler compiler(JavaCompiler javaCompiler) {
5970
/** The options passed to the compiler. */
6071
public abstract ImmutableList<String> options();
6172

73+
/** The compilation class path. If not present, the system class path is used. */
74+
public abstract Optional<ImmutableList<File>> classPath();
75+
6276
/**
6377
* Uses annotation processors during compilation. These replace any previously specified.
6478
*
@@ -78,7 +92,7 @@ public final Compiler withProcessors(Processor... processors) {
7892
* @return a new instance with the same options and the given processors
7993
*/
8094
public final Compiler withProcessors(Iterable<? extends Processor> processors) {
81-
return copy(ImmutableList.copyOf(processors), options());
95+
return copy(ImmutableList.copyOf(processors), options(), classPath());
8296
}
8397

8498
/**
@@ -96,21 +110,30 @@ public final Compiler withOptions(Object... options) {
96110
* @return a new instance with the same processors and the given options
97111
*/
98112
public final Compiler withOptions(Iterable<?> options) {
99-
return copy(processors(), FluentIterable.from(options).transform(toStringFunction()).toList());
113+
return copy(
114+
processors(),
115+
FluentIterable.from(options).transform(toStringFunction()).toList(),
116+
classPath());
100117
}
101118

102119
/**
103-
* Uses the classpath from the passed on classloader (and its parents) for the compilation
104-
* instead of the system classpath.
120+
* Uses the classpath from the passed on classloader (and its parents) for the compilation instead
121+
* of the system classpath.
105122
*
106123
* @throws IllegalArgumentException if the given classloader had classpaths which we could not
107124
* determine or use for compilation.
125+
* @deprecated prefer {@link #withClasspath(Iterable)}. This method only supports {@link
126+
* URLClassLoader} and the default system classloader, and {@link File}s are usually a more
127+
* natural way to expression compilation classpaths than class loaders.
108128
*/
129+
@Deprecated
109130
public final Compiler withClasspathFrom(ClassLoader classloader) {
110-
String classpath = getClasspathFromClassloader(classloader);
111-
ImmutableList<String> options =
112-
ImmutableList.<String>builder().add("-classpath").add(classpath).addAll(options()).build();
113-
return copy(processors(), options);
131+
return copy(processors(), options(), Optional.of(getClasspathFromClassloader(classloader)));
132+
}
133+
134+
/** Uses the given classpath for the compilation instead of the system classpath. */
135+
public final Compiler withClasspath(Iterable<File> classPath) {
136+
return copy(processors(), options(), Optional.of(ImmutableList.copyOf(classPath)));
114137
}
115138

116139
/**
@@ -132,6 +155,16 @@ public final Compilation compile(Iterable<? extends JavaFileObject> files) {
132155
InMemoryJavaFileManager fileManager =
133156
new InMemoryJavaFileManager(
134157
javaCompiler().getStandardFileManager(diagnosticCollector, Locale.getDefault(), UTF_8));
158+
classPath()
159+
.ifPresent(
160+
classPath -> {
161+
try {
162+
fileManager.setLocation(StandardLocation.CLASS_PATH, classPath);
163+
} catch (IOException e) {
164+
// impossible by specification
165+
throw new UncheckedIOException(e);
166+
}
167+
});
135168
CompilationTask task =
136169
javaCompiler()
137170
.getTask(
@@ -156,20 +189,38 @@ public final Compilation compile(Iterable<? extends JavaFileObject> files) {
156189
return compilation;
157190
}
158191

192+
@VisibleForTesting static final ClassLoader platformClassLoader = getPlatformClassLoader();
193+
194+
private static ClassLoader getPlatformClassLoader() {
195+
try {
196+
// JDK >= 9
197+
return (ClassLoader) ClassLoader.class.getMethod("getPlatformClassLoader").invoke(null);
198+
} catch (ReflectiveOperationException e) {
199+
// Java <= 8
200+
return null;
201+
}
202+
}
203+
159204
/**
160205
* Returns the current classpaths of the given classloader including its parents.
161206
*
162207
* @throws IllegalArgumentException if the given classloader had classpaths which we could not
163208
* determine or use for compilation.
164209
*/
165-
private static String getClasspathFromClassloader(ClassLoader currentClassloader) {
210+
private static ImmutableList<File> getClasspathFromClassloader(ClassLoader currentClassloader) {
166211
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
167212

168213
// Concatenate search paths from all classloaders in the hierarchy 'till the system classloader.
169214
Set<String> classpaths = new LinkedHashSet<>();
170215
while (true) {
171216
if (currentClassloader == systemClassLoader) {
172-
classpaths.add(StandardSystemProperty.JAVA_CLASS_PATH.value());
217+
Iterables.addAll(
218+
classpaths,
219+
Splitter.on(StandardSystemProperty.PATH_SEPARATOR.value())
220+
.split(StandardSystemProperty.JAVA_CLASS_PATH.value()));
221+
break;
222+
}
223+
if (currentClassloader == platformClassLoader) {
173224
break;
174225
}
175226
if (currentClassloader instanceof URLClassLoader) {
@@ -185,16 +236,21 @@ private static String getClasspathFromClassloader(ClassLoader currentClassloader
185236
}
186237
} else {
187238
throw new IllegalArgumentException(
188-
"Classpath for compilation could not be extracted "
189-
+ "since given classloader is not an instance of URLClassloader");
239+
String.format(
240+
"Classpath for compilation could not be extracted "
241+
+ "since %s is not an instance of URLClassloader",
242+
currentClassloader));
190243
}
191244
currentClassloader = currentClassloader.getParent();
192245
}
193246

194-
return Joiner.on(StandardSystemProperty.PATH_SEPARATOR.value()).join(classpaths);
247+
return classpaths.stream().map(File::new).collect(toImmutableList());
195248
}
196249

197-
private Compiler copy(ImmutableList<Processor> processors, ImmutableList<String> options) {
198-
return new AutoValue_Compiler(javaCompiler(), processors, options);
250+
private Compiler copy(
251+
ImmutableList<Processor> processors,
252+
ImmutableList<String> options,
253+
Optional<ImmutableList<File>> classPath) {
254+
return new AutoValue_Compiler(javaCompiler(), processors, options, classPath);
199255
}
200256
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (C) 2018 Google, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.testing.compile;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import javax.tools.ForwardingJavaFileManager;
22+
import javax.tools.JavaFileObject;
23+
import javax.tools.StandardJavaFileManager;
24+
25+
/**
26+
* Forwards calls to a given {@link StandardJavaFileManager}. Subclasses of this class might
27+
* override some of these methods and might also provide additional fields and methods.
28+
*/
29+
class ForwardingStandardJavaFileManager extends ForwardingJavaFileManager<StandardJavaFileManager>
30+
implements StandardJavaFileManager {
31+
32+
/**
33+
* Creates a new instance of ForwardingStandardJavaFileManager.
34+
*
35+
* @param fileManager delegate to this file manager
36+
*/
37+
ForwardingStandardJavaFileManager(StandardJavaFileManager fileManager) {
38+
super(fileManager);
39+
}
40+
41+
@Override
42+
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(
43+
Iterable<? extends File> files) {
44+
return fileManager.getJavaFileObjectsFromFiles(files);
45+
}
46+
47+
@Override
48+
public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
49+
return fileManager.getJavaFileObjects(files);
50+
}
51+
52+
@Override
53+
public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
54+
return fileManager.getJavaFileObjects(names);
55+
}
56+
57+
@Override
58+
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
59+
return fileManager.getJavaFileObjectsFromStrings(names);
60+
}
61+
62+
@Override
63+
public void setLocation(Location location, Iterable<? extends File> path) throws IOException {
64+
fileManager.setLocation(location, path);
65+
}
66+
67+
@Override
68+
public Iterable<? extends File> getLocation(Location location) {
69+
return fileManager.getLocation(location);
70+
}
71+
}

src/main/java/com/google/testing/compile/InMemoryJavaFileManager.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,10 @@
3434
import java.nio.charset.Charset;
3535
import java.util.Map.Entry;
3636
import javax.tools.FileObject;
37-
import javax.tools.ForwardingJavaFileManager;
38-
import javax.tools.JavaFileManager;
3937
import javax.tools.JavaFileObject;
4038
import javax.tools.JavaFileObject.Kind;
4139
import javax.tools.SimpleJavaFileObject;
40+
import javax.tools.StandardJavaFileManager;
4241
import javax.tools.StandardLocation;
4342

4443
/**
@@ -47,7 +46,7 @@
4746
* @author Gregory Kick
4847
*/
4948
// TODO(gak): under java 1.7 this could all be done with a PathFileManager
50-
final class InMemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
49+
final class InMemoryJavaFileManager extends ForwardingStandardJavaFileManager {
5150
private final LoadingCache<URI, JavaFileObject> inMemoryFileObjects =
5251
CacheBuilder.newBuilder().build(new CacheLoader<URI, JavaFileObject>() {
5352
@Override
@@ -56,7 +55,7 @@ public JavaFileObject load(URI key) {
5655
}
5756
});
5857

59-
InMemoryJavaFileManager(JavaFileManager fileManager) {
58+
InMemoryJavaFileManager(StandardJavaFileManager fileManager) {
6059
super(fileManager);
6160
}
6261

src/main/java/com/google/testing/compile/JavaSourcesSubject.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.google.testing.compile.CompilationSubject.DiagnosticOnLine;
4141
import com.google.testing.compile.Parser.ParseResult;
4242
import com.sun.source.tree.CompilationUnitTree;
43+
import java.io.File;
4344
import java.io.IOException;
4445
import java.nio.charset.Charset;
4546
import java.util.ArrayList;
@@ -65,6 +66,7 @@ public final class JavaSourcesSubject
6566
implements CompileTester, ProcessedCompileTesterFactory {
6667
private final List<String> options = new ArrayList<String>(Arrays.asList("-Xlint"));
6768
@Nullable private ClassLoader classLoader;
69+
@Nullable private ImmutableList<File> classPath;
6870

6971
JavaSourcesSubject(FailureMetadata failureMetadata, Iterable<? extends JavaFileObject> subject) {
7072
super(failureMetadata, subject);
@@ -82,12 +84,24 @@ public JavaSourcesSubject withCompilerOptions(String... options) {
8284
return this;
8385
}
8486

87+
/**
88+
* @deprecated prefer {@link #withClasspath(Iterable)}. This method only supports {@link
89+
* URLClassLoader} and the default system classloader, and {@link File}s are usually a more
90+
* natural way to expression compilation classpaths than class loaders.
91+
*/
92+
@Deprecated
8593
@Override
8694
public JavaSourcesSubject withClasspathFrom(ClassLoader classLoader) {
8795
this.classLoader = classLoader;
8896
return this;
8997
}
9098

99+
@Override
100+
public JavaSourcesSubject withClasspath(Iterable<File> classPath) {
101+
this.classPath = ImmutableList.copyOf(classPath);
102+
return this;
103+
}
104+
91105
@Override
92106
public CompileTester processedWith(Processor first, Processor... rest) {
93107
return processedWith(Lists.asList(first, rest));
@@ -312,6 +326,9 @@ private Compilation compilation() {
312326
if (classLoader != null) {
313327
compiler = compiler.withClasspathFrom(classLoader);
314328
}
329+
if (classPath != null) {
330+
compiler = compiler.withClasspath(classPath);
331+
}
315332
return compiler.compile(actual());
316333
}
317334
}
@@ -577,11 +594,22 @@ public JavaSourcesSubject withCompilerOptions(String... options) {
577594
return delegate.withCompilerOptions(options);
578595
}
579596

597+
/**
598+
* @deprecated prefer {@link #withClasspath(Iterable)}. This method only supports {@link
599+
* URLClassLoader} and the default system classloader, and {@link File}s are usually a more
600+
* natural way to expression compilation classpaths than class loaders.
601+
*/
602+
@Deprecated
580603
@Override
581604
public JavaSourcesSubject withClasspathFrom(ClassLoader classLoader) {
582605
return delegate.withClasspathFrom(classLoader);
583606
}
584607

608+
@Override
609+
public JavaSourcesSubject withClasspath(Iterable<File> classPath) {
610+
return delegate.withClasspath(classPath);
611+
}
612+
585613
@Override
586614
public CompileTester processedWith(Processor first, Processor... rest) {
587615
return delegate.newCompilationClause(Lists.asList(first, rest));

0 commit comments

Comments
 (0)