|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2019 the original author or authors. |
| 2 | + * Copyright 2002-2022 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
36 | 36 | import javax.annotation.meta.When;
|
37 | 37 |
|
38 | 38 | import org.junit.jupiter.api.Disabled;
|
| 39 | +import org.junit.jupiter.api.Nested; |
39 | 40 | import org.junit.jupiter.api.Test;
|
40 | 41 |
|
41 | 42 | import org.springframework.core.annotation.AnnotationUtilsTests.ExtendsBaseClassWithGenericAnnotatedMethod;
|
@@ -82,6 +83,90 @@ class AnnotatedElementUtilsTests {
|
82 | 83 | private static final String TX_NAME = Transactional.class.getName();
|
83 | 84 |
|
84 | 85 |
|
| 86 | + @Nested |
| 87 | + class ConventionBasedAnnotationAttributeOverrideTests { |
| 88 | + |
| 89 | + @Test |
| 90 | + void getMergedAnnotationAttributesWithConventionBasedComposedAnnotation() { |
| 91 | + Class<?> element = ConventionBasedComposedContextConfigClass.class; |
| 92 | + String name = ContextConfig.class.getName(); |
| 93 | + AnnotationAttributes attributes = getMergedAnnotationAttributes(element, name); |
| 94 | + |
| 95 | + assertThat(attributes).as("Should find @ContextConfig on " + element.getSimpleName()).isNotNull(); |
| 96 | + assertThat(attributes.getStringArray("locations")).as("locations").containsExactly("explicitDeclaration"); |
| 97 | + assertThat(attributes.getStringArray("value")).as("value").containsExactly("explicitDeclaration"); |
| 98 | + |
| 99 | + // Verify contracts between utility methods: |
| 100 | + assertThat(isAnnotated(element, name)).isTrue(); |
| 101 | + } |
| 102 | + |
| 103 | + /** |
| 104 | + * This test should never pass, simply because Spring does not support a hybrid |
| 105 | + * approach for annotation attribute overrides with transitive implicit aliases. |
| 106 | + * See SPR-13554 for details. |
| 107 | + * <p>Furthermore, if you choose to execute this test, it can fail for either |
| 108 | + * the first test class or the second one (with different exceptions), depending |
| 109 | + * on the order in which the JVM returns the attribute methods via reflection. |
| 110 | + */ |
| 111 | + @Disabled("Permanently disabled but left in place for illustrative purposes") |
| 112 | + @Test |
| 113 | + void getMergedAnnotationAttributesWithHalfConventionBasedAndHalfAliasedComposedAnnotation() { |
| 114 | + for (Class<?> clazz : asList(HalfConventionBasedAndHalfAliasedComposedContextConfigClassV1.class, |
| 115 | + HalfConventionBasedAndHalfAliasedComposedContextConfigClassV2.class)) { |
| 116 | + getMergedAnnotationAttributesWithHalfConventionBasedAndHalfAliasedComposedAnnotation(clazz); |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + private void getMergedAnnotationAttributesWithHalfConventionBasedAndHalfAliasedComposedAnnotation(Class<?> clazz) { |
| 121 | + String name = ContextConfig.class.getName(); |
| 122 | + String simpleName = clazz.getSimpleName(); |
| 123 | + AnnotationAttributes attributes = getMergedAnnotationAttributes(clazz, name); |
| 124 | + |
| 125 | + assertThat(attributes).as("Should find @ContextConfig on " + simpleName).isNotNull(); |
| 126 | + assertThat(attributes.getStringArray("locations")).as("locations for class [" + simpleName + "]") |
| 127 | + .containsExactly("explicitDeclaration"); |
| 128 | + assertThat(attributes.getStringArray("value")).as("value for class [" + simpleName + "]") |
| 129 | + .containsExactly("explicitDeclaration"); |
| 130 | + |
| 131 | + // Verify contracts between utility methods: |
| 132 | + assertThat(isAnnotated(clazz, name)).isTrue(); |
| 133 | + } |
| 134 | + |
| 135 | + @Test |
| 136 | + void getMergedAnnotationAttributesWithInvalidConventionBasedComposedAnnotation() { |
| 137 | + Class<?> element = InvalidConventionBasedComposedContextConfigClass.class; |
| 138 | + assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() -> |
| 139 | + getMergedAnnotationAttributes(element, ContextConfig.class)) |
| 140 | + .withMessageContaining("Different @AliasFor mirror values for annotation") |
| 141 | + .withMessageContaining("attribute 'locations' and its alias 'value'") |
| 142 | + .withMessageContaining("values of [{requiredLocationsDeclaration}] and [{duplicateDeclaration}]"); |
| 143 | + } |
| 144 | + |
| 145 | + @Test |
| 146 | + void findMergedAnnotationAttributesWithSingleElementOverridingAnArrayViaConvention() { |
| 147 | + assertComponentScanAttributes(ConventionBasedSinglePackageComponentScanClass.class, "com.example.app.test"); |
| 148 | + } |
| 149 | + |
| 150 | + @Test |
| 151 | + void findMergedAnnotationWithLocalAliasesThatConflictWithAttributesInMetaAnnotationByConvention() { |
| 152 | + Class<?> element = SpringAppConfigClass.class; |
| 153 | + ContextConfig contextConfig = findMergedAnnotation(element, ContextConfig.class); |
| 154 | + |
| 155 | + assertThat(contextConfig).as("Should find @ContextConfig on " + element).isNotNull(); |
| 156 | + assertThat(contextConfig.locations()).as("locations for " + element).isEmpty(); |
| 157 | + // 'value' in @SpringAppConfig should not override 'value' in @ContextConfig |
| 158 | + assertThat(contextConfig.value()).as("value for " + element).isEmpty(); |
| 159 | + assertThat(contextConfig.classes()).as("classes for " + element).containsExactly(Number.class); |
| 160 | + } |
| 161 | + |
| 162 | + @Test |
| 163 | + void findMergedAnnotationWithSingleElementOverridingAnArrayViaConvention() throws Exception { |
| 164 | + assertWebMapping(WebController.class.getMethod("postMappedWithPathAttribute")); |
| 165 | + } |
| 166 | + |
| 167 | + } |
| 168 | + |
| 169 | + |
85 | 170 | @Test
|
86 | 171 | void getMetaAnnotationTypesOnNonAnnotatedClass() {
|
87 | 172 | assertThat(getMetaAnnotationTypes(NonAnnotatedClass.class, TransactionalComponent.class).isEmpty()).isTrue();
|
@@ -363,51 +448,6 @@ void getMergedAnnotationAttributesOnNonInheritedAnnotationInterface() {
|
363 | 448 | assertThat(isAnnotated(element, name)).isTrue();
|
364 | 449 | }
|
365 | 450 |
|
366 |
| - @Test |
367 |
| - void getMergedAnnotationAttributesWithConventionBasedComposedAnnotation() { |
368 |
| - Class<?> element = ConventionBasedComposedContextConfigClass.class; |
369 |
| - String name = ContextConfig.class.getName(); |
370 |
| - AnnotationAttributes attributes = getMergedAnnotationAttributes(element, name); |
371 |
| - |
372 |
| - assertThat(attributes).as("Should find @ContextConfig on " + element.getSimpleName()).isNotNull(); |
373 |
| - assertThat(attributes.getStringArray("locations")).as("locations").isEqualTo(asArray("explicitDeclaration")); |
374 |
| - assertThat(attributes.getStringArray("value")).as("value").isEqualTo(asArray("explicitDeclaration")); |
375 |
| - |
376 |
| - // Verify contracts between utility methods: |
377 |
| - assertThat(isAnnotated(element, name)).isTrue(); |
378 |
| - } |
379 |
| - |
380 |
| - /** |
381 |
| - * This test should never pass, simply because Spring does not support a hybrid |
382 |
| - * approach for annotation attribute overrides with transitive implicit aliases. |
383 |
| - * See SPR-13554 for details. |
384 |
| - * <p>Furthermore, if you choose to execute this test, it can fail for either |
385 |
| - * the first test class or the second one (with different exceptions), depending |
386 |
| - * on the order in which the JVM returns the attribute methods via reflection. |
387 |
| - */ |
388 |
| - @Disabled("Permanently disabled but left in place for illustrative purposes") |
389 |
| - @Test |
390 |
| - void getMergedAnnotationAttributesWithHalfConventionBasedAndHalfAliasedComposedAnnotation() { |
391 |
| - for (Class<?> clazz : asList(HalfConventionBasedAndHalfAliasedComposedContextConfigClassV1.class, |
392 |
| - HalfConventionBasedAndHalfAliasedComposedContextConfigClassV2.class)) { |
393 |
| - getMergedAnnotationAttributesWithHalfConventionBasedAndHalfAliasedComposedAnnotation(clazz); |
394 |
| - } |
395 |
| - } |
396 |
| - |
397 |
| - private void getMergedAnnotationAttributesWithHalfConventionBasedAndHalfAliasedComposedAnnotation(Class<?> clazz) { |
398 |
| - String[] expected = asArray("explicitDeclaration"); |
399 |
| - String name = ContextConfig.class.getName(); |
400 |
| - String simpleName = clazz.getSimpleName(); |
401 |
| - AnnotationAttributes attributes = getMergedAnnotationAttributes(clazz, name); |
402 |
| - |
403 |
| - assertThat(attributes).as("Should find @ContextConfig on " + simpleName).isNotNull(); |
404 |
| - assertThat(attributes.getStringArray("locations")).as("locations for class [" + clazz.getSimpleName() + "]").isEqualTo(expected); |
405 |
| - assertThat(attributes.getStringArray("value")).as("value for class [" + clazz.getSimpleName() + "]").isEqualTo(expected); |
406 |
| - |
407 |
| - // Verify contracts between utility methods: |
408 |
| - assertThat(isAnnotated(clazz, name)).isTrue(); |
409 |
| - } |
410 |
| - |
411 | 451 | @Test
|
412 | 452 | void getMergedAnnotationAttributesWithAliasedComposedAnnotation() {
|
413 | 453 | Class<?> element = AliasedComposedContextConfigClass.class;
|
@@ -530,16 +570,6 @@ void getMergedAnnotationWithImplicitAliasesWithDefaultsInMetaAnnotationOnCompose
|
530 | 570 | assertThat(isAnnotated(element, name)).isTrue();
|
531 | 571 | }
|
532 | 572 |
|
533 |
| - @Test |
534 |
| - void getMergedAnnotationAttributesWithInvalidConventionBasedComposedAnnotation() { |
535 |
| - Class<?> element = InvalidConventionBasedComposedContextConfigClass.class; |
536 |
| - assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() -> |
537 |
| - getMergedAnnotationAttributes(element, ContextConfig.class)) |
538 |
| - .withMessageContaining("Different @AliasFor mirror values for annotation") |
539 |
| - .withMessageContaining("attribute 'locations' and its alias 'value'") |
540 |
| - .withMessageContaining("values of [{requiredLocationsDeclaration}] and [{duplicateDeclaration}]"); |
541 |
| - } |
542 |
| - |
543 | 573 | @Test
|
544 | 574 | void getMergedAnnotationAttributesWithShadowedAliasComposedAnnotation() {
|
545 | 575 | Class<?> element = ShadowedAliasComposedContextConfigClass.class;
|
@@ -743,11 +773,6 @@ void findMergedAnnotationOnClassWithComposedMetaTransactionalAnnotation() throws
|
743 | 773 | assertThat(annotation.qualifier()).as("TX qualifier for " + clazz).isEqualTo("anotherTransactionManager");
|
744 | 774 | }
|
745 | 775 |
|
746 |
| - @Test |
747 |
| - void findMergedAnnotationAttributesWithSingleElementOverridingAnArrayViaConvention() { |
748 |
| - assertComponentScanAttributes(ConventionBasedSinglePackageComponentScanClass.class, "com.example.app.test"); |
749 |
| - } |
750 |
| - |
751 | 776 | @Test
|
752 | 777 | void findMergedAnnotationAttributesWithSingleElementOverridingAnArrayViaAliasFor() {
|
753 | 778 | assertComponentScanAttributes(AliasForBasedSinglePackageComponentScanClass.class, "com.example.app.test");
|
@@ -800,24 +825,6 @@ void findMergedAnnotationForMultipleMetaAnnotationsWithClashingAttributeNames()
|
800 | 825 | assertThat(testPropSource.value()).as("value").isEqualTo(propFiles);
|
801 | 826 | }
|
802 | 827 |
|
803 |
| - @Test |
804 |
| - void findMergedAnnotationWithLocalAliasesThatConflictWithAttributesInMetaAnnotationByConvention() { |
805 |
| - final String[] EMPTY = new String[0]; |
806 |
| - Class<?> element = SpringAppConfigClass.class; |
807 |
| - ContextConfig contextConfig = findMergedAnnotation(element, ContextConfig.class); |
808 |
| - |
809 |
| - assertThat(contextConfig).as("Should find @ContextConfig on " + element).isNotNull(); |
810 |
| - assertThat(contextConfig.locations()).as("locations for " + element).isEqualTo(EMPTY); |
811 |
| - // 'value' in @SpringAppConfig should not override 'value' in @ContextConfig |
812 |
| - assertThat(contextConfig.value()).as("value for " + element).isEqualTo(EMPTY); |
813 |
| - assertThat(contextConfig.classes()).as("classes for " + element).isEqualTo(new Class<?>[] {Number.class}); |
814 |
| - } |
815 |
| - |
816 |
| - @Test |
817 |
| - void findMergedAnnotationWithSingleElementOverridingAnArrayViaConvention() throws Exception { |
818 |
| - assertWebMapping(WebController.class.getMethod("postMappedWithPathAttribute")); |
819 |
| - } |
820 |
| - |
821 | 828 | @Test
|
822 | 829 | void findMergedAnnotationWithSingleElementOverridingAnArrayViaAliasFor() throws Exception {
|
823 | 830 | assertWebMapping(WebController.class.getMethod("getMappedWithValueAttribute"));
|
|
0 commit comments