Search code examples
javakotlinrmi

How to specify @Throws for a property in interface


I am currently porting some Java RMI code to Kotlin. The legacy interface in Java is:

interface Foo: Remote {
    Bar getBar() throws RemoteException
}

After running the auto-migration tool, the field bar is changed into a property:

interface Foo: Remote {
    val bar: Bar
}

However, in the migrated program, getBar is no longer marked as throws RemoteException, which causes illegal remote method encountered error in a RMI call.

I was wondering is there any way to mark @Throws for a property?


Solution

  • Well, if you look at @Throws:

    If there is a specific getter that does not use the backing field, simply annotate it directly:

    val bar: Bar
        @Throws(RemoteException::class) get() = doSomething()
    

    The valid targets for @Throws are

    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER,
    AnnotationTarget.CONSTRUCTOR
    

    So in other cases, you need to target the getter itself and not the property:

    @get:Throws(RemoteException::class)
    

    The full list of supported use-site targets is:

    • file;
    • property (annotations with this target are not visible to Java);
    • field;
    • get (property getter);
    • set (property setter);
    • receiver (receiver parameter of an extension function or property);
    • param (constructor parameter);
    • setparam (property setter parameter);
    • delegate (the field storing the delegate instance for a delegated property).

    @get specifies that this annotation will be applied to the getter.

    Your full interface would be

    interface Foo: Remote {
        @get:Throws(RemoteException::class)
        val bar: Bar
    }
    

    Here's a problem though - in the generated code, there is no throws clause generated. I feel like this may be a bug, as the annotation is clearly marked as targeting these four use-sites. CONSTRUCTOR and FUNCTION definitely work, it's just the property ones that have none generated.


    I took a look at the Kotlin compiler trying to find a possible reason, and I found this:

    interface ReplStateFacade : Remote {
    
        @Throws(RemoteException::class)
        fun getId(): Int
    
        ...
    }
    

    Which interestingly avoids properties in order to use @Throws. Maybe this is a known workaround?