diff --git a/org.springframework.aop/src/main/java/org/springframework/aop/config/AbstractInterceptorDrivenBeanDefinitionDecorator.java b/org.springframework.aop/src/main/java/org/springframework/aop/config/AbstractInterceptorDrivenBeanDefinitionDecorator.java index 524d0f2df4a..628333b7fb3 100644 --- a/org.springframework.aop/src/main/java/org/springframework/aop/config/AbstractInterceptorDrivenBeanDefinitionDecorator.java +++ b/org.springframework.aop/src/main/java/org/springframework/aop/config/AbstractInterceptorDrivenBeanDefinitionDecorator.java @@ -64,13 +64,15 @@ public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implement // get the root bean name - will be the name of the generated proxy factory bean String existingBeanName = definitionHolder.getBeanName(); BeanDefinition targetDefinition = definitionHolder.getBeanDefinition(); + BeanDefinitionHolder targetHolder = new BeanDefinitionHolder(targetDefinition, existingBeanName + ".TARGET"); // delegate to subclass for interceptor definition BeanDefinition interceptorDefinition = createInterceptorDefinition(node); // generate name and register the interceptor String interceptorName = existingBeanName + "." + getInterceptorNameSuffix(interceptorDefinition); - BeanDefinitionReaderUtils.registerBeanDefinition(new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry); + BeanDefinitionReaderUtils.registerBeanDefinition( + new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry); BeanDefinitionHolder result = definitionHolder; @@ -79,8 +81,10 @@ public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implement RootBeanDefinition proxyDefinition = new RootBeanDefinition(); // create proxy factory bean definition proxyDefinition.setBeanClass(ProxyFactoryBean.class); + proxyDefinition.setScope(targetDefinition.getScope()); // set the target - proxyDefinition.getPropertyValues().add("target", targetDefinition); + proxyDefinition.setDecoratedDefinition(targetHolder); + proxyDefinition.getPropertyValues().add("target", targetHolder); // create the interceptor names list proxyDefinition.getPropertyValues().add("interceptorNames", new ManagedList()); // copy autowire settings from original bean definition. diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 3c418e4714f..5955a6888cc 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -57,6 +57,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.SmartFactoryBean; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.beans.factory.config.BeanPostProcessor; @@ -473,7 +474,20 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp return parentBeanFactory.isTypeMatch(originalBeanName(name), targetType); } + // Retrieve corresponding bean definition. RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); + + // Check decorated bean definition, if any: We assume it'll be easier + // to determine the decorated bean's type than the proxy's type. + BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); + if (dbd != null) { + RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd); + Class targetClass = predictBeanType(dbd.getBeanName(), tbd, FactoryBean.class, typeToMatch); + if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) { + return typeToMatch.isAssignableFrom(targetClass); + } + } + Class beanClass = predictBeanType(beanName, mbd, FactoryBean.class, typeToMatch); if (beanClass == null) { return false; diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java index 44c6d3c6286..5dc0dd0d717 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java @@ -24,6 +24,7 @@ import java.util.Set; import org.springframework.beans.MutablePropertyValues; 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.Assert; @@ -53,6 +54,8 @@ public class RootBeanDefinition extends AbstractBeanDefinition { private final Set externallyManagedDestroyMethods = Collections.synchronizedSet(new HashSet()); + private BeanDefinitionHolder decoratedDefinition; + boolean isFactoryMethodUnique; /** Package-visible field for caching the resolved constructor or factory method */ @@ -75,7 +78,6 @@ public class RootBeanDefinition extends AbstractBeanDefinition { final Object postProcessingLock = new Object(); - /** * Create a new RootBeanDefinition, to be configured through its bean * properties and configuration methods. @@ -224,7 +226,9 @@ public class RootBeanDefinition extends AbstractBeanDefinition { RootBeanDefinition(BeanDefinition original) { super(original); if (original instanceof RootBeanDefinition) { - this.isFactoryMethodUnique = ((RootBeanDefinition) original).isFactoryMethodUnique; + RootBeanDefinition originalRbd = (RootBeanDefinition) original; + this.decoratedDefinition = originalRbd.decoratedDefinition; + this.isFactoryMethodUnique = originalRbd.isFactoryMethodUnique; } } @@ -289,6 +293,14 @@ public class RootBeanDefinition extends AbstractBeanDefinition { return this.externallyManagedDestroyMethods.contains(destroyMethod); } + public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) { + this.decoratedDefinition = decoratedDefinition; + } + + public BeanDefinitionHolder getDecoratedDefinition() { + return this.decoratedDefinition; + } + @Override public RootBeanDefinition cloneBeanDefinition() { diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests-context.xml b/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests-context.xml index 723437cb21c..0e8bf1f076c 100644 --- a/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests-context.xml +++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests-context.xml @@ -19,6 +19,10 @@ + + + + diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests.java b/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests.java index 80129ae5d47..2e9e369aaac 100644 --- a/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests.java +++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/support/CustomNamespaceHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2010 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,24 +16,32 @@ package org.springframework.beans.factory.xml.support; -import static java.lang.String.format; -import static org.junit.Assert.*; - import java.io.IOException; +import static java.lang.String.format; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; +import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import test.interceptor.NopInterceptor; + import org.springframework.aop.Advisor; import org.springframework.aop.config.AbstractInterceptorDrivenBeanDefinitionDecorator; import org.springframework.aop.framework.Advised; import org.springframework.aop.interceptor.DebugInterceptor; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.ITestBean; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.AbstractBeanDefinition; @@ -51,12 +59,6 @@ import org.springframework.beans.factory.xml.PluggableSchemaResolver; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.xml.sax.InputSource; - -import test.interceptor.NopInterceptor; /** * Unit tests for custom XML namespace handler implementations. @@ -65,7 +67,7 @@ import test.interceptor.NopInterceptor; * @author Rick Evans * @author Chris Beams */ -public final class CustomNamespaceHandlerTests { +public class CustomNamespaceHandlerTests { private static final Class CLASS = CustomNamespaceHandlerTests.class; private static final String CLASSNAME = CLASS.getSimpleName(); @@ -92,29 +94,42 @@ public final class CustomNamespaceHandlerTests { @Test public void testSimpleParser() throws Exception { TestBean bean = (TestBean) this.beanFactory.getBean("testBean"); - assetTestBean(bean); + assertTestBean(bean); } @Test public void testSimpleDecorator() throws Exception { TestBean bean = (TestBean) this.beanFactory.getBean("customisedTestBean"); - assetTestBean(bean); + assertTestBean(bean); } @Test public void testProxyingDecorator() throws Exception { ITestBean bean = (ITestBean) this.beanFactory.getBean("debuggingTestBean"); - assetTestBean(bean); + assertTestBean(bean); assertTrue(AopUtils.isAopProxy(bean)); Advisor[] advisors = ((Advised) bean).getAdvisors(); assertEquals("Incorrect number of advisors", 1, advisors.length); assertEquals("Incorrect advice class.", DebugInterceptor.class, advisors[0].getAdvice().getClass()); } + @Test + public void testProxyingDecoratorNoInstance() throws Exception { + String[] beanNames = this.beanFactory.getBeanNamesForType(ITestBean.class); + assertTrue(Arrays.asList(beanNames).contains("debuggingTestBeanNoInstance")); + try { + this.beanFactory.getBean("debuggingTestBeanNoInstance"); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getRootCause() instanceof BeanInstantiationException); + } + } + @Test public void testChainedDecorators() throws Exception { ITestBean bean = (ITestBean) this.beanFactory.getBean("chainedTestBean"); - assetTestBean(bean); + assertTestBean(bean); assertTrue(AopUtils.isAopProxy(bean)); Advisor[] advisors = ((Advised) bean).getAdvisors(); assertEquals("Incorrect number of advisors", 2, advisors.length); @@ -159,7 +174,7 @@ public final class CustomNamespaceHandlerTests { } - private void assetTestBean(ITestBean bean) { + private void assertTestBean(ITestBean bean) { assertEquals("Invalid name", "Rob Harrop", bean.getName()); assertEquals("Invalid age", 23, bean.getAge()); } @@ -175,7 +190,6 @@ public final class CustomNamespaceHandlerTests { super(CLASS.getClassLoader()); } - public InputSource resolveEntity(String publicId, String systemId) throws IOException { InputSource source = super.resolveEntity(publicId, systemId); if (source == null) {