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