Skip to content

Inconsistent @AliasFor behavior #36680

@creckord

Description

@creckord

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.

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)status: waiting-for-feedbackWe need additional information before we can continue

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions