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.filemanagers; 017 018import java.io.IOException; 019import java.io.InputStream; 020import java.io.OutputStream; 021import java.io.Reader; 022import java.io.Writer; 023import java.net.URI; 024import java.nio.file.NoSuchFileException; 025import java.nio.file.Path; 026import javax.lang.model.element.Modifier; 027import javax.lang.model.element.NestingKind; 028import javax.tools.FileObject; 029import javax.tools.JavaFileManager.Location; 030import javax.tools.JavaFileObject; 031import org.apiguardian.api.API; 032import org.apiguardian.api.API.Status; 033import org.jspecify.annotations.Nullable; 034 035/** 036 * Interface for a path-based {@link JavaFileObject} that points to a path on a file system 037 * somewhere. 038 * 039 * <p>This object will always use UTF-8 encoding when obtaining readers or writers. 040 * 041 * <p>No access level or nesting kind information is provided by this implementation. 042 * 043 * @author Ashley Scopes 044 * @since 1.0.0 045 */ 046@API(since = "1.0.0", status = Status.STABLE) 047public interface PathFileObject extends JavaFileObject { 048 049 /** 050 * Timestamp that is returned if the file object has never been modified. 051 */ 052 long NOT_MODIFIED = 0L; 053 054 /** 055 * Attempt to delete the file. 056 * 057 * @return {@code true} if the file was deleted, or {@code false} if it was not deleted. 058 */ 059 @Override 060 boolean delete(); 061 062 /** 063 * Determine if this object equals another. 064 * 065 * @param other the other object to compare with. 066 * @return {@code true} if the other object is also a {@link FileObject} and has the same 067 * {@link #toUri() URI} as this object, or {@code false} otherwise. 068 */ 069 @Override 070 boolean equals(@Nullable Object other); 071 072 /** 073 * Get the absolute path of this file object. 074 * 075 * @return the full path. 076 */ 077 Path getAbsolutePath(); 078 079 /** 080 * Get the class access level, where appropriate. 081 * 082 * <p>In most implementations, this class will always return {@code null}, since this 083 * information is not readily available without preloading the file in question and parsing it 084 * first. 085 * 086 * <p>At the time of writing, the OpenJDK implementations of the JavaFileObject class 087 * do not provide an implementation for this method either. 088 * 089 * @return the modifier for the access level, or {@code null} if the information is not available. 090 */ 091 @Nullable 092 @Override 093 default Modifier getAccessLevel() { 094 return null; 095 } 096 097 /** 098 * Get the inferred binary name of the file object. 099 * 100 * @return the inferred binary name. 101 */ 102 String getBinaryName(); 103 104 /** 105 * Read the character content of the file into memory and decode it using the default character 106 * set. 107 * 108 * @param ignoreEncodingErrors ignore encoding errors if {@code true}, or throw them otherwise. 109 * @return the character content, encoded as UTF-8. 110 * @throws IOException if an IO error occurs. 111 */ 112 @Override 113 String getCharContent(boolean ignoreEncodingErrors) throws IOException; 114 115 /** 116 * Get the kind of the file. 117 * 118 * @return the inferred file kind. 119 */ 120 @Override 121 Kind getKind(); 122 123 /** 124 * Determine when the file was last modified. 125 * 126 * @return the timestamp in milliseconds since UNIX epoch that the file was last modified at, or 127 * {@link #NOT_MODIFIED} if unmodified, if the information is not available, or if an error 128 * occurred obtaining the information. 129 */ 130 @Override 131 long getLastModified(); 132 133 /** 134 * Get the location of this path file object. 135 * 136 * @return the location. 137 */ 138 Location getLocation(); 139 140 /** 141 * Get the file name as a string. 142 * 143 * @return the name of the file. 144 */ 145 @Override 146 String getName(); 147 148 /** 149 * Determine the class nesting kind, where appropriate. 150 * 151 * <p>In most implementations, this method will always return {@code null}, since this 152 * information is not readily available without preloading the file in question and parsing it 153 * first. 154 * 155 * <p>At the time of writing, the OpenJDK implementations of the JavaFileObject class 156 * do not provide an implementation for this method either. 157 * 158 * @return the nesting kind, or {@code null} if the information is not available. 159 */ 160 @Nullable 161 @Override 162 default NestingKind getNestingKind() { 163 return null; 164 } 165 166 /** 167 * Get the relative path of this file object. 168 * 169 * @return the path of this file object. 170 */ 171 Path getRelativePath(); 172 173 /** 174 * Get the root path that the package containing this file is nested within. 175 * 176 * @return the root path. 177 */ 178 Path getRootPath(); 179 180 /** 181 * Determine the hash code for this object. 182 * 183 * @return the hash code for the object. 184 */ 185 @Override 186 int hashCode(); 187 188 /** 189 * Determine if a given simple name and file kind are compatible with this file object. 190 * 191 * <p>This will perform a case-sensitive check, regardless of the platform that it runs on. 192 * 193 * @param simpleName the simple name of the class to compare to this file. 194 * @param kind the kind of the class to compare to this file. 195 * @return {@code true} if the simple name and kind are compatible with the current file object 196 * name, or {@code false} if not. 197 */ 198 @Override 199 boolean isNameCompatible(String simpleName, Kind kind); 200 201 /** 202 * Open an input stream into this file. 203 * 204 * <p>This input stream must be closed once finished with, otherwise resources will be leaked. 205 * 206 * <p>The returned implementation will always be buffered when appropriate. 207 * 208 * @return an input stream. 209 * @throws NoSuchFileException if the file does not exist. 210 * @throws IOException if an IO error occurs. 211 */ 212 @Override 213 InputStream openInputStream() throws IOException; 214 215 /** 216 * Open an output stream to this file. 217 * 218 * <p>This will create the file first if it does not already exist. If it does exist, then this 219 * will overwrite the file and truncate it. The parent directories will also be created if they do 220 * not exist. 221 * 222 * <p>This output stream must be closed once finished with, otherwise resources will be leaked. 223 * 224 * <p>The returned implementation will always be buffered when appropriate. 225 * 226 * @return an output stream. 227 * @throws IOException if an IO error occurs. 228 */ 229 @Override 230 OutputStream openOutputStream() throws IOException; 231 232 /** 233 * Open a reader to this file using the default charset (UTF-8). 234 * 235 * <p>This reader must be closed once finished with, otherwise resources will be leaked. 236 * 237 * <p>The returned implementation will always be buffered when appropriate. 238 * 239 * @param ignoreEncodingErrors {@code true} to suppress encoding errors, or {@code false} to throw 240 * them to the caller. 241 * @return a reader. 242 * @throws NoSuchFileException if the file does not exist. 243 * @throws IOException if an IO error occurs. 244 */ 245 @Override 246 Reader openReader(boolean ignoreEncodingErrors) throws IOException; 247 248 /** 249 * Open a writer to this file using the default charset (UTF-8). 250 * 251 * <p>This will create the file first if it does not already exist. If it does exist, this will 252 * first overwrite the file and truncate it. The parent directories will also be created if they 253 * do not exist. 254 * 255 * <p>This input stream must be closed once finished with, otherwise resources will be leaked. 256 * 257 * <p>The returned implementation will always be buffered when appropriate. 258 * 259 * @return a writer. 260 * @throws IOException if an IO error occurs. 261 */ 262 @Override 263 Writer openWriter() throws IOException; 264 265 /** 266 * Get a string representation of this object. 267 * 268 * @return a string representation of this object. 269 */ 270 @Override 271 String toString(); 272 273 /** 274 * Determine the URI for this file. 275 * 276 * @return the URI for this file object. 277 */ 278 @Override 279 URI toUri(); 280}