Spring Framework
  1. Spring Framework
  2. SPR-7827

Provide meta-annotation support for test-related annotations

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Complete
    • Affects Version/s: 3.0.5
    • Fix Version/s: 4.0 RC1
    • Component/s: Test
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      Overview

      Spring 3.0 already allows component stereotypes to be used in a meta-annotation fashion, for example by creating a custom @TransactionalService stereotype annotation which combines @Transactional and @Service in a single, reusable, application-specific annotation.

      As mentioned in various forums, a JIRA comment, and discussions I've had with Spring users, it would be beneficial to provide similar meta-annotation support for test-related annotations.

      Given a custom @TransactionalTest stereotype annotation (see code listing below), multiple test classes in the application's test suite could rely on centralized configuration of the context and transaction configuration and thus avoid unnecessary duplication. See UserRepositoryIntegrationTests for an example.

      Notes on JUnit

      Naturally, Spring cannot provide meta-annotation support for JUnit's @RunWith annotation, since @RunWith is processed by JUnit internals. Developers would therefore still be required to specify SpringJUnit4ClassRunner as the runner for each individual test class.


      Deliverables

      Provide meta-annotation support for the following annotations within the context of the TestContext framework.

      1. @ContextConfiguration
      2. @WebAppConfiguration
      3. @ContextHierarchy
      4. @ActiveProfiles
      5. @DirtiesContext
      6. @TestExecutionListeners
      7. @IfProfileValue
      8. @ProfileValueSourceConfiguration
      9. @Transactional
      10. @BeforeTransaction
      11. @AfterTransaction
      12. @TransactionConfiguration
      13. @Rollback
      14. @Repeat
      15. @Timed

      Code Examples

      @TransactionalTest stereotype
      @Transactional
      @ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
      public @interface TransactionalTest {}
      
      UserRepositoryIntegrationTests
      @TransactionalTest
      @RunWith(SpringJUnit4ClassRunner.class)
      public class UserRepositoryIntegrationTests { /* ... */ }
      

      Further Resources


        Issue Links

          Activity

          Hide
          Neale Upstone added a comment -

          That's the job.

          I recall having raised the issue of meta-annotations for JUnit a while back and it getting declined. Can't find it now. Prob pre-dates their shift to githubs issue tracking.

          Show
          Neale Upstone added a comment - That's the job. I recall having raised the issue of meta-annotations for JUnit a while back and it getting declined. Can't find it now. Prob pre-dates their shift to githubs issue tracking.
          Hide
          Neale Upstone added a comment -

          Just working on the JUnit end on this with aim of getting it merged in to 4.9, such that the above example would go further and add the @RunWith to TransactionalTest (the JUnit issue tracking this, with associated patches is https://github.com/KentBeck/junit/issues/194/)

          On the Spring end, what you've identified for the test component is also applicable elsewhere, in that meta-annotations are inconsistently supported, which is not a good position to be in as a Spring user.

          I'd like to see the scope of this broadened to be that AnnotationUtils is used as widely as possible in place of Method.getAnnotation() and Class.getAnnotation().

          Show
          Neale Upstone added a comment - Just working on the JUnit end on this with aim of getting it merged in to 4.9, such that the above example would go further and add the @RunWith to TransactionalTest (the JUnit issue tracking this, with associated patches is https://github.com/KentBeck/junit/issues/194/ ) On the Spring end, what you've identified for the test component is also applicable elsewhere, in that meta-annotations are inconsistently supported, which is not a good position to be in as a Spring user. I'd like to see the scope of this broadened to be that AnnotationUtils is used as widely as possible in place of Method.getAnnotation() and Class.getAnnotation().
          Hide
          Giovanni Dall'Oglio Risso added a comment - - edited

          I'm working on a project, whose architecture is plugin-structured, and the Application Context files are loaded with "classpath*:*/-Context.xml" directive.

          The structure of the project is a "matrix":

          • common-core and common-batch are the core libraries
          • ext1-core and ext1-batch are the extensions

          In short: the library ext1-batch depends on all the others, but ext1-core and common-batch does not mix.

          So: I imagined this configuration, which makes use of meta-annotations described in this issue.

          @ContextConfiguration([...]) // config for HSQLDB environment
          public @interface InRamEnvironment
          
          @ContextConfiguration([...]) // config for Oracle test environment
          public @interface OracleEnvironment
          
          @ContextConfiguration([...]) // config for common-core part
          public @interface CommonCoreIntegrationTest
          
          @ContextConfiguration([...]) // config for common-batch part
          @CommonCoreIntegrationTest // decorating with common-core
          public @interface CommonBatchIntegrationTest
          
          @ContextConfiguration([...])  // config for ext1-core part
          @CommonCoreIntegrationTest // decorating with common-core
          public @interface ExtOneCoreIntegrationTest
          
          @ContextConfiguration([...]) // config for ext1-batch part
          @CommonBatchIntegrationTest // decorating with common-batch
          @ExtOneCoreIntegrationTest // decorating with ext1-core
          public @interface ExtOneBatchIntegrationTest
          
          @ExtOneBatchIntegrationTest
          @InRamEnvironment
          public class OneBatchTest {
          
          [...]
          
          }
          

          ...but to use this configuration, it is necessary set up the recognition of meta-annotations, at least for part of the @ContextConfiguration.

          So, I picked up your code, I developed the feature, and I allowed myself to make a pull request: https://github.com/SpringSource/spring-framework/pull/201

          For the rest of the issue, I realize that there's more work to be done.

          In the meantime I would be grateful if you would consider my little addition, and make available this improvement as soon as possible, perhaps since the version 3.2

          Thank you for the attention, and for your great framework...

          Show
          Giovanni Dall'Oglio Risso added a comment - - edited I'm working on a project, whose architecture is plugin-structured, and the Application Context files are loaded with "classpath*:* / -Context.xml" directive. The structure of the project is a "matrix": common-core and common-batch are the core libraries ext1-core and ext1-batch are the extensions In short: the library ext1-batch depends on all the others, but ext1-core and common-batch does not mix. So: I imagined this configuration, which makes use of meta-annotations described in this issue. @ContextConfiguration([...]) // config for HSQLDB environment public @ interface InRamEnvironment @ContextConfiguration([...]) // config for Oracle test environment public @ interface OracleEnvironment @ContextConfiguration([...]) // config for common-core part public @ interface CommonCoreIntegrationTest @ContextConfiguration([...]) // config for common-batch part @CommonCoreIntegrationTest // decorating with common-core public @ interface CommonBatchIntegrationTest @ContextConfiguration([...]) // config for ext1-core part @CommonCoreIntegrationTest // decorating with common-core public @ interface ExtOneCoreIntegrationTest @ContextConfiguration([...]) // config for ext1-batch part @CommonBatchIntegrationTest // decorating with common-batch @ExtOneCoreIntegrationTest // decorating with ext1-core public @ interface ExtOneBatchIntegrationTest @ExtOneBatchIntegrationTest @InRamEnvironment public class OneBatchTest { [...] } ...but to use this configuration, it is necessary set up the recognition of meta-annotations, at least for part of the @ContextConfiguration. So, I picked up your code, I developed the feature, and I allowed myself to make a pull request: https://github.com/SpringSource/spring-framework/pull/201 For the rest of the issue, I realize that there's more work to be done. In the meantime I would be grateful if you would consider my little addition, and make available this improvement as soon as possible, perhaps since the version 3.2 Thank you for the attention, and for your great framework...
          Hide
          Neale Upstone added a comment -

          Update on earlier JUnit link (although not strictly relevant to this. JUnit has moved repo to junit-team: so above link becomes https://github.com/junit-team/junit/issues/194/).

          Also, above pull request has now been superceded by https://github.com/SpringSource/spring-framework/pull/219

          Show
          Neale Upstone added a comment - Update on earlier JUnit link (although not strictly relevant to this. JUnit has moved repo to junit-team: so above link becomes https://github.com/junit-team/junit/issues/194/ ). Also, above pull request has now been superceded by https://github.com/SpringSource/spring-framework/pull/219
          Hide
          Giovanni Dall'Oglio Risso added a comment -

          My pull request is a year old.

          I would not bet a dollar that can be rebased without going crazy...
          By the way, is there someone who is already working on, and has already figured out what to do?
          Otherwise I would neither bet that you can make into the 4.0.RC1 milestone (10 days from now, and some other things to work)...

          If you agree to postpone this issue to the 4.0.RC2 (and give me a month), I would love to try to help.
          Obviously (since you know your framework better than me) you should also support me, discussing together to figure out the best solution

          Thank you.

          Show
          Giovanni Dall'Oglio Risso added a comment - My pull request is a year old. I would not bet a dollar that can be rebased without going crazy... By the way, is there someone who is already working on, and has already figured out what to do? Otherwise I would neither bet that you can make into the 4.0.RC1 milestone (10 days from now, and some other things to work)... If you agree to postpone this issue to the 4.0.RC2 (and give me a month), I would love to try to help. Obviously (since you know your framework better than me) you should also support me, discussing together to figure out the best solution Thank you.
          Hide
          Sam Brannen added a comment -

          Giovanni Dall'Oglio Risso et al,

          I have in fact been working on this feature in my SPR-7827 branch on GitHub. So feel free to track the progress there.

          Please note, however, that the current implementation is in line with the original intent of this issue: to allow test-related annotations to be used as meta-annotations within the TestContext framework (TCF). In other words, after this work is committed to master, developers will be able to create custom stereotype annotations for use with the TCF. Therefore, the implementation that will make it into 4.0 RC1 does not allow for sourcing @ContextConfiguration or @ContextHierarchy from multiple custom stereotype annotations on a single test class.

          Regards,

          Sam

          Show
          Sam Brannen added a comment - Giovanni Dall'Oglio Risso et al, I have in fact been working on this feature in my SPR-7827 branch on GitHub. So feel free to track the progress there. Please note, however, that the current implementation is in line with the original intent of this issue: to allow test-related annotations to be used as meta-annotations within the TestContext framework (TCF). In other words, after this work is committed to master , developers will be able to create custom stereotype annotations for use with the TCF. Therefore, the implementation that will make it into 4.0 RC1 does not allow for sourcing @ContextConfiguration or @ContextHierarchy from multiple custom stereotype annotations on a single test class. Regards, Sam
          Hide
          Sam Brannen added a comment -

          This issue has been addressed as described in the comments for GitHub commit 2bd5a535e1.

          Provide meta-annotation support in the TCF

          Spring 3.0 already allows component stereotypes to be used in a
          meta-annotation fashion, for example by creating a custom
          @TransactionalService stereotype annotation which combines
          @Transactional and @Service in a single, reusable, application-specific
          annotation. However, the Spring TestContext Framework (TCF) currently
          does not provide any support for test-related annotations to be used as
          meta-annotations.

          This commit overhauls the TCF with regard to how annotations are
          retrieved and adds explicit support for the following annotations to be
          used as meta-annotations in conjunction with the TCF.

          • @ContextConfiguration
          • @ContextHierarchy
          • @ActiveProfiles
          • @DirtiesContext
          • @IfProfileValue
          • @ProfileValueSourceConfiguration
          • @BeforeTransaction
          • @AfterTransaction
          • @TransactionConfiguration
          • @Rollback
          • @TestExecutionListeners
          • @Repeat
          • @Timed
          • @WebAppConfiguration

          Note that meta-annotation support for @Transactional was already
          available prior to this commit.

          The following is a summary of the major changes included in this commit.

          • Now using AnnotationUtils.getAnnotation() instead of
            Class.getAnnotation() where appropriate in the TestContext Framework.
          • Now using AnnotationUtils.findAnnotation() instead of
            Class.isAnnotationPresent() where appropriate in the TestContext
            Framework.
          • Introduced findAnnotationPrefersInteracesOverLocalMetaAnnotations() in
            AnnotationUtilsTests in order to verify the status quo.
          • AnnotationUtils.findAnnotationDeclaringClass() and
            AnnotationUtils.findAnnotationDeclaringClassForTypes() now support
            meta annotations.
          • Introduced MetaAnnotationUtils and AnnotationDescriptor in the
            spring-test module.
          • Introduced UntypedAnnotationDescriptor in MetaAnnotationUtils.
          • Introduced findAnnotationDescriptorForTypes() in MetaAnnotationUtils.
          • ContextLoaderUtils now uses MetaAnnotationUtils for looking up
            @ActiveProfiles as a potential meta-annotation.
          • TestContextManager now uses MetaAnnotationUtils for looking up
            @TestExecutionListeners as a potential meta-annotation.
          • DirtiesContextTestExecutionListener now uses AnnotationUtils for
            looking up @DirtiesContext as a potential meta-annotation.
          • Introduced DirtiesContextTestExecutionListenerTests.
          • ProfileValueUtils now uses AnnotationUtils for looking up
            @IfProfileValue and @ProfileValueSourceConfiguration as potential
            meta-annotations.
          • @BeforeTransaction and @AfterTransaction now support ANNOTATION_TYPE
            as a target, allowing them to be used as meta-annotations.
          • TransactionalTestExecutionListener now uses AnnotationUtils for
            looking up @BeforeTransaction, @AfterTransaction, @Rollback, and
            @TransactionConfiguration as potential meta-annotations.
          • Introduced TransactionalTestExecutionListenerTests.
          • @Repeat and @Timed now support ANNOTATION_TYPE as a target, allowing
            them to be used as meta-annotations.
          • SpringJUnit4ClassRunner now uses AnnotationUtils for looking up
            @Repeat and @Timed as potential meta-annotations.
          • Moved all remaining logic for building the MergedContextConfiguration
            from the DefaultTestContext constructor to
            ContextLoaderUtils.buildMergedContextConfiguration().
          • Verified meta-annotation support for @WebAppConfiguration and
            @ContextConfiguration.
          Show
          Sam Brannen added a comment - This issue has been addressed as described in the comments for GitHub commit 2bd5a535e1 . Provide meta-annotation support in the TCF Spring 3.0 already allows component stereotypes to be used in a meta-annotation fashion, for example by creating a custom @TransactionalService stereotype annotation which combines @Transactional and @Service in a single, reusable, application-specific annotation. However, the Spring TestContext Framework (TCF) currently does not provide any support for test-related annotations to be used as meta-annotations. This commit overhauls the TCF with regard to how annotations are retrieved and adds explicit support for the following annotations to be used as meta-annotations in conjunction with the TCF. @ContextConfiguration @ContextHierarchy @ActiveProfiles @DirtiesContext @IfProfileValue @ProfileValueSourceConfiguration @BeforeTransaction @AfterTransaction @TransactionConfiguration @Rollback @TestExecutionListeners @Repeat @Timed @WebAppConfiguration Note that meta-annotation support for @Transactional was already available prior to this commit. The following is a summary of the major changes included in this commit. Now using AnnotationUtils.getAnnotation() instead of Class.getAnnotation() where appropriate in the TestContext Framework. Now using AnnotationUtils.findAnnotation() instead of Class.isAnnotationPresent() where appropriate in the TestContext Framework. Introduced findAnnotationPrefersInteracesOverLocalMetaAnnotations() in AnnotationUtilsTests in order to verify the status quo. AnnotationUtils.findAnnotationDeclaringClass() and AnnotationUtils.findAnnotationDeclaringClassForTypes() now support meta annotations. Introduced MetaAnnotationUtils and AnnotationDescriptor in the spring-test module. Introduced UntypedAnnotationDescriptor in MetaAnnotationUtils. Introduced findAnnotationDescriptorForTypes() in MetaAnnotationUtils. ContextLoaderUtils now uses MetaAnnotationUtils for looking up @ActiveProfiles as a potential meta-annotation. TestContextManager now uses MetaAnnotationUtils for looking up @TestExecutionListeners as a potential meta-annotation. DirtiesContextTestExecutionListener now uses AnnotationUtils for looking up @DirtiesContext as a potential meta-annotation. Introduced DirtiesContextTestExecutionListenerTests. ProfileValueUtils now uses AnnotationUtils for looking up @IfProfileValue and @ProfileValueSourceConfiguration as potential meta-annotations. @BeforeTransaction and @AfterTransaction now support ANNOTATION_TYPE as a target, allowing them to be used as meta-annotations. TransactionalTestExecutionListener now uses AnnotationUtils for looking up @BeforeTransaction, @AfterTransaction, @Rollback, and @TransactionConfiguration as potential meta-annotations. Introduced TransactionalTestExecutionListenerTests. @Repeat and @Timed now support ANNOTATION_TYPE as a target, allowing them to be used as meta-annotations. SpringJUnit4ClassRunner now uses AnnotationUtils for looking up @Repeat and @Timed as potential meta-annotations. Moved all remaining logic for building the MergedContextConfiguration from the DefaultTestContext constructor to ContextLoaderUtils.buildMergedContextConfiguration(). Verified meta-annotation support for @WebAppConfiguration and @ContextConfiguration.

            People

            • Assignee:
              Sam Brannen
              Reporter:
              Sam Brannen
              Last updater:
              Sam Brannen
            • Votes:
              8 Vote for this issue
              Watchers:
              11 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                25 weeks, 2 days ago