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