I am using currently TestContainers singleton pattern in order to reuse my db across all JVM tests and I ended up using an enum for it. So I was wondering if it was possible to extend the @DynamicPropertySource so it can be used at class level on something like this:

@DynamicPropertySource(TestContainers.POSTGRES)
public class MyFlowIT { ... } 

The updated annotation's "values"/default property (or a new explicit one) would have to be a new interface close to something like Consumer<DynamicPropertyRegistry>, since the very same consumer is illegal as an annotation attribute according to spec.

That would allow us to save from having to define the following in each test,

    @DynamicPropertySource
    static void postgresProperties(DynamicPropertyRegistry registry) {
        TestContainers.POSTGRES.registerProperties(registry);
    }

For instance, what about accepting an interface like:

interface DynamicPropertyRegistrable {
    public void registerProperties(DynamicPropertyRegistry dynamicPropertyRegistry) ; 
}   

Then the enum would be something like:

public enum TestContainers implements DynamicPropertyRegistrable {

    POSTGRES ("POSTGRES", new PostgresInitializer()),
    KAFKA ("KAFKA", new KafkaInitializer()),
    ACTIVEMQ ("ACTIVEMQ", new ActiveMQInitializer()),
    OPENSEARCH("OPENSEARCH", new OpenSearchInitialiser());

    @Override
    public void registerProperties(DynamicPropertyRegistry dynamicPropertyRegistry) {
        this.propertyRegistrar.forEach((property,supplier) -> dynamicPropertyRegistry.add(property, supplier));
    }
(...)

Then we could use it as @DynamicPropertySource(TestContainers.POSTGRES). I would really love to save me from defining the register section at the beginning of each of my 300 ITs and annotation composition is less problematic and more elegant than abstracting in parents expressly. With my suggested way, we could also include the db setup as part of a meta-annotation with other annotations. Wouldn't rock something like this?:

@IntegrationTest   
public class MyFlowIT { ... }

where my custom annotation would be something like:

@DynamicPropertySource(TestContainers.POSTGRES) 
@TestInstance(LifeCycle.PER_CLASS)
@Sql(scripts = "/db/scenarios/common/CleanDB.sql", executionPhase = AFTER_TEST_METHOD)
@SqlMergeMode(SqlMergeMode.MergeMode.MERGE) 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface IntegrationTest {}

Comment From: wilkinsona

In the interests of avoiding wasted time, this was originally proposed in the Spring Boot issue tracker. @nightswimmings, making the same proposal here without first addressing the problems that Phil and I already described is unlikely to be an efficient use of everyone's time.

Comment From: nightswimmings

@wilkinsona I did not understand your comment on the Spring Boot tracker, I assumed you meant that current annotation did not have an attribute specified for it! ( it couldn't be used as the type of the annotation's attribute as @DynamicPropertySource knows nothing about it.) I understood from Phil that I cannot use a Consumer in an annotation, but why not a class? The spec enumerates both Enum and Class. What is the problem of @CustomAnnotation(value = instance) ?

I am really sorry if what you were trying to tell me is that this approach is impossible by spec. Is this then not feasible?

public @interface DynamicPropertySource {
    public  DynamicPropertyRegistrable  value();
}

Comment From: nightswimmings

And still, I believe there must be a way to do it, by designing the @DynamicPropertySource in a way that it tries to cast the provided instance at runtime.

Comment From: wilkinsona

Is this then not feasible?

No, unfortunately not. If you try it for yourself, you'll see that it does not compile.

It would compile if the attribute was a enum such as your Testcontainers enum. However, @DynamicPropertySource can't depend on an application-specific enum. It doesn't know anything about such an enum, and nor should it.

You may be able to implement something similar to what you want by making the attribute a Class<? extends DynamicPropertyRegistrable>. The test framework would then create an instance of this class and call registerProperties. However, you wouldn't be able to use your Testcontainers enum in this case as the test framework would have no way of knowing how to create the instance, i.e. which constant on the enum to use.

Comment From: nightswimmings

Thanks for your patience, @wilkinsona. I really see no creative solution for this, after all your explanations, so I guess we can close it