提交 94533976 编写于 作者: J Juergen Hoeller

full compliance with the JSR-330 TCK

上级 a429e230
......@@ -27,6 +27,7 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -270,28 +271,16 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
try {
metadata.injectFields(bean, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Autowiring of fields failed", ex);
}
return true;
}
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
try {
metadata.injectMethods(bean, beanName, pvs);
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Autowiring of methods failed", ex);
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
......@@ -300,15 +289,16 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
* 'Native' processing method for direct calls with an arbitrary target instance,
* resolving all of its fields and methods which are annotated with <code>@Autowired</code>.
* @param bean the target instance to process
* @throws BeansException if autowiring failed
*/
public void processInjection(Object bean) throws BeansException {
InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
Class<?> clazz = bean.getClass();
InjectionMetadata metadata = findAutowiringMetadata(clazz);
try {
metadata.injectFields(bean, null);
metadata.injectMethods(bean, null, null);
metadata.inject(bean, null, null);
}
catch (Throwable ex) {
throw new BeanCreationException("Autowiring of fields/methods failed", ex);
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
}
}
......@@ -320,36 +310,49 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
final InjectionMetadata newMetadata = new InjectionMetadata(clazz);
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
public void doWith(Field field) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
for (Field field : targetClass.getDeclaredFields()) {
Annotation annotation = findAutowiredAnnotation(field);
if (annotation != null) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("Autowired annotation is not supported on static fields");
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
continue;
}
boolean required = determineRequiredStatus(annotation);
newMetadata.addInjectedField(new AutowiredFieldElement(field, required));
currElements.add(new AutowiredFieldElement(field, required));
}
}
});
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
for (Method method : targetClass.getDeclaredMethods()) {
Annotation annotation = findAutowiredAnnotation(method);
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("Autowired annotation is not supported on static methods");
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
}
continue;
}
if (method.getParameterTypes().length == 0) {
throw new IllegalStateException("Autowired annotation requires at least one argument: " + method);
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation should be used on methods with actual parameters: " + method);
}
}
boolean required = determineRequiredStatus(annotation);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
newMetadata.addInjectedMethod(new AutowiredMethodElement(method, required, pd));
currElements.add(new AutowiredMethodElement(method, required, pd));
}
}
});
metadata = newMetadata;
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
metadata = new InjectionMetadata(clazz, elements);
this.injectionMetadataCache.put(clazz, metadata);
}
}
......
......@@ -49,42 +49,21 @@ public class InjectionMetadata {
private final Log logger = LogFactory.getLog(InjectionMetadata.class);
private String targetClassName;
private final Set<InjectedElement> injectedElements;
private final Set<InjectedElement> injectedFields = new LinkedHashSet<InjectedElement>();
private final Set<InjectedElement> injectedMethods = new LinkedHashSet<InjectedElement>();
public InjectionMetadata() {
}
public InjectionMetadata(Class targetClass) {
this.targetClassName = targetClass.getName();
}
public void addInjectedField(InjectedElement element) {
if (logger.isDebugEnabled()) {
logger.debug("Found injected field on class [" + this.targetClassName + "]: " + element);
}
this.injectedFields.add(element);
}
public void addInjectedMethod(InjectedElement element) {
if (logger.isDebugEnabled()) {
logger.debug("Found injected method on class [" + this.targetClassName + "]: " + element);
public InjectionMetadata(Class targetClass, Collection<InjectedElement> elements) {
this.injectedElements = new LinkedHashSet<InjectedElement>();
for (InjectedElement element : elements) {
if (logger.isDebugEnabled()) {
logger.debug("Found injected element on class [" + targetClass.getName() + "]: " + element);
}
this.injectedElements.add(element);
}
this.injectedMethods.add(element);
}
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
doRegisterConfigMembers(beanDefinition, this.injectedFields);
doRegisterConfigMembers(beanDefinition, this.injectedMethods);
}
private void doRegisterConfigMembers(RootBeanDefinition beanDefinition, Collection<InjectedElement> members) {
for (Iterator<InjectedElement> it = members.iterator(); it.hasNext();) {
for (Iterator<InjectedElement> it = this.injectedElements.iterator(); it.hasNext();) {
Member member = it.next().getMember();
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
beanDefinition.registerExternallyManagedConfigMember(member);
......@@ -95,22 +74,10 @@ public class InjectionMetadata {
}
}
public void injectFields(Object target, String beanName) throws Throwable {
if (!this.injectedFields.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : this.injectedFields) {
if (debug) {
logger.debug("Processing injected field of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, null);
}
}
}
public void injectMethods(Object target, String beanName, PropertyValues pvs) throws Throwable {
if (!this.injectedMethods.isEmpty()) {
public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
if (!this.injectedElements.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : this.injectedMethods) {
for (InjectedElement element : this.injectedElements) {
if (debug) {
logger.debug("Processing injected method of bean '" + beanName + "': " + element);
}
......
......@@ -780,12 +780,18 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class beanType, String beanName)
throws BeansException {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
try {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
catch (Exception ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing failed of bean type [" + beanType + "] failed", ex);
}
}
/**
......
/*
* Copyright 2002-2008 the original author or authors.
* 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.
......@@ -16,12 +16,10 @@
package org.springframework.beans.factory.support;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -152,8 +150,8 @@ public class BeanDefinitionReaderUtils {
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (int i = 0; i < aliases.length; i++) {
registry.registerAlias(beanName, aliases[i]);
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}
......
/*
* 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.lang.annotation.Annotation;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
/**
* Convenient adapter for programmatic registration of annotated bean classes.
*
*
* @author Juergen Hoeller
* @since 3.0
*/
public class AnnotatedBeanDefinitionReader {
private final BeanDefinitionRegistry registry;
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private boolean includeAnnotationConfig = true;
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this.registry = registry;
}
/**
* Return the BeanDefinitionRegistry that this scanner operates on.
*/
public final BeanDefinitionRegistry getRegistry() {
return this.registry;
}
/**
* Set the BeanNameGenerator to use for detected bean classes.
* <p>Default is a {@link AnnotationBeanNameGenerator}.
*/
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator());
}
/**
* Set the ScopeMetadataResolver to use for detected bean classes.
* Note that this will override any custom "scopedProxyMode" setting.
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
* @see #setScopedProxyMode
*/
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
this.scopeMetadataResolver = scopeMetadataResolver;
}
/**
* Specify the proxy behavior for non-singleton scoped beans.
* Note that this will override any custom "scopeMetadataResolver" setting.
* <p>The default is {@link ScopedProxyMode#NO}.
* @see #setScopeMetadataResolver
*/
public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) {
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode);
}
/**
* Specify whether to register annotation config post-processors.
* <p>The default is to register the post-processors. Turn this off
* to be able to ignore the annotations or to process them differently.
*/
public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) {
this.includeAnnotationConfig = includeAnnotationConfig;
}
public void registerBeans(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
public void registerBean(Class<?> annotatedClass) {
registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null);
}
public void registerBean(Class<?> annotatedClass, Class<? extends Annotation>... qualifiers) {
registerBean(annotatedClass, null, qualifiers);
}
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
if (abd.getMetadata().isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
if (abd.getMetadata().isAnnotated(Lazy.class.getName())) {
Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value");
abd.setLazyInit(value);
}
if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) {
String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value");
abd.setDependsOn(value);
}
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class.equals(qualifier)) {
abd.setPrimary(true);
}
else if (Lazy.class.equals(qualifier)) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = applyScopedProxyMode(definitionHolder, scopeMetadata);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
}
/**
* Apply the specified scope to the given bean definition.
* @param definition the bean definition to configure
* @param metadata the corresponding scope metadata
* @return the final bean definition to use (potentially a proxy)
*/
private BeanDefinitionHolder applyScopedProxyMode(BeanDefinitionHolder definition, ScopeMetadata metadata) {
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
return ScopedProxyCreator.createScopedProxy(definition, this.registry, proxyTargetClass);
}
}
......@@ -315,5 +315,4 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
return ScopedProxyCreator.createScopedProxy(definition, this.registry, proxyTargetClass);
}
}
......@@ -31,6 +31,7 @@ import java.net.URL;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
......@@ -62,7 +63,6 @@ import org.springframework.core.Ordered;
import org.springframework.jndi.support.SimpleJndiBeanFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
......@@ -283,13 +283,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
}
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
InjectionMetadata metadata = findResourceMetadata(bean.getClass());
try {
metadata.injectFields(bean, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource fields failed", ex);
}
return true;
}
......@@ -298,10 +291,10 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
InjectionMetadata metadata = findResourceMetadata(bean.getClass());
try {
metadata.injectMethods(bean, beanName, pvs);
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource methods failed", ex);
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
......@@ -314,33 +307,34 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
final InjectionMetadata newMetadata = new InjectionMetadata(clazz);
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
public void doWith(Field field) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
for (Field field : targetClass.getDeclaredFields()) {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
newMetadata.addInjectedField(new WebServiceRefElement(field, null));
currElements.add(new WebServiceRefElement(field, null));
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
newMetadata.addInjectedField(new EjbRefElement(field, null));
currElements.add(new EjbRefElement(field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!ignoredResourceTypes.contains(field.getType().getName())) {
newMetadata.addInjectedField(new ResourceElement(field, null));
currElements.add(new ResourceElement(field, null));
}
}
}
});
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
for (Method method : targetClass.getDeclaredMethods()) {
if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass) &&
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
......@@ -350,7 +344,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
newMetadata.addInjectedMethod(new WebServiceRefElement(method, pd));
currElements.add(new WebServiceRefElement(method, pd));
}
else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass) &&
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
......@@ -361,7 +355,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
newMetadata.addInjectedMethod(new EjbRefElement(method, pd));
currElements.add(new EjbRefElement(method, pd));
}
else if (method.isAnnotationPresent(Resource.class) &&
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
......@@ -374,12 +368,16 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
}
if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
newMetadata.addInjectedMethod(new ResourceElement(method, pd));
currElements.add(new ResourceElement(method, pd));
}
}
}
});
metadata = newMetadata;
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
metadata = new InjectionMetadata(clazz, elements);
this.injectionMetadataCache.put(clazz, metadata);
}
}
......
......@@ -16,19 +16,16 @@
package org.springframework.context.annotation;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.support.AbstractRefreshableApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
......@@ -108,8 +105,7 @@ public class ConfigurationClassApplicationContext extends AbstractRefreshableApp
* @see Configuration#value()
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws IOException, BeansException {
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
this.delegate.loadBeanDefinitions(beanFactory);
}
......@@ -162,34 +158,27 @@ public class ConfigurationClassApplicationContext extends AbstractRefreshableApp
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
for (Class<?> configClass : this.configClasses) {
AbstractBeanDefinition def = BeanDefinitionBuilder.rootBeanDefinition(configClass).getBeanDefinition();
RootBeanDefinition def = new RootBeanDefinition(configClass);
String name = AnnotationUtils.findAnnotation(configClass, Configuration.class).value();
if (!StringUtils.hasLength(name)) {
name = new DefaultBeanNameGenerator().generateBeanName(def, beanFactory);
}
beanFactory.registerBeanDefinition(name, def);
}
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
}
/**
* @see ConfigurationClassApplicationContext#getBean(Class)
*/
@SuppressWarnings("unchecked")
public <T> T getBean(Class<T> requiredType, AbstractApplicationContext context) {
public <T> T getBean(Class<T> requiredType, ListableBeanFactory context) {
Assert.notNull(requiredType, "requiredType may not be null");
Assert.notNull(context, "context may not be null");
Map<String, ?> beansOfType = context.getBeansOfType(requiredType);
Map<String, T> beansOfType = context.getBeansOfType(requiredType);
switch (beansOfType.size()) {
case 0:
throw new NoSuchBeanDefinitionException(requiredType);
case 1:
return (T) beansOfType.values().iterator().next();
return beansOfType.values().iterator().next();
default:
throw new NoSuchBeanDefinitionException(requiredType,
beansOfType.size() + " matching bean definitions found " +
......@@ -199,4 +188,5 @@ public class ConfigurationClassApplicationContext extends AbstractRefreshableApp
}
}
}
}
/*
* 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.jsr330;
import junit.framework.Test;
import org.atinject.tck.Tck;
import org.atinject.tck.auto.Car;
import org.atinject.tck.auto.Convertible;
import org.atinject.tck.auto.Drivers;
import org.atinject.tck.auto.DriversSeat;
import org.atinject.tck.auto.FuelTank;
import org.atinject.tck.auto.Seat;
import org.atinject.tck.auto.Tire;
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.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.ScopeMetadata;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.context.support.GenericApplicationContext;
/**
* @author Juergen Hoeller
* @since 3.0
*/
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.registerBean(Convertible.class);
bdr.registerBean(DriversSeat.class, Drivers.class);
bdr.registerBean(Seat.class, Primary.class);
bdr.registerBean(V8Engine.class);
bdr.registerBean(SpareTire.class, "spare");
bdr.registerBean(Cupholder.class);
bdr.registerBean(Tire.class, Primary.class);
bdr.registerBean(FuelTank.class);
ac.refresh();
Car car = ac.getBean("convertible", Car.class);
return Tck.testsFor(car, false, true);
}
public static Test suiteX() {
GenericApplicationContext ac = new GenericApplicationContext();
GenericBeanDefinition carDef = new GenericBeanDefinition();
carDef.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
carDef.setBeanClass(Convertible.class);
ac.registerBeanDefinition("car", carDef);
GenericBeanDefinition driversSeatDef = new GenericBeanDefinition();
driversSeatDef.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
driversSeatDef.setBeanClass(DriversSeat.class);
driversSeatDef.addQualifier(new AutowireCandidateQualifier(Drivers.class));
ac.registerBeanDefinition("driversSeat", driversSeatDef);
GenericBeanDefinition seatDef = new GenericBeanDefinition();
seatDef.setBeanClass(Seat.class);
seatDef.setPrimary(true);
ac.registerBeanDefinition("seat", seatDef);
GenericBeanDefinition engineDef = new GenericBeanDefinition();
engineDef.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
engineDef.setBeanClass(V8Engine.class);
ac.registerBeanDefinition("engine", engineDef);
GenericBeanDefinition spareDef = new GenericBeanDefinition();
spareDef.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
spareDef.setBeanClass(SpareTire.class);
spareDef.addQualifier(new AutowireCandidateQualifier(Drivers.class));
ac.registerBeanDefinition("spare", spareDef);
GenericBeanDefinition cupholderDef = new GenericBeanDefinition();
cupholderDef.setBeanClass(Cupholder.class);
ac.registerBeanDefinition("cupholder", cupholderDef);
GenericBeanDefinition tireDef = new GenericBeanDefinition();
tireDef.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
tireDef.setBeanClass(Tire.class);
tireDef.setPrimary(true);
ac.registerBeanDefinition("tire", tireDef);
GenericBeanDefinition fuelTankDef = new GenericBeanDefinition();
fuelTankDef.setBeanClass(FuelTank.class);
ac.registerBeanDefinition("fuelTank", fuelTankDef);
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
ac.refresh();
Car car = ac.getBean("car", Car.class);
return Tck.testsFor(car, false, true);
}
}
......@@ -694,13 +694,28 @@ public abstract class ClassUtils {
*/
public static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
Method specificMethod = null;
if (method != null && !Modifier.isPrivate(method.getModifiers()) &&
if (method != null && isOverridable(method, targetClass) &&
targetClass != null && !targetClass.equals(method.getDeclaringClass())) {
specificMethod = ReflectionUtils.findMethod(targetClass, method.getName(), method.getParameterTypes());
}
return (specificMethod != null ? specificMethod : method);
}
/**
* Determine whether the given method is overridable in the given target class.
* @param method the method to check
* @param targetClass the target class to check against
*/
private static boolean isOverridable(Method method, Class targetClass) {
if (Modifier.isPrivate(method.getModifiers())) {
return false;
}
if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) {
return true;
}
return getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass));
}
/**
* Return a static method of a class.
* @param methodName the static method name
......
......@@ -433,12 +433,12 @@ public abstract class ReflectionUtils {
* class and superclasses.
* <p>The same named method occurring on subclass and superclass will appear
* twice, unless excluded by a {@link MethodFilter}.
* @param targetClass class to start looking at
* @param clazz class to start looking at
* @param mc the callback to invoke for each method
* @see #doWithMethods(Class, MethodCallback, MethodFilter)
*/
public static void doWithMethods(Class<?> targetClass, MethodCallback mc) throws IllegalArgumentException {
doWithMethods(targetClass, mc, null);
public static void doWithMethods(Class<?> clazz, MethodCallback mc) throws IllegalArgumentException {
doWithMethods(clazz, mc, null);
}
/**
......@@ -446,14 +446,15 @@ public abstract class ReflectionUtils {
* class and superclasses.
* <p>The same named method occurring on subclass and superclass will appear
* twice, unless excluded by the specified {@link MethodFilter}.
* @param targetClass class to start looking at
* @param clazz class to start looking at
* @param mc the callback to invoke for each method
* @param mf the filter that determines the methods to apply the callback to
*/
public static void doWithMethods(Class<?> targetClass, MethodCallback mc, MethodFilter mf)
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf)
throws IllegalArgumentException {
// Keep backing up the inheritance hierarchy.
Class<?> targetClass = clazz;
do {
Method[] methods = targetClass.getDeclaredMethods();
for (Method method : methods) {
......@@ -469,7 +470,8 @@ public abstract class ReflectionUtils {
}
}
targetClass = targetClass.getSuperclass();
} while (targetClass != null);
}
while (targetClass != null);
}
/**
......@@ -489,26 +491,26 @@ public abstract class ReflectionUtils {
/**
* Invoke the given callback on all fields in the target class, going up the
* class hierarchy to get all declared fields.
* @param targetClass the target class to analyze
* @param clazz the target class to analyze
* @param fc the callback to invoke for each field
*/
public static void doWithFields(Class<?> targetClass, FieldCallback fc) throws IllegalArgumentException {
doWithFields(targetClass, fc, null);
public static void doWithFields(Class<?> clazz, FieldCallback fc) throws IllegalArgumentException {
doWithFields(clazz, fc, null);
}
/**
* Invoke the given callback on all fields in the target class, going up the
* class hierarchy to get all declared fields.
* @param targetClass the target class to analyze
* @param clazz the target class to analyze
* @param fc the callback to invoke for each field
* @param ff the filter that determines the fields to apply the callback to
*/
public static void doWithFields(Class<?> targetClass, FieldCallback fc, FieldFilter ff)
public static void doWithFields(Class<?> clazz, FieldCallback fc, FieldFilter ff)
throws IllegalArgumentException {
// Keep backing up the inheritance hierarchy.
Class<?> targetClass = clazz;
do {
// Copy each field declared on this class unless it's static or file.
Field[] fields = targetClass.getDeclaredFields();
for (Field field : fields) {
// Skip static and final fields.
......@@ -519,12 +521,13 @@ public abstract class ReflectionUtils {
fc.doWith(field);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Shouldn't be illegal to access field '" + field.getName() + "': "
+ ex);
throw new IllegalStateException(
"Shouldn't be illegal to access field '" + field.getName() + "': " + ex);
}
}
targetClass = targetClass.getSuperclass();
} while (targetClass != null && targetClass != Object.class);
}
while (targetClass != null && targetClass != Object.class);
}
/**
......
......@@ -23,6 +23,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
......@@ -59,7 +60,6 @@ import org.springframework.orm.jpa.ExtendedEntityManagerCreator;
import org.springframework.orm.jpa.SharedEntityManagerCreator;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
* BeanPostProcessor that processes {@link javax.persistence.PersistenceUnit}
......@@ -302,13 +302,6 @@ public class PersistenceAnnotationBeanPostProcessor extends JndiLocatorSupport
}
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
InjectionMetadata metadata = findPersistenceMetadata(bean.getClass());
try {
metadata.injectFields(bean, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of persistence fields failed", ex);
}
return true;
}
......@@ -317,10 +310,10 @@ public class PersistenceAnnotationBeanPostProcessor extends JndiLocatorSupport
InjectionMetadata metadata = findPersistenceMetadata(bean.getClass());
try {
metadata.injectMethods(bean, beanName, pvs);
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of persistence methods failed", ex);
throw new BeanCreationException(beanName, "Injection of persistence dependencies failed", ex);
}
return pvs;
}
......@@ -346,21 +339,22 @@ public class PersistenceAnnotationBeanPostProcessor extends JndiLocatorSupport
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
final InjectionMetadata newMetadata = new InjectionMetadata(clazz);
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
public void doWith(Field field) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
for (Field field : targetClass.getDeclaredFields()) {
PersistenceContext pc = field.getAnnotation(PersistenceContext.class);
PersistenceUnit pu = field.getAnnotation(PersistenceUnit.class);
if (pc != null || pu != null) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("Persistence annotations are not supported on static fields");
}
newMetadata.addInjectedField(new PersistenceElement(field, null));
currElements.add(new PersistenceElement(field, null));
}
}
});
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
for (Method method : targetClass.getDeclaredMethods()) {
PersistenceContext pc = method.getAnnotation(PersistenceContext.class);
PersistenceUnit pu = method.getAnnotation(PersistenceUnit.class);
if (pc != null || pu != null &&
......@@ -372,11 +366,15 @@ public class PersistenceAnnotationBeanPostProcessor extends JndiLocatorSupport
throw new IllegalStateException("Persistence annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
newMetadata.addInjectedMethod(new PersistenceElement(method, pd));
currElements.add(new PersistenceElement(method, pd));
}
}
});
metadata = newMetadata;
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
metadata = new InjectionMetadata(clazz, elements);
this.injectionMetadataCache.put(clazz, metadata);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册