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