Introduce alias for 'value' attribute in @Scope

Issue: SPR-11393
This commit is contained in:
Sam Brannen 2015-06-13 16:07:29 +02:00
parent 6b7c1d72e8
commit 2d23f42609
5 changed files with 87 additions and 82 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@ -25,13 +25,14 @@ import org.springframework.util.Assert;
/**
* A {@link ScopeMetadataResolver} implementation that by default checks for
* the presence of Spring's {@link Scope} annotation on the bean class.
* the presence of Spring's {@link Scope @Scope} annotation on the bean class.
*
* <p>The exact type of annotation that is checked for is configurable via the
* {@link #setScopeAnnotationType(Class)} property.
* <p>The exact type of annotation that is checked for is configurable via
* {@link #setScopeAnnotationType(Class)}.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Sam Brannen
* @since 2.5
* @see org.springframework.context.annotation.Scope
*/
@ -43,27 +44,27 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
/**
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
* Construct a new {@code AnnotationScopeMetadataResolver}.
* @see #AnnotationScopeMetadataResolver(ScopedProxyMode)
* @see ScopedProxyMode#NO
*/
public AnnotationScopeMetadataResolver() {
this.defaultProxyMode = ScopedProxyMode.NO;
this(ScopedProxyMode.NO);
}
/**
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
* @param defaultProxyMode the desired scoped-proxy mode
* Construct a new {@code AnnotationScopeMetadataResolver} using the
* supplied default {@link ScopedProxyMode}.
* @param defaultProxyMode the default scoped-proxy mode
*/
public AnnotationScopeMetadataResolver(ScopedProxyMode defaultProxyMode) {
Assert.notNull(defaultProxyMode, "'defaultProxyMode' must not be null");
this.defaultProxyMode = defaultProxyMode;
}
/**
* Set the type of annotation that is checked for by this
* {@link AnnotationScopeMetadataResolver}.
* {@code AnnotationScopeMetadataResolver}.
* @param scopeAnnotationType the target annotation type
*/
public void setScopeAnnotationType(Class<? extends Annotation> scopeAnnotationType) {
@ -71,7 +72,6 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
this.scopeAnnotationType = scopeAnnotationType;
}
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
@ -79,9 +79,9 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
metadata.setScopeName(attributes.getAliasedString("value", this.scopeAnnotationType, definition.getSource()));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
if ((proxyMode == null) || (proxyMode == ScopedProxyMode.DEFAULT)) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);

View File

@ -65,6 +65,7 @@ import org.springframework.util.StringUtils;
* @author Chris Beams
* @author Juergen Hoeller
* @author Phillip Webb
* @author Sam Brannen
* @since 3.0
* @see ConfigurationClassParser
*/
@ -242,10 +243,12 @@ class ConfigurationClassBeanDefinitionReader {
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes scope = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (scope != null) {
beanDef.setScope(scope.getString("value"));
proxyMode = scope.getEnum("proxyMode");
// TODO Determine why type is hard coded to org.springframework.context.annotation.Scope,
// since AnnotationScopeMetadataResolver supports a custom scope annotation type.
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getAliasedString("value", Scope.class, configClass.getResource()));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}

View File

@ -23,6 +23,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.annotation.AliasFor;
/**
* When used as a type-level annotation in conjunction with
@ -57,14 +58,25 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
public @interface Scope {
/**
* Specifies the scope to use for the annotated component/bean.
* <p>Defaults to {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
* @see ConfigurableBeanFactory#SCOPE_SINGLETON
* Alias for {@link #name}.
* @see #name
*/
@AliasFor(attribute = "name")
String value() default "";
/**
* Specifies the name of the scope to use for the annotated component/bean.
* <p>Defaults to an empty string ({@code ""}) which implies
* {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
* @since 4.2
* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
* @see ConfigurableBeanFactory#SCOPE_SINGLETON
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
* @see #value
*/
String value() default ConfigurableBeanFactory.SCOPE_SINGLETON;
@AliasFor(attribute = "value")
String name() default "";
/**
* Specifies whether a component should be configured as a scoped proxy

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -17,12 +17,9 @@
package org.springframework.context.annotation;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
@ -33,137 +30,130 @@ import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import static org.junit.Assert.*;
import static org.springframework.context.annotation.ScopedProxyMode.*;
/**
* Unit tests for {@link AnnotationScopeMetadataResolver}.
*
* @author Rick Evans
* @author Chris Beams
* @author Juergen Hoeller
* @author Sam Brannen
*/
public final class AnnotationScopeMetadataResolverTests {
private AnnotationScopeMetadataResolver scopeMetadataResolver;
@Before
public void setUp() throws Exception {
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
}
public class AnnotationScopeMetadataResolverTests {
private AnnotationScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
@Test
public void testThatResolveScopeMetadataDoesNotApplyScopedProxyModeToASingleton() {
public void resolveScopeMetadataShouldNotApplyScopedProxyModeToSingleton() {
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithSingletonScope.class);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals(BeanDefinition.SCOPE_SINGLETON, scopeMetadata.getScopeName());
assertEquals(ScopedProxyMode.NO, scopeMetadata.getScopedProxyMode());
assertEquals(NO, scopeMetadata.getScopedProxyMode());
}
@Test
public void testThatResolveScopeMetadataDoesApplyScopedProxyModeToAPrototype() {
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(ScopedProxyMode.INTERFACES);
public void resolveScopeMetadataShouldApplyScopedProxyModeToPrototype() {
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(INTERFACES);
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithPrototypeScope.class);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals(BeanDefinition.SCOPE_PROTOTYPE, scopeMetadata.getScopeName());
assertEquals(ScopedProxyMode.INTERFACES, scopeMetadata.getScopedProxyMode());
assertEquals(INTERFACES, scopeMetadata.getScopedProxyMode());
}
@Test
public void testThatResolveScopeMetadataDoesReadScopedProxyModeFromTheAnnotation() {
public void resolveScopeMetadataShouldReadScopedProxyModeFromAnnotation() {
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithScopedProxy.class);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals("request", scopeMetadata.getScopeName());
assertEquals(ScopedProxyMode.TARGET_CLASS, scopeMetadata.getScopedProxyMode());
assertEquals(TARGET_CLASS, scopeMetadata.getScopedProxyMode());
}
@Test
public void testCustomRequestScope() {
public void customRequestScope() {
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithCustomRequestScope.class);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals("request", scopeMetadata.getScopeName());
assertEquals(ScopedProxyMode.NO, scopeMetadata.getScopedProxyMode());
assertEquals(NO, scopeMetadata.getScopedProxyMode());
}
@Test
public void testCustomRequestScopeViaAsm() throws IOException {
public void customRequestScopeViaAsm() throws IOException {
MetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory();
MetadataReader reader = readerFactory.getMetadataReader(AnnotatedWithCustomRequestScope.class.getName());
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(reader.getAnnotationMetadata());
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals("request", scopeMetadata.getScopeName());
assertEquals(ScopedProxyMode.NO, scopeMetadata.getScopedProxyMode());
assertEquals(NO, scopeMetadata.getScopedProxyMode());
}
@Test
public void testCustomRequestScopeWithAttribute() {
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithCustomRequestScopeWithAttribute.class);
public void customRequestScopeWithAttribute() {
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(
AnnotatedWithCustomRequestScopeWithAttributeOverride.class);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals("request", scopeMetadata.getScopeName());
assertEquals(ScopedProxyMode.TARGET_CLASS, scopeMetadata.getScopedProxyMode());
assertEquals(TARGET_CLASS, scopeMetadata.getScopedProxyMode());
}
@Test
public void testCustomRequestScopeWithAttributeViaAsm() throws IOException {
public void customRequestScopeWithAttributeViaAsm() throws IOException {
MetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory();
MetadataReader reader = readerFactory.getMetadataReader(AnnotatedWithCustomRequestScopeWithAttribute.class.getName());
MetadataReader reader = readerFactory.getMetadataReader(AnnotatedWithCustomRequestScopeWithAttributeOverride.class.getName());
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(reader.getAnnotationMetadata());
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals("request", scopeMetadata.getScopeName());
assertEquals(ScopedProxyMode.TARGET_CLASS, scopeMetadata.getScopedProxyMode());
assertEquals(TARGET_CLASS, scopeMetadata.getScopedProxyMode());
}
@Test(expected=IllegalArgumentException.class)
public void testCtorWithNullScopedProxyMode() {
@Test(expected = IllegalArgumentException.class)
public void ctorWithNullScopedProxyMode() {
new AnnotationScopeMetadataResolver(null);
}
@Test(expected=IllegalArgumentException.class)
public void testSetScopeAnnotationTypeWithNullType() {
@Test(expected = IllegalArgumentException.class)
public void setScopeAnnotationTypeWithNullType() {
scopeMetadataResolver.setScopeAnnotationType(null);
}
@Scope("singleton")
private static final class AnnotatedWithSingletonScope {
}
@Scope("prototype")
private static final class AnnotatedWithPrototypeScope {
}
@Scope(value="request", proxyMode = ScopedProxyMode.TARGET_CLASS)
private static final class AnnotatedWithScopedProxy {
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Scope("request")
public @interface CustomRequestScope {
@interface CustomRequestScope {
}
@CustomRequestScope
private static final class AnnotatedWithCustomRequestScope {
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Scope("request")
public @interface CustomRequestScopeWithAttribute {
@interface CustomRequestScopeWithAttributeOverride {
ScopedProxyMode proxyMode();
}
@CustomRequestScopeWithAttribute(proxyMode = ScopedProxyMode.TARGET_CLASS)
private static final class AnnotatedWithCustomRequestScopeWithAttribute {
@Scope("singleton")
private static class AnnotatedWithSingletonScope {
}
@Scope("prototype")
private static class AnnotatedWithPrototypeScope {
}
@Scope(name = "request", proxyMode = TARGET_CLASS)
private static class AnnotatedWithScopedProxy {
}
@CustomRequestScope
private static class AnnotatedWithCustomRequestScope {
}
@CustomRequestScopeWithAttributeOverride(proxyMode = TARGET_CLASS)
private static class AnnotatedWithCustomRequestScopeWithAttributeOverride {
}
}

View File

@ -787,7 +787,7 @@ public class ConfigurationClassPostProcessorTests {
public static class ScopedProxyRepositoryConfiguration {
@Bean
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Scope(name = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Repository<String> stringRepo() {
return new Repository<String>() {
@Override
@ -798,7 +798,7 @@ public class ConfigurationClassPostProcessorTests {
}
@Bean
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Scope(name = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Repository<Integer> integerRepo() {
return new Repository<Integer>() {
@Override