diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java index 193711808c..feac237c8c 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java @@ -46,6 +46,16 @@ public abstract class AutoConfigurationPackages { private static final String BEAN = AutoConfigurationPackages.class.getName(); + /** + * Determine if the auto-configuration base packages for the given bean factory are + * available + * @param beanFactory the source bean factory + * @return true if there are auto-config packages available + */ + public static boolean has(BeanFactory beanFactory) { + return beanFactory.containsBean(BEAN) && !get(beanFactory).isEmpty(); + } + /** * Return the auto-configuration base packages for the given bean factory * @param beanFactory the source bean factory diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java index b97c6dcb84..e6acf57fcd 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java @@ -110,8 +110,11 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { protected abstract EntityManagerFactoryBuilder.EntityManagerFactoryBeanCallback getVendorCallback(); protected String[] getPackagesToScan() { - List basePackages = AutoConfigurationPackages.get(this.beanFactory); - return basePackages.toArray(new String[basePackages.size()]); + if (AutoConfigurationPackages.has(this.beanFactory)) { + List basePackages = AutoConfigurationPackages.get(this.beanFactory); + return basePackages.toArray(new String[basePackages.size()]); + } + return new String[0]; } protected void configure( diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/jpa/JpaUserDetailsTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/jpa/JpaUserDetailsTests.java new file mode 100644 index 0000000000..012d395db5 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/jpa/JpaUserDetailsTests.java @@ -0,0 +1,31 @@ +package org.springframework.boot.autoconfigure.security.jpa; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * The EntityScanRegistrar can cause problems with Spring security and its eager + * instantiation needs. This test is designed to fail if the Entities can't be scanned + * because the registrar doesn't get a callback with the right beans (essentially because + * their instantiation order was accelerated by Security). + * + * @author Dave Syer + * + * @since 1.1 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = Main.class) +public class JpaUserDetailsTests { + + @Test + public void contextLoads() throws Exception { + } + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} \ No newline at end of file diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/jpa/Main.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/jpa/Main.java new file mode 100644 index 0000000000..e20801f6e2 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/jpa/Main.java @@ -0,0 +1,31 @@ +/* + * 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.boot.autoconfigure.security.jpa; + +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.user.SecurityConfig; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; + +@Import({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, SecurityAutoConfiguration.class }) +@ComponentScan(basePackageClasses = SecurityConfig.class) +public class Main { +} \ No newline at end of file diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/SecurityConfig.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/SecurityConfig.java new file mode 100644 index 0000000000..1e76db91fa --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/SecurityConfig.java @@ -0,0 +1,26 @@ + +package org.springframework.boot.autoconfigure.security.user; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.orm.jpa.EntityScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; + +@Configuration +@EnableGlobalMethodSecurity(securedEnabled = true) +@EntityScan(basePackageClasses = User.class) +@EnableJpaRepositories(basePackageClasses = User.class) +public class SecurityConfig extends GlobalAuthenticationConfigurerAdapter { + + @Autowired + private UserRepository userRepository; + + @Override + public void init(AuthenticationManagerBuilder auth) throws Exception { + System.err.println("Global security config"); + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/User.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/User.java new file mode 100644 index 0000000000..60d371c980 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/User.java @@ -0,0 +1,40 @@ +package org.springframework.boot.autoconfigure.security.user; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class User { + @Id + @GeneratedValue + private Long id; + private String email; + + public User() { + } + + public User(String email) { + this.email = email; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + @Override + public String toString() { + return getClass().getSimpleName() + ":" + id; + } +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/UserRepository.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/UserRepository.java new file mode 100644 index 0000000000..acefef24de --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/UserRepository.java @@ -0,0 +1,7 @@ +package org.springframework.boot.autoconfigure.security.user; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { + public User findByEmail(String email); +} \ No newline at end of file diff --git a/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScanRegistrar.java b/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScanRegistrar.java index d66054797a..6fcf2877db 100644 --- a/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScanRegistrar.java +++ b/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScanRegistrar.java @@ -54,6 +54,9 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar { beanDefinition.getConstructorArgumentValues().addGenericArgumentValue( getPackagesToScan(importingClassMetadata)); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + // We don't need this one to be post processed otherwise it can cause a + // cascade of bean instantiation that we would rather avoid. + beanDefinition.setSynthetic(true); registry.registerBeanDefinition(BEAN_NAME, beanDefinition); } }