In an abstract class, I have an annotated method. ...
# getting-started
d
In an abstract class, I have an annotated method. The annotation takes a parameter. Is there any way to provide that parameter from the concrete class? I know that annotation parameters must be compile-time constant so basically, my question can be generalized in a way whether it's possible to somehow sneak in a constant from the concrete implementation to the base class. Something like
abstract const val
d
I think you'd have to put the annotations on the derived classes, not the parent.
Can you be more specific about what you're trying to achieve?
d
The annonation is actually on a method, not on a class. Let me convert my words to a code:
Copy code
abstract class SomeClass {
  @SomeAnnotation(XXX) 
  fun someMethod()
}

class SomeClassImpl : SomeClass() {
  // somehow fill in XXX without overriding someMethod
}
d
I wrote "on the derived class", but I mean't "within" the derived class.
Copy code
abstract class SomeClass {
   fun someMethod() // not annotated
}

class SomeClassImpl : SomeClass {
   @SomeAnnotation
   override fun someMethod()
}
What are you actually trying to do? What is the annotation, and what library/framework uses it? Some frameworks have other ways to achieve what your trying, but there isn't a way to do what you're trying to do.
d
The XXX in my example is actually the annotation parameter which I want to set up in the concrete class. Before asking this I was 95% sure that it can't be done but one never knows 🙂 Still, I would like to at least know whether something like this would make sense in theory, and it isn't implemented for some technical (perhaps JVM?) reason, or it even doesn't make semantical sense.
d
You've got the X/Y problem here... You're trying to solve X by doing Y, and so you've asked how to do Y. What are you actually trying to do? What is the actual annotation you're trying to do this with? Which library or framework are you using where this seems like a good idea?
d
I'm using Spring but I don't think this particular problem is anyhow specific to that framework, if you don't argue that over-reliance on annotations isn't a good idea in the first place, precisely because of the issues similar to mine 🙂 My X problem isn't really much different from the example I've provided. I have a bunch of classes (Kafka listeners) with a
@KafkaListener
annotated method. These are almost the same in all the classes except for one annotation parameter, namely the Kafka topic name. If the listener config was not done via annotations but programmatically I would simply create a base class with the topic as constructor parameter. What I would like to do, is to achieve the same with annotations, i.e. passing the parameter from the concrete implementation to the base class. The complication here is that it must be a compile-time constant so that it can be used in the annotation. (I know that Kafka listeners can be constructed programmatically but this brings a lot of other complexity (you have to register the listeners manually at a central place, for example), so I would like to stick with the annotation-based approach.)
s
Spring's annotations have a bunch of special magic of their own, though. Specifically, the
@KafkaListener
annotation supports SpEL expressions, and recognizes a special
__listener
token that refers to the current instance. So you should be able to write:
Copy code
@KafkaListener(topics = "#{__listener.topic}")
Then you just need a separate
topic
property which you override in each subclass. Or provide as a constructor parameter like you suggested.
plus1 1
d
Ah, great! My use case is actually explicitly mentioned in the documentation: https://docs.spring.io/spring-kafka/reference/kafka/receiving-messages/listener-annotation.html#annotation-properties. I feel ashamed 😊
Anyway, don't you think that my original ask (of
abstract const val
) would make sense by itself? Perhaps I should ask in a different channel, though.
s
What you're asking for sounds somewhat similar to static interfaces. I don't think it's feasible in the way you describe, though. Constants are by definition known at compile-time, while abstract properties are by definition resolved dynamically. It's a contradiction.
d
abstract properties are by definition resolved dynamically
I imagined that the suggested
abstract const val
would require the subclasses to override that property with a constant, i.e. with the same restrictions as the current
const val
. That way it would still be guaranteed that the concrete value is known at compile time.
s
You have to look at it the way the compiler sees the annotation on the superclass method. It needs there to be a single constant value which can be compiled into the class file. Even if you can prove that every subclass has a corresponding constant value, you still don't have a constant—because it would resolve dynamically to a different value depending on the concrete class. To put it another way: if you have two constants
a
and
b
, you can make a third property
c
that dynamically resolves to one of
a
or
b
, but that means
c
itself is not a constant, even though both of its possible values are constants.
d
It needs there to be a single constant value which can be compiled into the class file
This makes it clear to me. That's probably the main point of the constants after all - that they are compiled/inlined directly in the class file. Thanks.