The @ConditionalOnProperty is available as meta annotation (despite the #13996) but the @AliasFor does not work.

I've included a simple test showing four different bean: no condition, direct @ConditionalOnProperty, meta without alias, and meta with alias. As you can see the meta with alias does not disable the bean while the simple meta does.

My use case would be to create a @ConditionalOnModuleState meta alias with @AliasFor which could ensure that the autoconfiguration (which is loaded by spring.factories) can be turned off without removing the dependency.

package support;

import static org.assertj.core.api.Assertions.assertThatCode;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor;
import org.springframework.test.context.TestPropertySource;

@SpringBootTest(classes = ConditionalOnPropertyTest.Config.class)
@TestPropertySource(properties = "module.enabled=false")
public class ConditionalOnPropertyTest {
  @Autowired
  private ApplicationContext context;

  @Test
  public void testReference() {
    assertThatCode(() -> context.getBean("reference"))
        .doesNotThrowAnyException();
  }

  @Test
  public void testDirect() {
    assertThatCode(() -> context.getBean("direct"))
        .isInstanceOf(NoSuchBeanDefinitionException.class);
  }

  @Test
  public void testModuleState() {
    assertThatCode(() -> context.getBean("moduleState"))
        .isInstanceOf(NoSuchBeanDefinitionException.class);
  }

  @Test
  public void testModuleStateWithAlias() {
    assertThatCode(() -> context.getBean("moduleStateWithAlias"))
        .doesNotThrowAnyException();
        // This should raise the exception too but the @AliasFor seems to be not working.
        //.isInstanceOf(NoSuchBeanDefinitionException.class);
  }

  @Configuration
  public static class Config {
    @Bean
    public Object reference() {
      return new Object();
    }

    @Bean
    @ConditionalOnProperty(prefix = "module", name = "enabled", havingValue = "true", matchIfMissing = true)
    public Object direct() {
      return new Object();
    }

    @Bean
    @ConditionalOnModuleState
    public Object moduleState() {
      return new Object();
    }

    @Bean
    @ConditionalOnModuleStateWithAlias("module")
    public Object moduleStateWithAlias() {
      return new Object();
    }
  }

  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.TYPE, ElementType.METHOD})
  @ConditionalOnProperty(name = "enabled", havingValue = "true", matchIfMissing = true, prefix = "module")
  public @interface ConditionalOnModuleState {
  }

  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.TYPE, ElementType.METHOD})
  @ConditionalOnProperty(name = "enabled", havingValue = "true", matchIfMissing = true)
  public @interface ConditionalOnModuleStateWithAlias {
    @AliasFor(annotation = ConditionalOnProperty.class, attribute = "prefix")
    String value();
  }
}

Comment From: philwebb

We had an old issue about this (#5819) but perhaps we overlooked something.

@gebezs Are you able to share the code you pasted as a complete project that we can run? It can either be a link to a GitHub project, or a zip file.

Comment From: gebezs

The difference seems to be that I use @AliasFor. I've uploaded a simple maven project with the test: conditional.zip

Comment From: wilkinsona

It's not clear to me how to fix this without breaking metaAndDirectAnnotationConditionDoesNotMatchWhenOnlyDirectPropertyIsSet. It looks like we need a variant of AnnotatedTypeMetadata.getAllAnnotationAttributes(String) that takes attribute overrides into account.

Comment From: wilkinsona

Closing in favor of #30505.