diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Jsr330ScopeMetadataResolver.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Jsr330ScopeMetadataResolver.java
new file mode 100644
index 00000000000..61e79114b96
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Jsr330ScopeMetadataResolver.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2002-2009 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.context.annotation;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinition;
+
+/**
+ * Simple {@link ScopeMetadataResolver} implementation that follows JSR-330 scoping rules:
+ * defaulting to prototype scope unless {@link javax.inject.Singleton} is present.
+ *
+ *
This scope resolver can be used with {@link ClassPathBeanDefinitionScanner} and
+ * {@link AnnotatedBeanDefinitionReader} for standard JSR-330 compliance. However,
+ * in practice, you will typically use Spring's rich default scoping instead - or extend
+ * this resolver with custom scoping annotations that point to extended Spring scopes.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see #registerScope
+ * @see #resolveScopeName
+ * @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver
+ * @see AnnotatedBeanDefinitionReader#setScopeMetadataResolver
+ */
+public class Jsr330ScopeMetadataResolver implements ScopeMetadataResolver {
+
+ private final Map scopeMap = new HashMap();
+
+
+ public Jsr330ScopeMetadataResolver() {
+ registerScope("javax.inject.Singleton", BeanDefinition.SCOPE_SINGLETON);
+ }
+
+
+ /**
+ * Register an extended JSR-330 scope annotation, mapping it onto a
+ * specific Spring scope by name.
+ * @param annotationType the JSR-330 annotation type as a Class
+ * @param scopeName the Spring scope name
+ */
+ public final void registerScope(Class annotationType, String scopeName) {
+ this.scopeMap.put(annotationType.getName(), scopeName);
+ }
+
+ /**
+ * Register an extended JSR-330 scope annotation, mapping it onto a
+ * specific Spring scope by name.
+ * @param annotationType the JSR-330 annotation type by name
+ * @param scopeName the Spring scope name
+ */
+ public final void registerScope(String annotationType, String scopeName) {
+ this.scopeMap.put(annotationType, scopeName);
+ }
+
+ /**
+ * Resolve the given annotation type into a named Spring scope.
+ * The default implementation simply checks against registered scopes.
+ * Can be overridden for custom mapping rules, e.g. naming conventions.
+ * @param annotationType the JSR-330 annotation type
+ * @return the Spring scope name
+ */
+ protected String resolveScopeName(String annotationType) {
+ return this.scopeMap.get(annotationType);
+ }
+
+
+ public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
+ ScopeMetadata metadata = new ScopeMetadata();
+ metadata.setScopeName(BeanDefinition.SCOPE_PROTOTYPE);
+ if (definition instanceof AnnotatedBeanDefinition) {
+ AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
+ Set annTypes = annDef.getMetadata().getAnnotationTypes();
+ String found = null;
+ for (String annType : annTypes) {
+ Set metaAnns = annDef.getMetadata().getMetaAnnotationTypes(annType);
+ if (metaAnns.contains("javax.inject.Scope")) {
+ if (found != null) {
+ throw new IllegalStateException("Found ambiguous scope annotations on bean class [" +
+ definition.getBeanClassName() + "]: " + found + ", " + annType);
+ }
+ found = annType;
+ String scopeName = resolveScopeName(annType);
+ if (scopeName == null) {
+ throw new IllegalStateException(
+ "Unsupported scope annotation - not mapped onto Spring scope name: " + annType);
+ }
+ metadata.setScopeName(scopeName);
+ }
+ }
+ }
+ return metadata;
+ }
+
+}
diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTck.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTck.java
index 821b0465abb..860430c3478 100644
--- a/org.springframework.context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTck.java
+++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTck.java
@@ -29,12 +29,9 @@ import org.atinject.tck.auto.V8Engine;
import org.atinject.tck.auto.accessories.Cupholder;
import org.atinject.tck.auto.accessories.SpareTire;
-import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
-import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
+import org.springframework.context.annotation.Jsr330ScopeMetadataResolver;
import org.springframework.context.annotation.Primary;
-import org.springframework.context.annotation.ScopeMetadata;
-import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.context.support.GenericApplicationContext;
/**
@@ -46,17 +43,7 @@ public class SpringAtInjectTck {
public static Test suite() {
GenericApplicationContext ac = new GenericApplicationContext();
AnnotatedBeanDefinitionReader bdr = new AnnotatedBeanDefinitionReader(ac);
- bdr.setScopeMetadataResolver(new ScopeMetadataResolver() {
- public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
- ScopeMetadata metadata = new ScopeMetadata();
- if (definition instanceof AnnotatedBeanDefinition) {
- AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
- metadata.setScopeName(annDef.getMetadata().hasAnnotation(javax.inject.Singleton.class.getName()) ?
- BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);
- }
- return metadata;
- }
- });
+ bdr.setScopeMetadataResolver(new Jsr330ScopeMetadataResolver());
bdr.registerBean(Convertible.class);
bdr.registerBean(DriversSeat.class, Drivers.class);