001/* 002 * Copyright (C) 2022 - 2024, the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.github.ascopes.jct.compilers; 017 018import io.github.ascopes.jct.containers.ModuleContainerGroup; 019import io.github.ascopes.jct.containers.OutputContainerGroup; 020import io.github.ascopes.jct.containers.PackageContainerGroup; 021import io.github.ascopes.jct.diagnostics.TraceDiagnostic; 022import io.github.ascopes.jct.filemanagers.JctFileManager; 023import java.util.List; 024import java.util.Set; 025import javax.tools.JavaFileObject; 026import javax.tools.StandardLocation; 027import org.apiguardian.api.API; 028import org.apiguardian.api.API.Status; 029import org.jspecify.annotations.Nullable; 030 031/** 032 * The result of a compilation. 033 * 034 * <p>This provides access to a number of useful pieces of information 035 * including the file manager used for the compilation, compiler logs, 036 * and diagnostics. 037 * 038 * @author Ashley Scopes 039 * @since 0.0.1 040 */ 041@API(since = "0.0.1", status = Status.STABLE) 042public interface JctCompilation { 043 044 /** 045 * Get the command line arguments that were passed to the compiler. 046 * 047 * @return the command line arguments. 048 */ 049 @API(since = "0.5.0", status = Status.STABLE) 050 List<String> getArguments(); 051 052 /** 053 * Determine if warnings were treated as errors. 054 * 055 * @return {@code true} if warnings were treated as errors, or {@code false} otherwise. 056 */ 057 boolean isFailOnWarnings(); 058 059 /** 060 * Determine if the compilation was successful or not. 061 * 062 * @return {@code true} if successful, or {@code false} if not successful. 063 */ 064 boolean isSuccessful(); 065 066 /** 067 * Determine if the compilation was a failure or not. 068 * 069 * @return {@code true} if not successful, or {@code false} if successful. 070 */ 071 default boolean isFailure() { 072 return !isSuccessful(); 073 } 074 075 /** 076 * Get the lines of output produced by the compiler, if any were captured. 077 * 078 * <p>This is separate to diagnostics. 079 * 080 * @return the lines of output. 081 */ 082 List<String> getOutputLines(); 083 084 /** 085 * Get the compilation units used in the compilation. 086 * 087 * @return the compilation units. 088 */ 089 Set<JavaFileObject> getCompilationUnits(); 090 091 /** 092 * Get the diagnostics that were reported by the compilation, in the order that they 093 * were reported. 094 * 095 * @return the diagnostics 096 */ 097 List<TraceDiagnostic<JavaFileObject>> getDiagnostics(); 098 099 /** 100 * Get the file manager that was used to store and manage files. 101 * 102 * <p>This can be used to obtain a classloader for any compiled sources, 103 * which can then be used to reflectively test what the compiler produced. 104 * 105 * @return the file manager. 106 */ 107 JctFileManager getFileManager(); 108 109 /** 110 * Get the output container group for class outputs. 111 * 112 * <p>This usually consists of any {@code *.class} files produced by the compiler, 113 * and is equivalent to {@code target/classes} in a Maven project. 114 * 115 * @return the output container group, or {@code null} if it does not exist. 116 */ 117 @Nullable 118 default OutputContainerGroup getClassOutputs() { 119 return getFileManager().getOutputContainerGroup(StandardLocation.CLASS_OUTPUT); 120 } 121 122 /** 123 * Get the output container group for source outputs. 124 * 125 * <p>This consists of any generated source code created by annotation processors, 126 * and is equivalent to {@code target/generated-sources} in a Maven project. 127 * 128 * @return the output container group, or {@code null} if it does not exist. 129 */ 130 @Nullable 131 default OutputContainerGroup getSourceOutputs() { 132 return getFileManager().getOutputContainerGroup(StandardLocation.SOURCE_OUTPUT); 133 } 134 135 /** 136 * Get the package container group for the class path. 137 * 138 * <p>This represents the class path used for compilation. 139 * 140 * @return the package container group, or {@code null} if it does not exist. 141 */ 142 @Nullable 143 default PackageContainerGroup getClassPath() { 144 return getFileManager().getPackageContainerGroup(StandardLocation.CLASS_PATH); 145 } 146 147 /** 148 * Get the package container group for the source path. 149 * 150 * <p>This is equivalent to {@code src/main/java} and {@code src/main/resources} 151 * in a Maven project. 152 * 153 * @return the package container group, or {@code null} if it does not exist. 154 */ 155 @Nullable 156 default PackageContainerGroup getSourcePath() { 157 return getFileManager().getPackageContainerGroup(StandardLocation.SOURCE_PATH); 158 } 159 160 /** 161 * Get the package container group for the annotation processor path. 162 * 163 * @return the package container group, or {@code null} if it does not exist. 164 */ 165 @Nullable 166 default PackageContainerGroup getAnnotationProcessorPath() { 167 return getFileManager().getPackageContainerGroup(StandardLocation.ANNOTATION_PROCESSOR_PATH); 168 } 169 170 /** 171 * Get the module container group for the annotation processor module path. 172 * 173 * @return the module container group, or {@code null} if it does not exist. 174 */ 175 @Nullable 176 default ModuleContainerGroup getAnnotationProcessorModulePath() { 177 return getFileManager() 178 .getModuleContainerGroup(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH); 179 } 180 181 /** 182 * Get the package container group for the platform class path (a.k.a. the bootstrap class path). 183 * 184 * <p>You generally do not need to use this. The platform class path mechanism has been mostly 185 * replaced by the use of the system modules path as of Java 11. It is simply provided for 186 * backwards compatibility. 187 * 188 * @return the package container group, or {@code null} if it does not exist. 189 */ 190 @Nullable 191 default PackageContainerGroup getPlatformClassPath() { 192 return getFileManager().getPackageContainerGroup(StandardLocation.PLATFORM_CLASS_PATH); 193 } 194 195 /** 196 * Get the output container group for the native header file outputs. 197 * 198 * <p>If you invoke {@code javac} with the {@code -H} flag, then this represents the 199 * directory that C/C++ header file stubs for JNI are written to. 200 * 201 * @return the output container group, or {@code null} if it does not exist. 202 */ 203 @Nullable 204 default OutputContainerGroup getNativeHeaderOutputs() { 205 return getFileManager().getOutputContainerGroup(StandardLocation.NATIVE_HEADER_OUTPUT); 206 } 207 208 /** 209 * Get the module container group for the module source path. 210 * 211 * <p>Many build tools do not provide a direct equivalent of this mechanism as of now, but 212 * this is a source path introduced in Java 9 that allows specifying multiple named JPMS 213 * modules to compile under a single compilation invocation. 214 * 215 * <p>For example, you may use this in a project to compile an API module, a default 216 * implementation module, and a module containing unit tests all together. 217 * 218 * @return the module container group, or {@code null} if it does not exist. 219 */ 220 @Nullable 221 default ModuleContainerGroup getModuleSourcePath() { 222 return getFileManager().getModuleContainerGroup(StandardLocation.MODULE_SOURCE_PATH); 223 } 224 225 /** 226 * Get the module container group for the upgrade module path. 227 * 228 * <p>You generally will not need to use this, as this is a mechanism used to upgrade 229 * modules in-place incrementally with fixes without redistributing the entire application. 230 * 231 * @return the module container group, or {@code null} if it does not exist. 232 */ 233 @Nullable 234 default ModuleContainerGroup getUpgradeModulePath() { 235 return getFileManager().getModuleContainerGroup(StandardLocation.UPGRADE_MODULE_PATH); 236 } 237 238 /** 239 * Get the module container group for all system modules that are part of the JDK distribution. 240 * 241 * <p>This will usually just point to the Java standard library. 242 * 243 * @return the module container group, or {@code null} if it does not exist. 244 */ 245 @Nullable 246 default ModuleContainerGroup getSystemModules() { 247 return getFileManager().getModuleContainerGroup(StandardLocation.SYSTEM_MODULES); 248 } 249 250 /** 251 * Get the module container group for the module path. 252 * 253 * <p>This is equivalent to the class path, but holds any JPMS modules. 254 * 255 * @return the module container group, or {@code null} if it does not exist. 256 */ 257 @Nullable 258 default ModuleContainerGroup getModulePath() { 259 return getFileManager().getModuleContainerGroup(StandardLocation.MODULE_PATH); 260 } 261 262 /** 263 * Get the module container group for the patch module path. 264 * 265 * <p>You generally will not need to use this. It consists of patchable module sources that 266 * can be used to inject additional classes into a module. This can be used for cases like 267 * unit tests where you wish to embed the unit test classes into the existing application 268 * module to exploit features such as package private access. 269 * 270 * @return the module container group, or {@code null} if it does not exist. 271 */ 272 @Nullable 273 default ModuleContainerGroup getPatchModulePath() { 274 return getFileManager().getModuleContainerGroup(StandardLocation.PATCH_MODULE_PATH); 275 } 276}