Kotlin annotation not in fieldDecleration or compiled java

Sjenkie :

For my data objects in Kotlin I have added a custom annotation for GSON to have an exclusion rule.

In the past this has worked perfectly, now it does not show up in my class reflection (this.javaClass.declaredFields[3].annotations is null) nor does it show up in the compiled java output.

I have tried different things, like upgrading my kotlin version, adding kotlin-kapt, using different @Retention types, restarting my computer (you never know) and have looked at other annotations. Those other annotations (for instance for Hibernate a @OneToOne) shows up with no issue.

Annotation definition:

@Retention(AnnotationRetention.RUNTIME)
@Repeatable
@Target(
        AnnotationTarget.FIELD,
        AnnotationTarget.PROPERTY_GETTER,
        AnnotationTarget.PROPERTY_SETTER,
        AnnotationTarget.PROPERTY,
        AnnotationTarget.VALUE_PARAMETER
)
annotation class ExcludeFromJSON

Usage in data class:

@Entity
@Table(name = "user")
class User (

        var username: String = "",
        var email: String = "",

        @ExcludeFromJSON
        private var password: String
) {}

I expect the annotation to show up in the javaClass reflection and in the compiled java code. It does neither.

Compiled password var (no annotation...):

private final var password: kotlin.String /* compiled code */`
Slaw :

You should qualify the annotation with the appropriate use-site target:

@field:ExcludeFromJSON
private var password: String

This will cause the annotation to be present on the Java field generated by this property.


From the Kotlin Reference regarding Annotation Use-site Targets:

When you're annotating a property or a primary constructor parameter, there are multiple Java elements which are generated from the corresponding Kotlin element, and therefore multiple possible locations for the annotation in the generated Java bytecode. [...]

[...]

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

[...]

If you don't specify a use-site target, the target is chosen according to the @Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:

  • param;
  • property;
  • field.

The three important things to take away from that are:

  1. Annotations in Kotlin have a certain amount of ambiguity1 regarding where they're ultimately applied. For instance, placing your annotation where you did means said annotation could be applied to one of at least five different locations: property, field, getter, setter, setter parameter.
  2. An annotation applied to a Kotlin property is not visible on the Java side.
  3. An annotation on a Kotlin property, without a use-site target, will only be applied to the backing field if it's not also applicable to being applied to the Kotlin property.

Your annotation has both AnnotationTarget.FIELD and AnnotationTarget.PROPERTY in its @Target annotation. Since you don't specify a use-site target, the property takes precedence—meaning the annotation is not visible to Java.

For more information regarding properties and fields, see the Properties and Fields page of the Kotlin Reference.


1. It's not technically ambiguous, as everything is well defined.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=148759&siteId=1