1
2
3
4
5
6 package gov.nist.secauto.metaschema.databind.codegen;
7
8 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
9
10 import org.apache.logging.log4j.LogManager;
11 import org.apache.logging.log4j.Logger;
12
13 import java.io.IOException;
14 import java.io.Writer;
15 import java.nio.file.Path;
16 import java.util.LinkedHashSet;
17 import java.util.LinkedList;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.stream.Collectors;
21
22 import javax.tools.DiagnosticCollector;
23 import javax.tools.JavaCompiler;
24 import javax.tools.JavaFileObject;
25 import javax.tools.StandardJavaFileManager;
26 import javax.tools.ToolProvider;
27
28 import edu.umd.cs.findbugs.annotations.NonNull;
29 import edu.umd.cs.findbugs.annotations.Nullable;
30
31 public class JavaCompilerSupport {
32 private static final Logger LOGGER = LogManager.getLogger(JavaCompilerSupport.class);
33
34 @NonNull
35 private final Path classDir;
36 @NonNull
37 private final Set<String> classPath = new LinkedHashSet<>();
38 @NonNull
39 private final Set<String> modulePath = new LinkedHashSet<>();
40 @NonNull
41 private final Set<String> rootModuleNames = new LinkedHashSet<>();
42
43 public JavaCompilerSupport(@NonNull Path classDir) {
44 this.classDir = classDir;
45 }
46
47 public Set<String> getClassPath() {
48 return classPath;
49 }
50
51 public Set<String> getModulePath() {
52 return modulePath;
53 }
54
55 public Set<String> getRootModuleNames() {
56 return rootModuleNames;
57 }
58
59 public void addToClassPath(@NonNull String entry) {
60 classPath.add(entry);
61 }
62
63 public void addToModulePath(@NonNull String entry) {
64 modulePath.add(entry);
65 }
66
67 public void addRootModule(@NonNull String entry) {
68 rootModuleNames.add(entry);
69 }
70
71 @NonNull
72 protected List<String> generateCompilerOptions() {
73 List<String> options = new LinkedList<>();
74
75
76 options.add("-d");
77 options.add(classDir.toString());
78
79 if (!classPath.isEmpty()) {
80 options.add("-classpath");
81 options.add(classPath.stream()
82 .collect(Collectors.joining(":")));
83 }
84
85 if (!modulePath.isEmpty()) {
86 options.add("-p");
87 options.add(modulePath.stream()
88 .collect(Collectors.joining(":")));
89 }
90
91 return options;
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 public CompilationResult compile(@NonNull List<Path> classFiles, @Nullable Writer compileOut) throws IOException {
112 DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
113
114 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
115
116 List<JavaFileObject> compilationUnits;
117 try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) {
118
119 compilationUnits = classFiles.stream()
120 .map(fileManager::getJavaFileObjects)
121 .map(CollectionUtil::toList)
122 .flatMap(List::stream)
123 .collect(Collectors.toUnmodifiableList());
124
125 List<String> options = generateCompilerOptions();
126
127 if (LOGGER.isDebugEnabled()) {
128 LOGGER.atDebug().log("Using options: {}", options);
129 }
130
131 JavaCompiler.CompilationTask task = compiler.getTask(
132 compileOut,
133 fileManager,
134 diagnostics,
135 options,
136 null,
137 compilationUnits);
138
139 task.addModules(rootModuleNames);
140
141 return new CompilationResult(task.call(), diagnostics);
142 }
143 }
144
145 public static final class CompilationResult {
146 private final boolean successful;
147 @NonNull
148 private final DiagnosticCollector<JavaFileObject> diagnostics;
149
150 private CompilationResult(boolean successful, @NonNull DiagnosticCollector<JavaFileObject> diagnostics) {
151 this.successful = successful;
152 this.diagnostics = diagnostics;
153 }
154
155 public boolean isSuccessful() {
156 return successful;
157 }
158
159 public DiagnosticCollector<?> getDiagnostics() {
160 return diagnostics;
161 }
162 }
163 }