001/* 002 * Copyright (C) 2022 - 2023, 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 or if the information is not available. 128 */ 129 @Override 130 long getLastModified(); 131 132 /** 133 * Get the location of this path file object. 134 * 135 * @return the location. 136 */ 137 Location getLocation(); 138 139 /** 140 * Get the file name as a string. 141 * 142 * @return the name of the file. 143 */ 144 @Override 145 String getName(); 146 147 /** 148 * Determine the class nesting kind, where appropriate. 149 * 150 * <p>In most implementations, this method will always return {@code null}, since this 151 * information is not readily available without preloading the file in question and parsing it 152 * first. 153 * 154 * <p>At the time of writing, the OpenJDK implementations of the JavaFileObject class 155 * do not provide an implementation for this method either. 156 * 157 * @return the nesting kind, or {@code null} if the information is not available. 158 */ 159 @Nullable 160 @Override 161 default NestingKind getNestingKind() { 162 return null; 163 } 164 165 /** 166 * Get the relative path of this file object. 167 * 168 * @return the path of this file object. 169 */ 170 Path getRelativePath(); 171 172 /** 173 * Get the root path that the package containing this file is nested within. 174 * 175 * @return the root path. 176 */ 177 Path getRootPath(); 178 179 /** 180 * Determine the hash code for this object. 181 * 182 * @return the hash code for the object. 183 */ 184 @Override 185 int hashCode(); 186 187 /** 188 * Determine if a given simple name and file kind are compatible with this file object. 189 * 190 * <p>This will perform a case-sensitive check, regardless of the platform that it runs on. 191 * 192 * @param simpleName the simple name of the class to compare to this file. 193 * @param kind the kind of the class to compare to this file. 194 * @return {@code true} if the simple name and kind are compatible with the current file object 195 * name, or {@code false} if not. 196 */ 197 @Override 198 boolean isNameCompatible(String simpleName, Kind kind); 199 200 /** 201 * Open an input stream into this file. 202 * 203 * <p>This input stream must be closed once finished with, otherwise resources will be leaked. 204 * 205 * <p>The returned implementation will always be buffered when appropriate. 206 * 207 * @return an input stream. 208 * @throws NoSuchFileException if the file does not exist. 209 * @throws IOException if an IO error occurs. 210 */ 211 @Override 212 InputStream openInputStream() throws IOException; 213 214 /** 215 * Open an output stream to this file. 216 * 217 * <p>This will create the file first if it does not already exist. If it does exist, then this 218 * will overwrite the file and truncate it. The parent directories will also be created if they do 219 * not exist. 220 * 221 * <p>This output stream must be closed once finished with, otherwise resources will be leaked. 222 * 223 * <p>The returned implementation will always be buffered when appropriate. 224 * 225 * @return an output stream. 226 * @throws IOException if an IO error occurs. 227 */ 228 @Override 229 OutputStream openOutputStream() throws IOException; 230 231 /** 232 * Open a reader to this file using the default charset (UTF-8). 233 * 234 * <p>This reader must be closed once finished with, otherwise resources will be leaked. 235 * 236 * <p>The returned implementation will always be buffered when appropriate. 237 * 238 * @param ignoreEncodingErrors {@code true} to suppress encoding errors, or {@code false} to throw 239 * them to the caller. 240 * @return a reader. 241 * @throws NoSuchFileException if the file does not exist. 242 * @throws IOException if an IO error occurs. 243 */ 244 @Override 245 Reader openReader(boolean ignoreEncodingErrors) throws IOException; 246 247 /** 248 * Open a writer to this file using the default charset (UTF-8). 249 * 250 * <p>This will create the file first if it does not already exist. If it does exist, this will 251 * first overwrite the file and truncate it. The parent directories will also be created if they 252 * do not exist. 253 * 254 * <p>This input stream must be closed once finished with, otherwise resources will be leaked. 255 * 256 * <p>The returned implementation will always be buffered when appropriate. 257 * 258 * @return a writer. 259 * @throws IOException if an IO error occurs. 260 */ 261 @Override 262 Writer openWriter() throws IOException; 263 264 /** 265 * Get a string representation of this object. 266 * 267 * @return a string representation of this object. 268 */ 269 @Override 270 String toString(); 271 272 /** 273 * Determine the URI for this file. 274 * 275 * @return the URI for this file object. 276 */ 277 @Override 278 URI toUri(); 279}