@Throws在目标是属性时不起作用

在看这个问题的时候 ,我注意到将@Throws应用到getset use-site没有任何作用。

此外, @Throws 的唯一有效目标AnnotationTarget.FUNCTIONAnnotationTarget.PROPERTY_GETTERAnnotationTarget.PROPERTY_SETTERAnnotationTarget.CONSTRUCTOR

其他注释,如JPA批注和Deprecated工作正常,并适用于该方法!

这是奇怪的行为。

为了演示,我用Java创建了一个简单的抽象类,有一个构造函数,一个方法和一个get方法。

 public abstract class JavaAbstractClass { @Deprecated @NotNull public abstract String getString() throws IOException; public abstract void setString(@NotNull String string) throws IOException; public abstract void throwsFunction() throws IOException; public JavaAbstractClass() throws IOException { } } 

正如你所看到的,每个方法/构造函数都被标记为抛出IOException

但是,当我尝试在Kotlin中编写一个等同的类,并用互斥标记相应的方法时,生成的getStringsetString方法没有throws子句。

 abstract class KotlinAbstractClass @Throws(IOException::class) constructor() { @get:Deprecated("Deprecated") @get:Throws(IOException::class) @set:Throws(IOException::class) abstract var string: String @Throws(IOException::class) abstract fun throwsFunction() } 

反编译的代码:

 @Metadata(Some metadata here) public abstract class KotlinAbstractClass { /** @deprecated */ @Deprecated( message = "Deprecated" ) // @Deprecated made it through! @NotNull public abstract String getString(); // Nothing here! public abstract void setString(@NotNull String var1); // Nothing here! public abstract void throwsFunction() throws IOException; public KotlinAbstractClass() throws IOException { } } 

对我来说,这似乎是因为这些内部注释必须由编译器专门处理,而不是直接应用于该方法。

此外,将其应用于非抽象属性的getter:

 val string: String @Throws(IOException::class) get() = "Foo" 

生成一个方法与签名public final String getString() throws IOException

也许这个案子处理不好?

这是一个错误?


注意:这与方法是否实际引发此exception没有任何关系。

如果我做:

 @get:Throws(IOException::class) val string: String get() = BufferedReader(FileReader("file.txt")).readText() 

编译的代码仍然是

 @NotNull public final String getString() { return TextStreamsKt.readText((Reader)(new BufferedReader((Reader)(new FileReader("file.txt"))))); } 

尽管FileReader构造函数抛出FileNotFoundException

另外,对于抽象方法来说,这应该不是问题,因为它们不能实现,并且还可以有一个throws子句。

如果我这样做@tynn建议并添加一个具体的实现:

 class ConcreteClass : KotlinAbstractClass() { override val string: String get() = BufferedReader(FileReader("file.txt")).readText() ... } 

我仍然得到相同的结果。

我相信@tynn建议你做以下几点:

 override val string: String @Throws(FileNotFoundException::class) get() = BufferedReader(FileReader("file.txt")).readText() 

这应该给你签名中的适当的Java版本。 我猜的原因是,如果你只是这样做:

 @get:Throws(IOException::class) val foo: String = "foo" 

编译器足够聪明,可以看到getter中没有任何东西会抛出IOException ,因为你从来没有重写它,所以它不会产生throws部分。 当getter被覆盖时,编译器无法知道你提供的代码是否可以抛出,所以它遵从注释,并总是输出throws部分。

UPDATE

以下似乎生成正确的字节码:

 abstract class KotlinAbstractClass { abstract var string: String @Throws(IOException::class) get @Throws(IOException::class) set } 

仔细看后,我发现@get:Throws(IOException::class)没有理由@get:Throws(IOException::class)在这种情况下不起作用。 您可能会针对Kotlin的YouTrack提出问题,并查看团队成员对此有何评论。

Interesting Posts