In one of our projects, we had an annotation declaration with meta-annotations that was missing an @AliasFor:
public abstract class CallbackListener {
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@KafkaListener(id = LISTENER_ID, idIsGroup = false)
public @interface CallbackListenerDef {
@AliasFor(annotation = KafkaListener.class)
String[] topics() default {};
// This was missing: @AliasFor(annotation = KafkaListener.class)
String groupId() default "${spring.kafka.consumer.group-id}.callback";
}
@KafkaHandler(isDefault = true)
public void executeCallback(CallbackEvent event) {
// ...
}
@Service
@Profile("!mock")
@CallbackListenerDef(topics = TOPIC)
public static class ProdCallbackListener extends CallbackListener {
}
@Service
@Profile("mock")
@CallbackListenerDef(topics = TOPIC_MOCK, groupId = "${spring.kafka.consumer.group-id}.callback-mock")
public static class MockCallbackListener extends CallbackListener {
}
}
Note the missing @AliasFor on groupId.
In Spring Boot 3.5 / Spring Core 6.2, this magically worked anyway, and we got listeners with group.id app.callback and app.callback-mock depending on the deployment's active profile.
In Spring Boot 4 / Spring Core 7.0.6, this broke in a fun and unexpected way: The ProdCallbackListener got its group.id set to app.callback via the default value of our annotation, whereas the explicit groupId on MockCallbackListener caused the whole thing to be ignored and it ended up with the global default group.id of just app.
I would have expected that this behaved consistently, i.e. either disregarding the non-aliased groupId entirely, or applying it in both cases.
In one of our projects, we had an annotation declaration with meta-annotations that was missing an
@AliasFor:Note the missing
@AliasForongroupId.In Spring Boot 3.5 / Spring Core 6.2, this magically worked anyway, and we got listeners with group.id
app.callbackandapp.callback-mockdepending on the deployment's active profile.In Spring Boot 4 / Spring Core 7.0.6, this broke in a fun and unexpected way: The
ProdCallbackListenergot its group.id set toapp.callbackvia thedefaultvalue of our annotation, whereas the explicitgroupIdonMockCallbackListenercaused the whole thing to be ignored and it ended up with the global default group.id of justapp.I would have expected that this behaved consistently, i.e. either disregarding the non-aliased
groupIdentirely, or applying it in both cases.