diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaComponentScanDetector.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaComponentScanDetector.java
new file mode 100644
index 00000000000..214d694c8c6
--- /dev/null
+++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaComponentScanDetector.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2012-2013 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.bootstrap.autoconfigure.data;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+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.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.bootstrap.context.annotation.AutoConfigurationUtils;
+import org.springframework.cglib.proxy.Enhancer;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.core.annotation.AnnotationAttributes;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.core.type.StandardAnnotationMetadata;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * Helper to detect a component scan declared in the enclosing context (normally on a
+ * @Configuration
class). Once the component scan is detected, the base
+ * packages are stored for retrieval later by the {@link JpaRepositoriesAutoConfiguration}
+ * .
+ *
+ * @author Dave Syer
+ *
+ */
+class JpaComponentScanDetector implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ private BeanFactory beanFactory;
+
+ private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
+ final BeanDefinitionRegistry registry) {
+ storeComponentScanBasePackages();
+ }
+
+ private void storeComponentScanBasePackages() {
+ if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
+ storeComponentScanBasePackages((ConfigurableListableBeanFactory) this.beanFactory);
+ } else {
+ if (this.logger.isWarnEnabled()) {
+ this.logger
+ .warn("Unable to read @ComponentScan annotations for auto-configure");
+ }
+ }
+ }
+
+ private void storeComponentScanBasePackages(
+ ConfigurableListableBeanFactory beanFactory) {
+ List basePackages = new ArrayList();
+ for (String beanName : beanFactory.getBeanDefinitionNames()) {
+ BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+ String[] basePackagesAttribute = (String[]) beanDefinition
+ .getAttribute("componentScanBasePackages");
+ if (basePackagesAttribute != null) {
+ basePackages.addAll(Arrays.asList(basePackagesAttribute));
+ }
+ AnnotationMetadata metadata = getMetadata(beanDefinition);
+ basePackages.addAll(getBasePackages(metadata));
+ }
+ AutoConfigurationUtils.storeBasePackages(beanFactory, basePackages);
+ }
+
+ private AnnotationMetadata getMetadata(BeanDefinition beanDefinition) {
+ if (beanDefinition instanceof AbstractBeanDefinition
+ && ((AbstractBeanDefinition) beanDefinition).hasBeanClass()) {
+ Class> beanClass = ((AbstractBeanDefinition) beanDefinition).getBeanClass();
+ if (Enhancer.isEnhanced(beanClass)) {
+ beanClass = beanClass.getSuperclass();
+ }
+ return new StandardAnnotationMetadata(beanClass, true);
+ }
+ String className = beanDefinition.getBeanClassName();
+ if (className != null) {
+ try {
+ MetadataReader metadataReader = this.metadataReaderFactory
+ .getMetadataReader(className);
+ return metadataReader.getAnnotationMetadata();
+ } catch (IOException ex) {
+ if (this.logger.isDebugEnabled()) {
+ this.logger.debug(
+ "Could not find class file for introspecting @ComponentScan classes: "
+ + className, ex);
+ }
+ }
+ }
+ return null;
+ }
+
+ private List getBasePackages(AnnotationMetadata metadata) {
+ AnnotationAttributes attributes = AnnotationAttributes
+ .fromMap((metadata == null ? null : metadata.getAnnotationAttributes(
+ ComponentScan.class.getName(), true)));
+ if (attributes != null) {
+ List basePackages = new ArrayList();
+ addAllHavingText(basePackages, attributes.getStringArray("value"));
+ addAllHavingText(basePackages, attributes.getStringArray("basePackages"));
+ for (String packageClass : attributes.getStringArray("basePackageClasses")) {
+ basePackages.add(ClassUtils.getPackageName(packageClass));
+ }
+ if (basePackages.isEmpty()) {
+ basePackages.add(ClassUtils.getPackageName(metadata.getClassName()));
+ }
+ return basePackages;
+ }
+ return Collections.emptyList();
+ }
+
+ private void addAllHavingText(List list, String[] strings) {
+ for (String s : strings) {
+ if (StringUtils.hasText(s)) {
+ list.add(s);
+ }
+ }
+ }
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+ }
+}
diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfiguration.java
index 46aa1413590..0528b949cf9 100644
--- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfiguration.java
+++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfiguration.java
@@ -34,7 +34,7 @@ import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
@Configuration
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean(JpaRepositoryFactoryBean.class)
-@Import(JpaRepositoriesAutoConfigureRegistrar.class)
+@Import({ JpaComponentScanDetector.class, JpaRepositoriesAutoConfigureRegistrar.class })
public class JpaRepositoriesAutoConfiguration {
}
diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AbstractOnBeanCondition.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AbstractOnBeanCondition.java
index b2ef7ee1108..65f2a9e8b4a 100644
--- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AbstractOnBeanCondition.java
+++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AbstractOnBeanCondition.java
@@ -79,12 +79,20 @@ abstract class AbstractOnBeanCondition implements Condition {
if (this.logger.isDebugEnabled()) {
if (!beanClasses.isEmpty()) {
this.logger.debug("Looking for beans with class: " + beanClasses);
- this.logger.debug("Found beans with classes: " + beanClassesFound);
+ if (beanClassesFound.isEmpty()) {
+ this.logger.debug("Found no beans");
+ } else {
+ this.logger.debug("Found beans with classes: " + beanClassesFound);
+ }
}
if (!beanNames.isEmpty()) {
this.logger.debug("Looking for beans with names: " + beanNames);
- this.logger.debug("Found beans with names: " + beanNamesFound);
+ if (beanNamesFound.isEmpty()) {
+ this.logger.debug("Found no beans");
+ } else {
+ this.logger.debug("Found beans with names: " + beanNamesFound);
+ }
}
this.logger.debug("Match result is: " + result);
}
diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/EnableAutoConfigurationImportSelector.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/EnableAutoConfigurationImportSelector.java
index 49055f10e81..df1e3b4bb36 100644
--- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/EnableAutoConfigurationImportSelector.java
+++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/EnableAutoConfigurationImportSelector.java
@@ -16,35 +16,17 @@
package org.springframework.bootstrap.context.annotation;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.cglib.proxy.Enhancer;
-import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;
-import org.springframework.core.type.StandardAnnotationMetadata;
-import org.springframework.core.type.classreading.MetadataReader;
-import org.springframework.core.type.classreading.MetadataReaderFactory;
-import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.StringUtils;
/**
* {@link DeferredImportSelector} to handle {@link EnableAutoConfiguration
@@ -55,19 +37,12 @@ import org.springframework.util.StringUtils;
*/
@Order(Ordered.LOWEST_PRECEDENCE)
class EnableAutoConfigurationImportSelector implements DeferredImportSelector,
- BeanClassLoaderAware, BeanFactoryAware {
-
- private final Log logger = LogFactory.getLog(getClass());
+ BeanClassLoaderAware {
private ClassLoader beanClassLoader;
- private BeanFactory beanFactory;
-
- private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
-
@Override
public String[] selectImports(AnnotationMetadata metadata) {
- storeComponentScanBasePackages();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata
.getAnnotationAttributes(EnableAutoConfiguration.class.getName(), true));
List factories = new ArrayList(
@@ -77,94 +52,9 @@ class EnableAutoConfigurationImportSelector implements DeferredImportSelector,
return factories.toArray(new String[factories.size()]);
}
- private void storeComponentScanBasePackages() {
- if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
- storeComponentScanBasePackages((ConfigurableListableBeanFactory) this.beanFactory);
- } else {
- if (this.logger.isWarnEnabled()) {
- this.logger
- .warn("Unable to read @ComponentScan annotations for auto-configure");
- }
- }
- }
-
- private void storeComponentScanBasePackages(
- ConfigurableListableBeanFactory beanFactory) {
- List basePackages = new ArrayList();
- for (String beanName : beanFactory.getBeanDefinitionNames()) {
- BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
- String[] basePackagesAttribute = (String[]) beanDefinition
- .getAttribute("componentScanBasePackages");
- if (basePackagesAttribute != null) {
- basePackages.addAll(Arrays.asList(basePackagesAttribute));
- }
- AnnotationMetadata metadata = getMetadata(beanDefinition);
- basePackages.addAll(getBasePackages(metadata));
- }
- AutoConfigurationUtils.storeBasePackages(beanFactory, basePackages);
- }
-
- private AnnotationMetadata getMetadata(BeanDefinition beanDefinition) {
- if (beanDefinition instanceof AbstractBeanDefinition
- && ((AbstractBeanDefinition) beanDefinition).hasBeanClass()) {
- Class> beanClass = ((AbstractBeanDefinition) beanDefinition).getBeanClass();
- if (Enhancer.isEnhanced(beanClass)) {
- beanClass = beanClass.getSuperclass();
- }
- return new StandardAnnotationMetadata(beanClass, true);
- }
- String className = beanDefinition.getBeanClassName();
- if (className != null) {
- try {
- MetadataReader metadataReader = this.metadataReaderFactory
- .getMetadataReader(className);
- return metadataReader.getAnnotationMetadata();
- } catch (IOException ex) {
- if (this.logger.isDebugEnabled()) {
- this.logger.debug(
- "Could not find class file for introspecting @ComponentScan classes: "
- + className, ex);
- }
- }
- }
- return null;
- }
-
- private List getBasePackages(AnnotationMetadata metadata) {
- AnnotationAttributes attributes = AnnotationAttributes
- .fromMap((metadata == null ? null : metadata.getAnnotationAttributes(
- ComponentScan.class.getName(), true)));
- if (attributes != null) {
- List basePackages = new ArrayList();
- addAllHavingText(basePackages, attributes.getStringArray("value"));
- addAllHavingText(basePackages, attributes.getStringArray("basePackages"));
- for (String packageClass : attributes.getStringArray("basePackageClasses")) {
- basePackages.add(ClassUtils.getPackageName(packageClass));
- }
- if (basePackages.isEmpty()) {
- basePackages.add(ClassUtils.getPackageName(metadata.getClassName()));
- }
- return basePackages;
- }
- return Collections.emptyList();
- }
-
- private void addAllHavingText(List list, String[] strings) {
- for (String s : strings) {
- if (StringUtils.hasText(s)) {
- list.add(s);
- }
- }
- }
-
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
- @Override
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- this.beanFactory = beanFactory;
- }
-
}
diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnClassCondition.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnClassCondition.java
index 7b8e5fd4a40..85f62996ecc 100644
--- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnClassCondition.java
+++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnClassCondition.java
@@ -62,7 +62,7 @@ class OnClassCondition implements Condition {
}
}
if (logger.isDebugEnabled()) {
- logger.debug("All classes found (search terminated with matches=true)");
+ logger.debug("Match result is: true");
}
return true;
}
diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingBeanCondition.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingBeanCondition.java
index 8943e8aa1ed..17bacf9054a 100644
--- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingBeanCondition.java
+++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingBeanCondition.java
@@ -16,9 +16,9 @@
package org.springframework.bootstrap.context.annotation;
+import java.util.List;
+
import org.springframework.context.annotation.Condition;
-import org.springframework.context.annotation.ConditionContext;
-import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* {@link Condition} that checks that specific beans are missing.
@@ -34,7 +34,7 @@ class OnMissingBeanCondition extends AbstractOnBeanCondition {
}
@Override
- public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
- return !super.matches(context, metadata);
+ protected boolean evaluate(List beanClassesFound, List beanNamesFound) {
+ return !super.evaluate(beanClassesFound, beanNamesFound);
}
}
diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingClassCondition.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingClassCondition.java
index 3e01b13a228..43697887f44 100644
--- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingClassCondition.java
+++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingClassCondition.java
@@ -60,6 +60,9 @@ class OnMissingClassCondition implements Condition {
}
}
}
+ if (logger.isDebugEnabled()) {
+ logger.debug("Match result is: true");
+ }
return true;
}
diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigurationTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigurationTests.java
new file mode 100644
index 00000000000..2134662cf8b
--- /dev/null
+++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigurationTests.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012-2013 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.bootstrap.autoconfigure.data;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.junit.Test;
+import org.springframework.bootstrap.autoconfigure.data.test.CityRepository;
+import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration;
+import org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class JpaRepositoriesAutoConfigurationTests {
+
+ private AnnotationConfigApplicationContext context;
+
+ @Test
+ public void testDefaultRepositoryConfiguration() throws Exception {
+ this.context = new AnnotationConfigApplicationContext();
+ this.context.register(TestConfiguration.class,
+ EmbeddedDatabaseAutoConfiguration.class,
+ JpaRepositoriesAutoConfiguration.class,
+ HibernateJpaAutoConfiguration.class);
+ this.context.refresh();
+ assertNotNull(this.context.getBean(CityRepository.class));
+ assertNotNull(this.context.getBean(PlatformTransactionManager.class));
+ assertNotNull(this.context.getBean(EntityManagerFactory.class));
+ }
+
+ @Configuration
+ @ComponentScan("org.springframework.bootstrap.autoconfigure.data.test")
+ protected static class TestConfiguration {
+
+ }
+
+}
diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/test/City.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/test/City.java
new file mode 100644
index 00000000000..91d6911b599
--- /dev/null
+++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/test/City.java
@@ -0,0 +1,60 @@
+package org.springframework.bootstrap.autoconfigure.data.test;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class City implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Column(nullable = false)
+ private String name;
+
+ @Column(nullable = false)
+ private String state;
+
+ @Column(nullable = false)
+ private String country;
+
+ @Column(nullable = false)
+ private String map;
+
+ protected City() {
+ }
+
+ public City(String name, String country) {
+ super();
+ this.name = name;
+ this.country = country;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getState() {
+ return this.state;
+ }
+
+ public String getCountry() {
+ return this.country;
+ }
+
+ public String getMap() {
+ return this.map;
+ }
+
+ @Override
+ public String toString() {
+ return getName() + "," + getState() + "," + getCountry();
+ }
+}
diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/test/CityRepository.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/test/CityRepository.java
new file mode 100644
index 00000000000..7037700fcc1
--- /dev/null
+++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/test/CityRepository.java
@@ -0,0 +1,16 @@
+package org.springframework.bootstrap.autoconfigure.data.test;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.repository.Repository;
+
+public interface CityRepository extends Repository {
+
+ Page findAll(Pageable pageable);
+
+ Page findByNameLikeAndCountryLikeAllIgnoringCase(String name, String country,
+ Pageable pageable);
+
+ City findByNameAndCountryAllIgnoringCase(String name, String country);
+
+}