Hi all, is there a way to write a data class that ...
# getting-started
p
Hi all, is there a way to write a data class that compiles to the same as the following Java class?
Copy code
public class Pet {

    private List<String> names;

    public @NonNull List<@NonNull String> getNames() {
        return names;
    }

    // constructor, setter, etc. omitted
}
I tried to write the following data class:
Copy code
data class Pet(val names: @get:NonNull List<@get:NonNull String>)
For each of the annotations I get two compile errors: - This annotation is not applicable to target 'undefined target' and use site target '@get' - This annotation is not applicable to target 'type usage' and use site target '@get' The NonNull annotation is from the Java library microprofile-graphql-api
Copy code
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Documented
public @interface NonNull {
}
I run into the same problem when I try to set the annotations on the field:
Copy code
data class Pet(val names: @field:NonNull List<@field:NonNull String>)
Is there a way to get annotations on the type and generic type of a getter method or field?
s
Copy code
data class Pet(@get:NonNull val names: List<@NonNull String>)
• The first annotation is for the property getter (
AnnotationTarget.PROPERTY_GETTER
). It goes before the property declaration, but needs the
get:
use-site target otherwise it would annotate the constructor parameter by default. • The second annotation is for the
String
type parameter use. (In Kotlin,
AnnotationTarget.TYPE
, in Java,
ElementType.TYPE_USE
). There’s no use-site target for this because it’s the only valid target for an annotation in that position.
Actually looking at your first example, I think both of your annotations are on the type usages. I had thought one of them was on the getter method. So maybe what you want is closer to:
Copy code
data class Pet(val names: @NonNull List<@NonNull String>)
I’m a bit fuzzy on what the difference would be in the resulting Java code, to be honest. I’ve been spoiled by writing Kotlin for too long 😄
tl;dr: to annotate a type use, you just use the annotation without any prefix (like
get:
).
p
Thanks Sam, but I need the annotations on the type (List) and type parameter (String), otherwise the Java library won't do the right things.
Copy code
data class Pet(val names: @NonNull List<@NonNull String>)
The above snippet will not put any annotation on the method, its type or type parameter. It will just compile them to
@kotlin.Metadata
where they are not visible to a Java library that is not aware of Kotlin. The Java code above compiles to
Copy code
public getNames()Ljava/util/List;
  @Lorg/eclipse/microprofile/graphql/NonNull;()
  @Lorg/eclipse/microprofile/graphql/NonNull;() : METHOD_RETURN, 0;
  @Lorg/eclipse/microprofile/graphql/NonNull;() : METHOD_RETURN, null
and I'm looking for a Kotlin data class that compiles to the same bytecode.
Copy code
data class Pet(@get:NonNull val names: List<@NonNull String>)
compiles to
Copy code
public final getNames()Ljava/util/List;
 @Lorg/eclipse/microprofile/graphql/NonNull;()
i.e. it puts the annotation on the method but not the type or type parameter.