Writer
或OutputStream
的close
方法写入文件内容后,由工具在后续的处理轮次中进行处理。区分三种类型的文件:源文件、类文件和辅助资源文件。
新创建的文件将被放置在两个支持的特定位置(逻辑文件系统中的子树):一个用于新源文件,一个用于新类文件。 (例如,可以在工具的命令行上指定这些位置,使用诸如-s
和-d
的标志。)实际的新源文件和新类文件的位置在特定运行中可能是相同的,也可能是不同的。资源文件可以在任一位置创建。读取和写入资源的方法接受一个相对名称参数。相对名称是由'/'
分隔的非空路径段序列;'.'
和'..'
是无效的路径段。有效的相对名称必须符合RFC 3986第3.3节的“path-rootless”规则。
文件创建方法接受可变数量的参数,以允许提供“起始元素”作为提示,以便工具基础设施更好地管理依赖关系。起始元素是导致注解处理器尝试创建新文件的类、接口、包(代表package-info
文件)或模块(代表module-info
文件)。换句话说,起始元素的粒度应该是“编译单元”(JLS第7.3节)的粒度,基本上是文件级别的粒度,而不是方法或字段声明等更细粒度的粒度。
例如,如果注解处理器尝试创建一个名为GeneratedFromUserSource
的源文件,以响应处理
则应将@Generate public class UserSource {}
UserSource
的类型元素作为创建方法调用的一部分传递,如下所示:
如果没有起始元素,则无需传递。此信息可用于增量环境中确定重新运行处理器或删除生成文件的需要。非增量环境可能会忽略起始元素信息。filer.createSourceFile("GeneratedFromUserSource", eltUtils.getTypeElement("UserSource"));
在注解处理工具的每次运行中,给定路径名的文件只能创建一次。如果在第一次尝试创建文件之前该文件已经存在,则将删除旧内容。在运行期间的任何后续尝试创建相同文件都将抛出一个FilerException
,尝试为相同类型名称或相同包名称创建类文件和源文件也将抛出异常。工具的初始输入被视为由第零轮创建;因此,尝试创建与这些输入对应的源文件或类文件将导致FilerException
。
一般来说,处理器不应故意尝试覆盖不是由某个处理器生成的现有文件。Filer
可能会拒绝尝试打开与现有类或接口对应的文件,例如java.lang.Object
。同样,注解处理工具的调用者不应故意配置工具,使得发现的处理器尝试覆盖不是由其生成的现有文件。
如果环境配置支持,处理器可以通过包含Generated
注解来指示源文件或类文件是由注解处理生成的,如果环境配置使得该类或接口可访问。
- API 注意:
- 通过使用装饰器样式模式可以实现覆盖文件的某些效果。不直接修改类,而是设计类,使得其超类由注解处理生成,或者类的子类由注解处理生成。如果生成子类,则父类可以设计为使用工厂而不是公共构造函数,以便只向父类的客户端呈现子类实例。
- 自版本:
- 1.6
- 外部规范
-
Method Summary
Modifier and TypeMethodDescriptioncreateClassFile
(CharSequence name, Element... originatingElements) 创建一个新的类文件,并返回一个对象以允许对其进行写入。createResource
(JavaFileManager.Location location, CharSequence moduleAndPkg, CharSequence relativeName, Element... originatingElements) 创建一个新的辅助资源文件以供写入,并返回一个文件对象。createSourceFile
(CharSequence name, Element... originatingElements) 创建一个新的源文件,并返回一个对象以允许对其进行写入。getResource
(JavaFileManager.Location location, CharSequence moduleAndPkg, CharSequence relativeName) 返回一个用于读取现有资源的对象。
-
Method Details
-
createSourceFile
JavaFileObject createSourceFile(CharSequence name, Element... originatingElements) throws IOException 创建一个新的源文件,并返回一个对象以允许对其进行写入。可以创建一个用于类、接口或包的源文件。文件的名称和路径(相对于源文件的根输出位置)基于要在该文件中声明的项目的名称以及项目的指定模块(如果有)。如果在单个文件中声明多个类或接口(即单个编译单元),则文件的名称应与主要顶级类或接口的名称对应(例如,公共类)。还可以创建一个用于保存有关包信息的源文件,包括包注解。要为命名包创建源文件,将
name
参数设置为包名称后跟".package-info"
;要为未命名包创建源文件,请使用"package-info"
。可选的模块名称前缀为类型名称或包名称,并使用“
/
”字符分隔。例如,要在模块foo
中为类a.B
创建源文件,请使用name
参数"foo/a.B"
。如果未给出显式模块前缀,并且环境支持模块,则会推断出适当的模块。如果无法推断出适当的模块,则会抛出
FilerException
。实现可能会使用有关注解处理工具配置的信息作为推断的一部分。在命名模块中或为未命名包创建源文件是不受支持的。
如果环境配置支持未命名类PREVIEW,则使用名称参数提供输出文件名称的前导组件。例如,
filer.createSourceFile("Foo")
用于创建托管在Foo.java
中的未命名类。所有未命名类必须位于未命名包中。- API 注意:
-
要使用特定的字符集对文件内容进行编码,可以从返回对象的
OutputStream
创建具有所选字符集的OutputStreamWriter
。如果直接使用返回对象的Writer
进行写入,则其字符集由实现确定。注解处理工具可能具有用于指定此选项的-encoding
标志或类似选项;否则,通常为平台的默认编码。为避免后续错误,源文件的内容应与此次运行所使用的源版本兼容。
- 实现注意:
-
在参考实现中,如果注解处理工具正在处理单个模块M,则对于没有显式模块前缀创建的文件,将使用M作为模块。如果工具正在处理多个模块,并且
Elements.getPackageElement(package-of(name))
返回一个包,则将使用拥有返回包的模块作为目标模块。如果无法使用上述规则确定目标模块,则可以使用单独的选项提供目标模块。 - 参数:
-
name
- 此文件中声明的主要类或接口的规范(完全限定)名称,或包名称后跟".package-info"
以用于包信息文件 -
originatingElements
- 与此文件创建相关联的类、接口、包或模块元素,可以省略或为null
- 返回:
-
一个
JavaFileObject
,用于写入新源文件 - 抛出:
-
FilerException
- 如果已经创建了相同的路径名,已经创建了相同的类或接口,名称对于请求创建的实体无效,无法确定目标模块,目标模块不可写入,或者在环境不支持模块的情况下指定了模块。 -
IOException
- 如果无法创建文件 - 参见Java语言规范:
-
7.3 编译单元
-
createClassFile
JavaFileObject createClassFile(CharSequence name, Element... originatingElements) throws IOException 创建一个新的类文件,并返回一个对象,允许向其写入。可以创建用于类、接口或包的类文件。文件的名称和路径(相对于类文件的根输出位置)基于要声明为的项的名称以及该项的指定模块(如果有)。也可以创建一个用于保存有关包信息的类文件,包括包注解。要创建一个命名包的类文件,将
name
参数设置为包名后跟".package-info"
;不支持为无名称的包创建类文件。可选的模块名称前缀于类型名称或包名称之前,并使用"
/
"字符分隔。例如,要在模块foo
中为类a.B
创建一个类文件,使用name
参数"foo/a.B"
。如果未提供显式模块前缀并且环境支持模块,则会推断适当的模块。如果无法推断出适当的模块,则会抛出
FilerException
。实现可能会使用有关注解处理工具配置的信息作为推断的一部分。在具名模块中为无名称包中的类文件创建或用于创建的类文件不受支持。
如果环境配置为支持无名称类PREVIEW,则名称参数用于提供用于输出文件的名称的前导组件。例如,
filer.createClassFile("Foo")
用于创建托管在Foo.class
中的无名称类。所有无名称类必须位于无名称包中。- API 注意:
- 为避免后续错误,类文件的内容应与此运行所使用的源版本兼容。
- 实现注意:
-
在参考实现中,如果注解处理工具正在处理单个模块M,则将M用作创建没有显式模块前缀的文件的模块。如果工具正在处理多个模块,并且
Elements.getPackageElement(package-of(name))
返回一个包,则将拥有返回的包的模块用作目标模块。如果无法使用上述规则确定目标模块,则可以使用单独的选项提供目标模块。 - 参数:
-
name
- 要写入的类或接口的二进制名称或包名称后跟".package-info"
以获取包信息文件 -
originatingElements
- 与创建此文件有因果关系的类、接口、包或模块元素,可以省略或为null
- 返回:
-
用于写入新类文件的
JavaFileObject
- 抛出:
-
FilerException
- 如果已创建相同的路径名、已创建相同的类或接口、名称对于类或接口无效、无法确定目标模块、目标模块不可写入,或在环境不支持模块时指定了模块。 -
IOException
- 如果无法创建文件
-
createResource
FileObject createResource(JavaFileManager.Location location, CharSequence moduleAndPkg, CharSequence relativeName, Element... originatingElements) throws IOException 创建一个新的辅助资源文件以进行写入,并返回一个文件对象。该文件可以位于新创建的源文件、新创建的二进制文件或其他支持的位置之间。必须支持位置CLASS_OUTPUT
和SOURCE_OUTPUT
。资源可以相对于某个模块和/或包(如源文件和类文件)命名,然后通过相对路径名。从宽泛意义上讲,新文件的完整路径名将是location
、moduleAndPkg
和relativeName
的连接。如果moduleAndPkg
包含"/
"字符,则"/
"字符之前的前缀是模块名称,"/
"字符之后的后缀是包名称。包后缀可能为空。如果moduleAndPkg
不包含"/
"字符,则整个参数被解释为包名称。如果给定的位置既不是面向模块的位置,也不是包含多个模块的输出位置,并且提供了显式模块前缀,则抛出
FilerException
。如果给定的位置是面向模块的位置或包含多个模块的输出位置,并且未提供显式模块前缀,则会推断适当的模块。如果无法推断出适当的模块,则会抛出
FilerException
。实现可能会使用有关注解处理工具配置的信息作为推断的一部分。- 实现注意:
-
在参考实现中,如果注解处理工具正在处理单个模块M,则将M用作创建没有显式模块前缀的文件的模块。如果工具正在处理多个模块,并且
Elements.getPackageElement(package-of(name))
返回一个包,则将拥有返回的包的模块用作目标模块。如果无法使用上述规则确定目标模块,则可以使用单独的选项提供目标模块。 - 参数:
-
location
- 新文件的位置 -
moduleAndPkg
- 相对于其应命名文件的模块和/或包,如果没有则为空字符串 -
relativeName
- 文件的最终路径名组件 -
originatingElements
- 与创建此文件有因果关系的类、接口、包或模块元素,可以省略或为null
- 返回:
-
用于写入新资源的
FileObject
- 抛出:
-
IOException
- 如果无法创建文件 -
FilerException
- 如果已创建相同的路径名、无法确定目标模块、目标模块不可写入,或者如果指定了显式目标模块且位置不支持它。 -
IllegalArgumentException
- 对于不支持的位置 -
IllegalArgumentException
- 如果moduleAndPkg
格式不正确 -
IllegalArgumentException
- 如果relativeName
不是相对的
-
getResource
FileObject getResource(JavaFileManager.Location location, CharSequence moduleAndPkg, CharSequence relativeName) throws IOException 返回一个用于读取现有资源的对象。必须支持位置CLASS_OUTPUT
和SOURCE_OUTPUT
。如果
moduleAndPkg
包含"/
"字符,则"/
"字符之前的前缀是模块名称,"/
"字符之后的后缀是包名称。包后缀可能为空;但是,如果存在模块名称,则必须为非空。如果moduleAndPkg
不包含"/
"字符,则整个参数被解释为包名称。如果给定的位置既不是面向模块的位置,也不是包含多个模块的输出位置,并且提供了显式模块前缀,则抛出
FilerException
。如果给定的位置是面向模块的位置或包含多个模块的输出位置,并且未提供显式模块前缀,则会推断适当的模块。如果无法推断出适当的模块,则会抛出
FilerException
。实现可能会使用有关注解处理工具配置的信息作为推断的一部分。- 实现注意事项:
-
在参考实现中,如果注解处理工具正在处理单个模块 M,那么将使用 M 作为没有显式模块前缀的文件的模块。如果工具正在处理多个模块,并且
Elements.getPackageElement(package-of(name))
返回一个包,则使用拥有返回的包的模块作为源模块。如果无法使用上述规则确定目标模块,则可以使用单独的选项提供目标模块。 - 参数:
-
location
- 文件的位置 -
moduleAndPkg
- 相对于其应该搜索文件的模块和/或包,如果没有则为空字符串 -
relativeName
- 文件的最终路径名组件 - 返回:
- 用于读取文件的对象
- 抛出:
-
FilerException
- 如果相同的路径名已经被打开进行写入,如果无法确定源模块,或者目标模块不可写,或者指定了显式目标模块且位置不支持它 -
IOException
- 如果无法打开文件 -
IllegalArgumentException
- 对于不受支持的位置 -
IllegalArgumentException
- 如果moduleAndPkg
格式不正确 -
IllegalArgumentException
- 如果relativeName
不是相对的
-