当目标是属性时,@ Thhrows无效

时间:2017-12-10 09:46:53

标签: java annotations jvm kotlin throws

在查看this question时,我发现将@Throws应用于getset使用网站无效。

此外, @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中编写一个等效的类,并使用throws标记适当的方法进行互操作时,生成的getStringsetString方法没有{{1}条款。

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()

}

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

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

@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 {
   }
}

生成一个带有签名val string: String @Throws(IOException::class) get() = "Foo" 的方法!

也许这个案子没有得到妥善处理?

这是一个错误吗?

注意:这与方法是否实际抛出此异常没有任何关系。

如果我这样做:

public final String getString() throws IOException

编译的代码仍然是

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

尽管FileReader constructor引发了@NotNull public final String getString() { return TextStreamsKt.readText((Reader)(new BufferedReader((Reader)(new FileReader("file.txt"))))); }

此外,这对抽象方法无关紧要,因为它们不能有实现,但仍然可以有FileNotFoundException子句。

如果我按@tynn建议并添加具体实现:

throws

我仍然得到相同的结果。

1 个答案:

答案 0 :(得分:2)

我相信@tynn建议您执行以下操作:

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

这应该会在签名中为您提供正确的Java版本throws。我想推理的原因是,如果你这样做:

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

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

<强>更新

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

throws

仔细观察后,我认为abstract class KotlinAbstractClass { abstract var string: String @Throws(IOException::class) get @Throws(IOException::class) set } 没有理由不在这种情况下工作。您可以在YouTrack for Kotlin上提出问题,看看团队成员对此有何看法。