diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanDefinitionRegistrar.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanDefinitionRegistrar.java
deleted file mode 100644
index eeef64639f3..00000000000
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanDefinitionRegistrar.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.config.java.support;
-
-import java.lang.reflect.Method;
-
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-
-
-/**
- * Registers bean definition(s) for a particular method, usually based on its annotation
- * metadata.
- *
- *
Constraints
Implementations must have only a default constructor, or explicitly
- * declare a no-arg constructor.
- *
- * @see BeanMethod
- *
- * @author Chris Beams
- */
-// TODO: SJC-242 document FactoryMethodHandler
-// TODO: SJC-242 odd that the api here uses both ModelMethod and java.lang.reflect.Member
-// TODO: SJC-242 document that there must be a no-arg ctor
-interface BeanDefinitionRegistrar {
-
- /**
- * Determines whether this registrar is capable of handling method.
- */
- // TODO: rename to supports() in alignment with Validator nomenclature
- boolean accepts(Method method);
-
- /**
- * Registers any bean definitions for method with registry.
- */
- void register(BeanMethod method, BeanDefinitionRegistry registry);
-
-}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanMethod.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanMethod.java
index 71bd4204630..559f76171c6 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanMethod.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanMethod.java
@@ -38,6 +38,10 @@ import org.springframework.util.Assert;
* Represents a {@link Configuration} class method marked with the {@link Bean} annotation.
*
* @author Chris Beams
+ * @see ConfigurationClass
+ * @see ConfigurationModel
+ * @see ConfigurationParser
+ * @see ConfigurationModelBeanDefinitionReader
*/
final class BeanMethod implements BeanMetadataElement {
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanMethodInterceptor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanMethodInterceptor.java
index 8b8b53c1b8f..9d94a8118c6 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanMethodInterceptor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanMethodInterceptor.java
@@ -24,16 +24,12 @@ import net.sf.cglib.proxy.MethodProxy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.config.java.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.util.Assert;
/**
@@ -41,17 +37,16 @@ import org.springframework.util.Assert;
* handling of bean semantics such as scoping and AOP proxying.
*
* @author Chris Beams
- * @since 3.0
* @see Bean
- * @see BeanRegistrar
*/
-class BeanMethodInterceptor implements BeanFactoryAware, MethodInterceptor {
- protected final Log log = LogFactory.getLog(this.getClass());
- protected DefaultListableBeanFactory beanFactory;
+class BeanMethodInterceptor implements MethodInterceptor {
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- Assert.isInstanceOf(DefaultListableBeanFactory.class, beanFactory);
- this.beanFactory = (DefaultListableBeanFactory) beanFactory;
+ private static final Log log = LogFactory.getLog(BeanMethodInterceptor.class);
+
+ private final DefaultListableBeanFactory beanFactory;
+
+ public BeanMethodInterceptor(DefaultListableBeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
}
/**
@@ -60,20 +55,18 @@ class BeanMethodInterceptor implements BeanFactoryAware, MethodInterceptor {
*/
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
- // determine the name of the bean
- String beanName;
+ // by default the bean name is the name of the @Bean-annotated method
+ String beanName = method.getName();
+
// check to see if the user has explicitly set the bean name
Bean bean = method.getAnnotation(Bean.class);
- if(bean != null && bean.name().length > 1)
+ if(bean != null && bean.name().length > 0)
beanName = bean.name()[0];
- // if not, simply return the name of the method as the bean name
- else
- beanName = method.getName();
// determine whether this bean is a scoped-proxy
Scope scope = AnnotationUtils.findAnnotation(method, Scope.class);
boolean isScopedProxy = (scope != null && scope.proxyMode() != ScopedProxyMode.NO);
- String scopedBeanName = BeanRegistrar.resolveHiddenScopedProxyBeanName(beanName);
+ String scopedBeanName = ConfigurationModelBeanDefinitionReader.resolveHiddenScopedProxyBeanName(beanName);
if (isScopedProxy && beanFactory.isCurrentlyInCreation(scopedBeanName))
beanName = scopedBeanName;
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanRegistrar.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanRegistrar.java
deleted file mode 100644
index 2ba7af8b64d..00000000000
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/BeanRegistrar.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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.config.java.support;
-
-import static java.lang.String.*;
-import static org.springframework.util.StringUtils.*;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
-import org.springframework.aop.scope.ScopedProxyFactoryBean;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.RootBeanDefinition;
-import org.springframework.config.java.Bean;
-import org.springframework.context.annotation.Scope;
-import org.springframework.context.annotation.ScopedProxyMode;
-import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.util.Assert;
-
-
-class BeanRegistrar implements BeanDefinitionRegistrar {
-
- private static final Log logger = LogFactory.getLog(BeanRegistrar.class);
-
- /** Prefix used when registering the target object for a scoped proxy. */
- private static final String TARGET_NAME_PREFIX = "scopedTarget.";
-
- /**
- * Ensures that member is a method and is annotated (directly or indirectly)
- * with {@link Bean @Bean}.
- */
- public boolean accepts(Method method) {
- return AnnotationUtils.findAnnotation(method, Bean.class) != null;
- }
-
- public void register(BeanMethod method, BeanDefinitionRegistry registry) {
- RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition();
-
- ConfigurationClass configClass = method.getDeclaringClass();
-
- beanDef.setFactoryBeanName(configClass.getBeanName());
- beanDef.setFactoryMethodName(method.getName());
-
- Bean bean = method.getRequiredAnnotation(Bean.class);
-
- // TODO: prune defaults
- //Configuration defaults = configClass.getMetadata();
-
- // consider scoping
- Scope scope = method.getAnnotation(Scope.class);
- if(scope != null)
- beanDef.setScope(scope.value());
-
- // TODO: prune autowiring
-// // consider autowiring
-// if (bean.autowire() != AnnotationUtils.getDefaultValue(Bean.class, "autowire"))
-// beanDef.setAutowireMode(bean.autowire().value());
-// else if (defaults.defaultAutowire() != AnnotationUtils.getDefaultValue(Configuration.class,
-// "defaultAutowire"))
-// beanDef.setAutowireMode(defaults.defaultAutowire().value());
-
- // consider name and any aliases
- ArrayList names = new ArrayList(Arrays.asList(bean.name()));
- String beanName = (names.size() > 0) ? names.remove(0) : method.getName();
- for (String alias : bean.name())
- registry.registerAlias(beanName, alias);
-
- // has this already been overriden (i.e.: via XML)?
- if (containsBeanDefinitionIncludingAncestry(beanName, registry)) {
- BeanDefinition existingBeanDef = getBeanDefinitionIncludingAncestry(beanName, registry);
-
- // is the existing bean definition one that was created by JavaConfig?
- if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
- // no -> then it's an external override, probably XML
-
- // TODO: Prune this
-// // ensure that overriding is ok
-// if (bean.allowOverriding() == false) {
-// UsageError error = configClass.new IllegalBeanOverrideError(null, method);
-// throw new MalformedConfigurationException(error);
-// }
-
- // overriding is legal, return immediately
- logger.info(format("Skipping loading bean definition for %s: a definition for bean "
- + "'%s' already exists. This is likely due to an override in XML.", method, beanName));
- return;
- }
- }
-
- // TODO: re-enable for Lazy support
- // // is this bean marked as primary for disambiguation?
- // if (bean.primary() == Primary.TRUE)
- // beanDef.setPrimary(true);
- //
- // // is this bean lazily instantiated?
- // if ((bean.lazy() == Lazy.TRUE)
- // || ((bean.lazy() == Lazy.UNSPECIFIED) && (defaults.defaultLazy() == Lazy.TRUE)))
- // beanDef.setLazyInit(true);
-
- // does this bean have a custom init-method specified?
- String initMethodName = bean.initMethod();
- if (hasText(initMethodName))
- beanDef.setInitMethodName(initMethodName);
-
- // does this bean have a custom destroy-method specified?
- String destroyMethodName = bean.destroyMethod();
- if (hasText(destroyMethodName))
- beanDef.setDestroyMethodName(destroyMethodName);
-
- // is this method annotated with @Scope(scopedProxy=...)?
- if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {
- RootBeanDefinition targetDef = beanDef;
-
- // Create a scoped proxy definition for the original bean name,
- // "hiding" the target bean in an internal target definition.
- String targetBeanName = resolveHiddenScopedProxyBeanName(beanName);
- RootBeanDefinition scopedProxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
- scopedProxyDefinition.getPropertyValues().addPropertyValue("targetBeanName", targetBeanName);
-
- if (scope.proxyMode() == ScopedProxyMode.TARGET_CLASS)
- targetDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
- // ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we
- // don't need to set it explicitly here.
- else
- scopedProxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass", Boolean.FALSE);
-
- // The target bean should be ignored in favor of the scoped proxy.
- targetDef.setAutowireCandidate(false);
-
- // Register the target bean as separate bean in the factory
- registry.registerBeanDefinition(targetBeanName, targetDef);
-
- // replace the original bean definition with the target one
- beanDef = scopedProxyDefinition;
- }
-
- // TODO: re-enable for @Meta support
- // does this bean method have any @Meta annotations?
- // for (Meta meta : bean.meta())
- // beanDef.addMetadataAttribute(new BeanMetadataAttribute(meta.key(),
- // meta.value()));
-
- if (bean.dependsOn().length > 0)
- beanDef.setDependsOn(bean.dependsOn());
-
- logger.info(format("Registering bean definition for @Bean method %s.%s()",
- configClass.getName(), beanName));
-
- registry.registerBeanDefinition(beanName, beanDef);
-
- }
-
- private boolean containsBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
- try {
- getBeanDefinitionIncludingAncestry(beanName, registry);
- return true;
- } catch (NoSuchBeanDefinitionException ex) {
- return false;
- }
- }
-
- private BeanDefinition getBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
- if(!(registry instanceof ConfigurableListableBeanFactory)) {
- return registry.getBeanDefinition(beanName);
- }
-
- ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) registry;
-
- do {
- if (clbf.containsBeanDefinition(beanName))
- return registry.getBeanDefinition(beanName);
-
- BeanFactory parent = clbf.getParentBeanFactory();
- if (parent == null) {
- clbf = null;
- } else if (parent instanceof ConfigurableListableBeanFactory) {
- clbf = (ConfigurableListableBeanFactory) parent;
- // TODO: re-enable
- // } else if (parent instanceof AbstractApplicationContext) {
- // clbf = ((AbstractApplicationContext) parent).getBeanFactory();
- } else {
- throw new IllegalStateException("unknown parent type: " + parent.getClass().getName());
- }
- } while (clbf != null);
-
- throw new NoSuchBeanDefinitionException(format("No bean definition matching name '%s' "
- + "could be found in %s or its ancestry", beanName, registry));
- }
-
- /**
- * Return the hidden name based on a scoped proxy bean name.
- *
- * @param originalBeanName the scope proxy bean name as declared in the
- * Configuration-annotated class
- *
- * @return the internally-used hidden bean name
- */
- public static String resolveHiddenScopedProxyBeanName(String originalBeanName) {
- Assert.hasText(originalBeanName);
- return TARGET_NAME_PREFIX.concat(originalBeanName);
- }
-
-}
-
-/**
- * {@link RootBeanDefinition} marker subclass used to signify that a bean definition created
- * by JavaConfig as opposed to any other configuration source. Used in bean overriding cases
- * where it's necessary to determine whether the bean definition was created externally
- * (e.g. via XML).
- */
-@SuppressWarnings("serial")
-class ConfigurationClassBeanDefinition extends RootBeanDefinition {
-}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClass.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClass.java
index a5fafab2049..41a4207a6b5 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClass.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClass.java
@@ -29,7 +29,7 @@ import org.springframework.util.Assert;
/**
- * Abstract representation of a user-defined {@link Configuration @Configuration} class.
+ * Represents a user-defined {@link Configuration @Configuration} class.
* Includes a set of {@link Bean} methods, including all such methods defined in the
* ancestry of the class, in a 'flattened-out' manner. Note that each {@link BeanMethod}
* representation contains source information about where it was originally detected
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassMethodVisitor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassMethodVisitor.java
index b22d9144a5e..f445aed2e65 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassMethodVisitor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassMethodVisitor.java
@@ -27,15 +27,16 @@ import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.ClassAdapter;
import org.springframework.asm.Label;
import org.springframework.asm.MethodAdapter;
+import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.config.java.Bean;
import org.springframework.config.java.Configuration;
/**
- * Visits a single method declared in a given {@link Configuration} class. Determines
- * whether the method is a {@link Bean} method and if so, adds it to the
- * {@link ConfigurationClass}.
+ * ASM {@link MethodVisitor} that visits a single method declared in a given
+ * {@link Configuration} class. Determines whether the method is a {@link Bean}
+ * method and if so, adds it to the {@link ConfigurationClass}.
*
* @author Chris Beams
*/
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassVisitor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassVisitor.java
index 8615ae82de1..ea83eca2c3e 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassVisitor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassVisitor.java
@@ -25,6 +25,7 @@ import java.util.Stack;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.ClassAdapter;
import org.springframework.asm.ClassReader;
+import org.springframework.asm.ClassVisitor;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.beans.factory.parsing.Location;
@@ -36,10 +37,12 @@ import org.springframework.core.io.ClassPathResource;
/**
- * Visits a {@link Configuration} class, populating a {@link ConfigurationClass} instance
- * with information gleaned along the way.
+ * ASM {@link ClassVisitor} that visits a {@link Configuration} class, populating a
+ * {@link ConfigurationClass} instance with information gleaned along the way.
*
* @author Chris Beams
+ * @see ConfigurationParser
+ * @see ConfigurationClass
*/
class ConfigurationClassVisitor extends ClassAdapter {
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationEnhancer.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationEnhancer.java
index 97046c80d19..a916087b552 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationEnhancer.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationEnhancer.java
@@ -17,29 +17,27 @@ package org.springframework.config.java.support;
import static java.lang.String.*;
import static org.springframework.config.java.support.Util.*;
-import static org.springframework.util.Assert.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
import net.sf.cglib.core.DefaultGeneratorStrategy;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
-import net.sf.cglib.proxy.MethodInterceptor;
-import net.sf.cglib.proxy.MethodProxy;
+import net.sf.cglib.proxy.NoOp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.asm.ClassAdapter;
import org.springframework.asm.ClassReader;
import org.springframework.asm.ClassWriter;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.config.java.Bean;
import org.springframework.config.java.Configuration;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.util.Assert;
/**
@@ -54,59 +52,30 @@ class ConfigurationEnhancer {
private static final Log log = LogFactory.getLog(ConfigurationEnhancer.class);
- private final ArrayList> callbackTypes = new ArrayList>();
-
- private final LinkedHashSet registrars = new LinkedHashSet();
-
private final ArrayList callbackInstances = new ArrayList();
-
- private final CallbackFilter callbackFilter = new CallbackFilter() {
- public int accept(Method candidateMethod) {
- Iterator iter = registrars.iterator();
- for (int i = 0; iter.hasNext(); i++)
- if (iter.next().accepts(candidateMethod))
- return i;
-
- throw new IllegalStateException(
- format("No registrar is capable of handling method [%s]. "
- + "Perhaps you forgot to add a catch-all registrar?",
- candidateMethod.getName()));
- }
- };
+ private final ArrayList> callbackTypes = new ArrayList>();
+ private final CallbackFilter callbackFilter;
/**
* Creates a new {@link ConfigurationEnhancer} instance.
*/
public ConfigurationEnhancer(DefaultListableBeanFactory beanFactory) {
- notNull(beanFactory, "beanFactory must be non-null");
-
- registrars.add(new BeanRegistrar());
- BeanMethodInterceptor beanMethodInterceptor = new BeanMethodInterceptor();
- beanMethodInterceptor.setBeanFactory(beanFactory);
- callbackInstances.add(beanMethodInterceptor);
-
- // add no-op default registrar and method interceptor
- registrars.add(new BeanDefinitionRegistrar() {
+ Assert.notNull(beanFactory, "beanFactory must be non-null");
- public boolean accepts(Method method) {
- return true;
- }
+ callbackInstances.add(new BeanMethodInterceptor(beanFactory));
+ callbackInstances.add(NoOp.INSTANCE);
- public void register(BeanMethod method, BeanDefinitionRegistry registry) {
- // no-op
- }
- });
- callbackInstances.add(new MethodInterceptor() {
-
- public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
- return null;
- }
-
- });
-
for (Callback callback : callbackInstances)
callbackTypes.add(callback.getClass());
+
+ // set up the callback filter to return the index of the BeanMethodInterceptor when
+ // handling a @Bean-annotated method; otherwise, return index of the NoOp callback.
+ callbackFilter = new CallbackFilter() {
+ public int accept(Method candidateMethod) {
+ return (AnnotationUtils.findAnnotation(candidateMethod, Bean.class) != null) ? 0 : 1;
+ }
+ };
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationModel.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationModel.java
index c2ea8230a1d..d0312088621 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationModel.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationModel.java
@@ -19,26 +19,22 @@ import static java.lang.String.*;
import java.util.ArrayList;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.config.java.Configuration;
/**
- * An abstract representation of a set of user-provided "Configuration classes", usually but
- * not necessarily annotated with {@link Configuration @Configuration}. The model is
- * populated with a
- * {@link org.springframework.config.java.support.ConfigurationParser}
- * implementation which may be reflection-based or ASM-based. Once a model has been
- * populated, it can then be rendered out to a set of BeanDefinitions. The model provides an
- * important layer of indirection between the complexity of parsing a set of classes and the
- * complexity of representing the contents of those classes as BeanDefinitions.
- *
- *
- * Interface follows the builder pattern for method chaining.
- *
+ * Represents the set of all user-defined {@link Configuration} classes. Once this model
+ * is populated using a {@link ConfigurationParser}, it can be rendered out to a set of
+ * {@link BeanDefinition} objects. This model provides an important layer of indirection
+ * between the complexity of parsing a set of classes and the complexity of representing
+ * the contents of those classes as BeanDefinitions.
*
* @author Chris Beams
- * @see org.springframework.config.java.support.ConfigurationParser
+ * @see ConfigurationClass
+ * @see ConfigurationParser
+ * @see ConfigurationModelBeanDefinitionReader
*/
final class ConfigurationModel {
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationModelBeanDefinitionReader.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationModelBeanDefinitionReader.java
index c58bb45c141..bc32a473760 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationModelBeanDefinitionReader.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationModelBeanDefinitionReader.java
@@ -16,17 +16,31 @@
package org.springframework.config.java.support;
import static java.lang.String.*;
+import static org.springframework.util.StringUtils.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
+import org.springframework.aop.scope.ScopedProxyFactoryBean;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
+import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.config.java.Bean;
import org.springframework.config.java.Configuration;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.core.io.Resource;
+import org.springframework.util.Assert;
/**
@@ -38,6 +52,8 @@ import org.springframework.core.io.Resource;
* {@link Resource}.
*
* @author Chris Beams
+ * @see ConfigurationModel
+ * @see AbstractConfigurationClassProcessor#processConfigBeanDefinitions()
*/
class ConfigurationModelBeanDefinitionReader {
@@ -46,12 +62,6 @@ class ConfigurationModelBeanDefinitionReader {
private BeanDefinitionRegistry registry;
- /**
- * Creates a new {@link ConfigurationModelBeanDefinitionReader} instance.
- */
- public ConfigurationModelBeanDefinitionReader() {
- }
-
/**
* Reads {@code model}, registering bean definitions with {@link #registry} based on
* its contents.
@@ -60,7 +70,7 @@ class ConfigurationModelBeanDefinitionReader {
*/
public BeanDefinitionRegistry loadBeanDefinitions(ConfigurationModel model) {
registry = new SimpleBeanDefinitionRegistry();
-
+
for (ConfigurationClass configClass : model.getAllConfigurationClasses())
loadBeanDefinitionsForConfigurationClass(configClass);
@@ -76,11 +86,6 @@ class ConfigurationModelBeanDefinitionReader {
for (BeanMethod method : configClass.getBeanMethods())
loadBeanDefinitionsForModelMethod(method);
-
-// Annotation[] pluginAnnotations = configClass.getPluginAnnotations();
-// Arrays.sort(pluginAnnotations, new PluginComparator());
-// for (Annotation annotation : pluginAnnotations)
-// loadBeanDefinitionsForExtensionAnnotation(beanDefs, annotation);
}
/**
@@ -117,40 +122,162 @@ class ConfigurationModelBeanDefinitionReader {
* {@link #registry} based on its contents.
*/
private void loadBeanDefinitionsForModelMethod(BeanMethod method) {
- new BeanRegistrar().register(method, registry);
+ RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition();
+
+ ConfigurationClass configClass = method.getDeclaringClass();
+
+ beanDef.setFactoryBeanName(configClass.getBeanName());
+ beanDef.setFactoryMethodName(method.getName());
+
+ Bean bean = method.getRequiredAnnotation(Bean.class);
+
+ // TODO: prune defaults
+ //Configuration defaults = configClass.getMetadata();
+
+ // consider scoping
+ Scope scope = method.getAnnotation(Scope.class);
+ if(scope != null)
+ beanDef.setScope(scope.value());
+
+ // consider name and any aliases
+ ArrayList names = new ArrayList(Arrays.asList(bean.name()));
+ String beanName = (names.size() > 0) ? names.remove(0) : method.getName();
+ for (String alias : bean.name())
+ registry.registerAlias(beanName, alias);
+
+ // has this already been overriden (i.e.: via XML)?
+ if (containsBeanDefinitionIncludingAncestry(beanName, registry)) {
+ BeanDefinition existingBeanDef = getBeanDefinitionIncludingAncestry(beanName, registry);
+
+ // is the existing bean definition one that was created by JavaConfig?
+ if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
+ // no -> then it's an external override, probably XML
+
+ // overriding is legal, return immediately
+ log.info(format("Skipping loading bean definition for %s: a definition for bean "
+ + "'%s' already exists. This is likely due to an override in XML.", method, beanName));
+ return;
+ }
+ }
+
+ // TODO: re-enable for Lazy support
+ // // is this bean marked as primary for disambiguation?
+ // if (bean.primary() == Primary.TRUE)
+ // beanDef.setPrimary(true);
+ //
+ // // is this bean lazily instantiated?
+ // if ((bean.lazy() == Lazy.TRUE)
+ // || ((bean.lazy() == Lazy.UNSPECIFIED) && (defaults.defaultLazy() == Lazy.TRUE)))
+ // beanDef.setLazyInit(true);
+
+ // does this bean have a custom init-method specified?
+ String initMethodName = bean.initMethod();
+ if (hasText(initMethodName))
+ beanDef.setInitMethodName(initMethodName);
+
+ // does this bean have a custom destroy-method specified?
+ String destroyMethodName = bean.destroyMethod();
+ if (hasText(destroyMethodName))
+ beanDef.setDestroyMethodName(destroyMethodName);
+
+ // is this method annotated with @Scope(scopedProxy=...)?
+ if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {
+ RootBeanDefinition targetDef = beanDef;
+
+ // Create a scoped proxy definition for the original bean name,
+ // "hiding" the target bean in an internal target definition.
+ String targetBeanName = resolveHiddenScopedProxyBeanName(beanName);
+ RootBeanDefinition scopedProxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
+ scopedProxyDefinition.getPropertyValues().addPropertyValue("targetBeanName", targetBeanName);
+
+ if (scope.proxyMode() == ScopedProxyMode.TARGET_CLASS)
+ targetDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
+ // ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we
+ // don't need to set it explicitly here.
+ else
+ scopedProxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass", Boolean.FALSE);
+
+ // The target bean should be ignored in favor of the scoped proxy.
+ targetDef.setAutowireCandidate(false);
+
+ // Register the target bean as separate bean in the factory
+ registry.registerBeanDefinition(targetBeanName, targetDef);
+
+ // replace the original bean definition with the target one
+ beanDef = scopedProxyDefinition;
+ }
+
+ if (bean.dependsOn().length > 0)
+ beanDef.setDependsOn(bean.dependsOn());
+
+ log.info(format("Registering bean definition for @Bean method %s.%s()",
+ configClass.getName(), beanName));
+
+ registry.registerBeanDefinition(beanName, beanDef);
+
}
-// @SuppressWarnings("unchecked")
-// private void loadBeanDefinitionsForExtensionAnnotation(Map beanDefs, Annotation anno) {
-// // ExtensionAnnotationUtils.getRegistrarFor(anno).registerBeanDefinitionsWith(beanFactory);
-// // there is a fixed assumption that in order for this annotation to have
-// // been registered in the first place, it must be meta-annotated with @Plugin
-// // assert this as an invariant now
-// Class> annoClass = anno.getClass();
-// Extension extensionAnno = AnnotationUtils.findAnnotation(annoClass, Extension.class);
-// Assert.isTrue(extensionAnno != null, format("%s annotation is not annotated as a @%s", annoClass,
-// Extension.class.getSimpleName()));
-//
-// Class extends ExtensionAnnotationBeanDefinitionRegistrar> extHandlerClass = extensionAnno.handler();
-//
-// ExtensionAnnotationBeanDefinitionRegistrar extHandler = getInstance(extHandlerClass);
-// extHandler.handle(anno, beanFactory);
-// }
-//
-// private static class PluginComparator implements Comparator {
-// public int compare(Annotation a1, Annotation a2) {
-// Integer i1 = getOrder(a1);
-// Integer i2 = getOrder(a2);
-// return i1.compareTo(i2);
-// }
-//
-// private Integer getOrder(Annotation a) {
-// Extension plugin = a.annotationType().getAnnotation(Extension.class);
-// if (plugin == null)
-// throw new IllegalArgumentException("annotation was not annotated with @Plugin: "
-// + a.annotationType());
-// return plugin.order();
-// }
-// }
+ private boolean containsBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
+ try {
+ getBeanDefinitionIncludingAncestry(beanName, registry);
+ return true;
+ } catch (NoSuchBeanDefinitionException ex) {
+ return false;
+ }
+ }
+ private BeanDefinition getBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
+ if(!(registry instanceof ConfigurableListableBeanFactory))
+ return registry.getBeanDefinition(beanName);
+
+ ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) registry;
+
+ do {
+ if (clbf.containsBeanDefinition(beanName))
+ return registry.getBeanDefinition(beanName);
+
+ BeanFactory parent = clbf.getParentBeanFactory();
+ if (parent == null) {
+ clbf = null;
+ } else if (parent instanceof ConfigurableListableBeanFactory) {
+ clbf = (ConfigurableListableBeanFactory) parent;
+ // TODO: re-enable
+ // } else if (parent instanceof AbstractApplicationContext) {
+ // clbf = ((AbstractApplicationContext) parent).getBeanFactory();
+ } else {
+ throw new IllegalStateException("unknown parent type: " + parent.getClass().getName());
+ }
+ } while (clbf != null);
+
+ throw new NoSuchBeanDefinitionException(
+ format("No bean definition matching name '%s' " +
+ "could be found in %s or its ancestry", beanName, registry));
+ }
+
+ /**
+ * Return the hidden name based on a scoped proxy bean name.
+ *
+ * @param originalBeanName the scope proxy bean name as declared in the
+ * Configuration-annotated class
+ *
+ * @return the internally-used hidden bean name
+ */
+ public static String resolveHiddenScopedProxyBeanName(String originalBeanName) {
+ Assert.hasText(originalBeanName);
+ return TARGET_NAME_PREFIX.concat(originalBeanName);
+ }
+
+ /** Prefix used when registering the target object for a scoped proxy. */
+ private static final String TARGET_NAME_PREFIX = "scopedTarget.";
+}
+
+
+/**
+ * {@link RootBeanDefinition} marker subclass used to signify that a bean definition created
+ * by JavaConfig as opposed to any other configuration source. Used in bean overriding cases
+ * where it's necessary to determine whether the bean definition was created externally
+ * (e.g. via XML).
+ */
+@SuppressWarnings("serial")
+class ConfigurationClassBeanDefinition extends RootBeanDefinition {
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationParser.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationParser.java
index 96915e865f5..9f6323afdb5 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationParser.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationParser.java
@@ -46,9 +46,11 @@ public class ConfigurationParser {
private final ClassLoader classLoader;
/**
- * Creates a new parser instance that will be used to populate model.
- * @param model model to be populated by each successive call to
- * {@link #parse(Object, String)}
+ * Creates a new {@link ConfigurationParser} instance that will be used to populate a
+ * {@link ConfigurationModel}.
+ *
+ * @param model model to be populated by each successive call to {@link #parse}
+ * @see #getConfigurationModel()
*/
public ConfigurationParser(ProblemReporter problemReporter, ClassLoader classLoader) {
this.model = new ConfigurationModel();
@@ -77,6 +79,9 @@ public class ConfigurationParser {
model.add(configClass);
}
+ /**
+ * Returns the current {@link ConfigurationModel}, to be called after {@link #parse}.
+ */
public ConfigurationModel getConfigurationModel() {
return model;
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ImportStack.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ImportStack.java
index 60e42cbf87d..70967bc0846 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ImportStack.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ImportStack.java
@@ -25,7 +25,7 @@ import org.springframework.util.Assert;
/**
- * Stack used for detecting circular use of the {@link Import} annotation.
+ * {@link Stack} used for detecting circular use of the {@link Import} annotation.
*
* @author Chris Beams
* @see Import
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ModelClass.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ModelClass.java
index ca4bed9a098..f3d33c2d55f 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ModelClass.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ModelClass.java
@@ -24,7 +24,7 @@ import org.springframework.util.ClassUtils;
/**
- * Representation of a class, free from java reflection,
+ * Represents a class, free from java reflection,
* populated by {@link ConfigurationParser}.
*
* @author Chris Beams
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/MutableAnnotationArrayVisitor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/MutableAnnotationArrayVisitor.java
index 2c89c7f4ae9..a31681513fb 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/MutableAnnotationArrayVisitor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/MutableAnnotationArrayVisitor.java
@@ -25,6 +25,14 @@ import java.util.ArrayList;
import org.springframework.asm.AnnotationVisitor;
+/**
+ * ASM {@link AnnotationVisitor} that visits any annotation array values while populating
+ * a new {@link MutableAnnotation} instance.
+ *
+ * @author Chris Beams
+ * @see MutableAnnotation
+ * @see MutableAnnotationUtils
+ */
class MutableAnnotationArrayVisitor extends AnnotationAdapter {
private final ArrayList