Verify status quo when searching for non-inherited composed annotations
Issue: SPR-11475
This commit is contained in:
parent
f8950960f2
commit
90b938aa8f
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.annotation;
|
||||
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AnnotatedElementUtils}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.0.3
|
||||
*/
|
||||
public class AnnotatedElementUtilsTests {
|
||||
|
||||
@Test
|
||||
public void getAnnotationAttributesFavorsInheritedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
|
||||
AnnotationAttributes attributes = AnnotatedElementUtils.getAnnotationAttributes(
|
||||
SubSubClassWithInheritedAnnotation.class, Transactional.class.getName());
|
||||
assertNotNull(attributes);
|
||||
|
||||
// By inspecting SubSubClassWithInheritedAnnotation, one might expect that the
|
||||
// readOnly flag should be true, since the immediate superclass is annotated with
|
||||
// @Composed2; however, with the current implementation the readOnly flag will be
|
||||
// false since @Transactional is declared as @Inherited.
|
||||
assertFalse("readOnly flag for SubSubClassWithInheritedAnnotation", attributes.getBoolean("readOnly"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnotationAttributesFavorsInheritedComposedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
|
||||
AnnotationAttributes attributes = AnnotatedElementUtils.getAnnotationAttributes(
|
||||
SubSubClassWithInheritedComposedAnnotation.class, Transactional.class.getName());
|
||||
assertNotNull(attributes);
|
||||
|
||||
// By inspecting SubSubClassWithInheritedComposedAnnotation, one might expect that
|
||||
// the readOnly flag should be true, since the immediate superclass is annotated
|
||||
// with @Composed2; however, with the current implementation the readOnly flag
|
||||
// will be false since @Composed1 is declared as @Inherited.
|
||||
assertFalse("readOnly flag", attributes.getBoolean("readOnly"));
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@interface Transactional {
|
||||
|
||||
boolean readOnly() default false;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@interface Composed1 {
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Composed2 {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
static class ClassWithInheritedAnnotation {
|
||||
}
|
||||
|
||||
@Composed2
|
||||
static class SubClassWithInheritedAnnotation extends ClassWithInheritedAnnotation {
|
||||
}
|
||||
|
||||
static class SubSubClassWithInheritedAnnotation extends SubClassWithInheritedAnnotation {
|
||||
}
|
||||
|
||||
@Composed1
|
||||
static class ClassWithInheritedComposedAnnotation {
|
||||
}
|
||||
|
||||
@Composed2
|
||||
static class SubClassWithInheritedComposedAnnotation extends ClassWithInheritedComposedAnnotation {
|
||||
}
|
||||
|
||||
static class SubSubClassWithInheritedComposedAnnotation extends SubClassWithInheritedComposedAnnotation {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -100,14 +100,40 @@ public class AnnotationUtilsTests {
|
|||
// }
|
||||
|
||||
@Test
|
||||
public void findAnnotationPrefersInterfacesOverLocalMetaAnnotations() {
|
||||
public void findAnnotationFavorsInterfacesOverLocalMetaAnnotations() {
|
||||
Component component = AnnotationUtils.findAnnotation(
|
||||
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, Component.class);
|
||||
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, Component.class);
|
||||
assertNotNull(component);
|
||||
|
||||
// By inspecting ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface, one
|
||||
// might expect that "meta2" should be found; however, with the current
|
||||
// implementation "meta1" will be found.
|
||||
assertEquals("meta1", component.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationFavorsInheritedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
|
||||
Transactional transactional = AnnotationUtils.findAnnotation(SubSubClassWithInheritedAnnotation.class,
|
||||
Transactional.class);
|
||||
assertNotNull(transactional);
|
||||
|
||||
// By inspecting SubSubClassWithInheritedAnnotation, one might expect that the
|
||||
// readOnly flag should be true, since the immediate superclass is annotated with
|
||||
// @Composed2; however, with the current implementation the readOnly flag will be
|
||||
// false since @Transactional is declared as @Inherited.
|
||||
assertFalse("readOnly flag for SubSubClassWithInheritedAnnotation", transactional.readOnly());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationFavorsInheritedComposedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
|
||||
Component component = AnnotationUtils.findAnnotation(SubSubClassWithInheritedMetaAnnotation.class,
|
||||
Component.class);
|
||||
assertNotNull(component);
|
||||
|
||||
// By inspecting SubSubClassWithInheritedMetaAnnotation, one might expect that
|
||||
// "meta2" should be found, since the immediate superclass is annotated with
|
||||
// @Meta2; however, with the current implementation "meta1" will be found since
|
||||
// @Meta1 is declared as @Inherited.
|
||||
assertEquals("meta1", component.value());
|
||||
}
|
||||
|
||||
|
|
@ -350,14 +376,15 @@ public class AnnotationUtilsTests {
|
|||
}
|
||||
|
||||
|
||||
@Component(value="meta1")
|
||||
@Component(value = "meta1")
|
||||
@Order
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@interface Meta1 {
|
||||
}
|
||||
|
||||
@Component(value="meta2")
|
||||
@Transactional
|
||||
@Component(value = "meta2")
|
||||
@Transactional(readOnly = true)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Meta2 {
|
||||
}
|
||||
|
|
@ -395,6 +422,28 @@ public class AnnotationUtilsTests {
|
|||
static class ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface implements InterfaceWithMetaAnnotation {
|
||||
}
|
||||
|
||||
@Meta1
|
||||
static class ClassWithInheritedMetaAnnotation {
|
||||
}
|
||||
|
||||
@Meta2
|
||||
static class SubClassWithInheritedMetaAnnotation extends ClassWithInheritedMetaAnnotation {
|
||||
}
|
||||
|
||||
static class SubSubClassWithInheritedMetaAnnotation extends SubClassWithInheritedMetaAnnotation {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
static class ClassWithInheritedAnnotation {
|
||||
}
|
||||
|
||||
@Meta2
|
||||
static class SubClassWithInheritedAnnotation extends ClassWithInheritedAnnotation {
|
||||
}
|
||||
|
||||
static class SubSubClassWithInheritedAnnotation extends SubClassWithInheritedAnnotation {
|
||||
}
|
||||
|
||||
@MetaMeta
|
||||
static class MetaMetaAnnotatedClass {
|
||||
}
|
||||
|
|
@ -453,6 +502,8 @@ public class AnnotationUtilsTests {
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@interface Transactional {
|
||||
|
||||
boolean readOnly() default false;
|
||||
}
|
||||
|
||||
public static abstract class Foo<T> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue