diff --git a/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java b/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java index b27116905..9e70c1322 100644 --- a/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 the original author or authors. + * 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.repository.config; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -32,22 +33,22 @@ public class DefaultRepositoryConfiguration findCandidateComponents(String basePackage) { + + Set candidates = super.findCandidateComponents(basePackage); + + for (BeanDefinition candidate : candidates) { + + if (candidate instanceof AnnotatedBeanDefinition) { + + // TODO: Remove after upgrade to Spring 3.2.5 - SPR-11032, DATACMNS-386 + // Use AnnotationConfigUtils directly + Method method = ReflectionUtils.findMethod(AnnotationConfigUtils.class, "processCommonDefinitionAnnotations", + AnnotatedBeanDefinition.class); + ReflectionUtils.makeAccessible(method); + ReflectionUtils.invokeMethod(method, null, candidate); + } + } + + return candidates; + } + /** * @return the considerNestedRepositoryInterfaces */ diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java index e778ca517..f9af621de 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 the original author or authors. + * 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. @@ -99,4 +99,11 @@ public interface RepositoryConfiguration> result = new HashSet>(); - for (String candidate : configSource.getCandidates(loader)) { + for (BeanDefinition candidate : configSource.getCandidates(loader)) { result.add(getRepositoryConfiguration(candidate, configSource)); } return result; @@ -138,12 +139,12 @@ public abstract class RepositoryConfigurationExtensionSupport implements Reposit * interface name. Defaults to the {@link DefaultRepositoryConfiguration} but allows sub-classes to override this to * customize the behaviour. * - * @param interfaceName will never be {@literal null} or empty. + * @param definition will never be {@literal null} or empty. * @param configSource will never be {@literal null}. * @return */ protected RepositoryConfiguration getRepositoryConfiguration( - String interfaceName, T configSource) { - return new DefaultRepositoryConfiguration(configSource, interfaceName); + BeanDefinition definition, T configSource) { + return new DefaultRepositoryConfiguration(configSource, definition); } } diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSource.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSource.java index 2e0bbfc49..e8e5a4e4b 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSource.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSource.java @@ -18,6 +18,7 @@ package org.springframework.data.repository.config; import java.util.Collection; import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.core.io.ResourceLoader; import org.springframework.data.repository.query.QueryLookupStrategy; @@ -71,10 +72,10 @@ public interface RepositoryConfigurationSource { String getRepositoryFactoryBeanName(); /** - * Returns the fully-qualified names of the repository interfaces to create repository instances for. + * Returns the source {@link BeanDefinition}s of the repository interfaces to create repository instances for. * * @param loader * @return */ - Collection getCandidates(ResourceLoader loader); + Collection getCandidates(ResourceLoader loader); } diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSourceSupport.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSourceSupport.java index b398763e7..73d92e225 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSourceSupport.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSourceSupport.java @@ -52,7 +52,7 @@ public abstract class RepositoryConfigurationSourceSupport implements Repository * (non-Javadoc) * @see org.springframework.data.repository.config.RepositoryConfiguration#getCandidates(org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider) */ - public Collection getCandidates(ResourceLoader loader) { + public Collection getCandidates(ResourceLoader loader) { RepositoryComponentProvider scanner = new RepositoryComponentProvider(getIncludeFilters()); scanner.setConsiderNestedRepositoryInterfaces(shouldConsiderNestedRepositories()); @@ -63,13 +63,11 @@ public abstract class RepositoryConfigurationSourceSupport implements Repository scanner.addExcludeFilter(filter); } - Set result = new HashSet(); + Set result = new HashSet(); for (String basePackage : getBasePackages()) { - Collection components = scanner.findCandidateComponents(basePackage); - for (BeanDefinition definition : components) { - result.add(definition.getBeanClassName()); - } + Set candidate = scanner.findCandidateComponents(basePackage); + result.addAll(candidate); } return result; diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java index 2e5214eba..25db19452 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2012 the original author or authors. + * Copyright 2008-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. @@ -52,6 +52,9 @@ public abstract class RepositoryFactoryBeanSupport, private NamedQueries namedQueries; private MappingContext mappingContext; private ClassLoader classLoader; + private boolean lazyInit = false; + + private T repository; /** * Setter to inject the repository interface to implement. @@ -102,6 +105,15 @@ public abstract class RepositoryFactoryBeanSupport, this.mappingContext = mappingContext; } + /** + * Configures whether to initialize the repository proxy lazily. This defaults to {@literal false}. + * + * @param lazyInit whether to initialize the repository proxy lazily. This defaults to {@literal false}. + */ + public void setLazyInit(boolean lazy) { + this.lazyInit = lazy; + } + /* * (non-Javadoc) * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader) @@ -159,7 +171,7 @@ public abstract class RepositoryFactoryBeanSupport, * @see org.springframework.beans.factory.FactoryBean#getObject() */ public T getObject() { - return factory.getRepository(repositoryInterface, customImplementation); + return initAndReturn(); } /* @@ -189,6 +201,26 @@ public abstract class RepositoryFactoryBeanSupport, this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey); this.factory.setNamedQueries(namedQueries); this.factory.setBeanClassLoader(classLoader); + + if (!lazyInit) { + initAndReturn(); + } + } + + /** + * Returns the previously initialized repository proxy or creates and returns the proxy if previously uninitialized. + * + * @return + */ + private T initAndReturn() { + + Assert.notNull(repositoryInterface, "Repository interface must not be null on initialization!"); + + if (this.repository == null) { + this.repository = this.factory.getRepository(repositoryInterface, customImplementation); + } + + return this.repository; } /** diff --git a/src/test/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSourceUnitTests.java b/src/test/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSourceUnitTests.java index 6bae75367..07d06671f 100644 --- a/src/test/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSourceUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSourceUnitTests.java @@ -22,6 +22,7 @@ import java.util.Collection; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.core.env.Environment; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.DefaultResourceLoader; @@ -57,9 +58,11 @@ public class AnnotationRepositoryConfigurationSourceUnitTests { @Test public void evaluatesExcludeFiltersCorrectly() { - Collection candidates = source.getCandidates(new DefaultResourceLoader()); + Collection candidates = source.getCandidates(new DefaultResourceLoader()); assertThat(candidates, hasSize(1)); - assertThat(candidates, hasItem(MyRepository.class.getName())); + + BeanDefinition candidate = candidates.iterator().next(); + assertThat(candidate.getBeanClassName(), is(MyRepository.class.getName())); } @Test diff --git a/src/test/java/org/springframework/data/repository/config/DefaultRepositoryConfigurationUnitTests.java b/src/test/java/org/springframework/data/repository/config/DefaultRepositoryConfigurationUnitTests.java index eb24f3bb7..db51f17ad 100644 --- a/src/test/java/org/springframework/data/repository/config/DefaultRepositoryConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/DefaultRepositoryConfigurationUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 the original author or authors. + * 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. @@ -22,6 +22,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.data.repository.query.QueryLookupStrategy.Key; /** @@ -32,19 +33,19 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key; @RunWith(MockitoJUnitRunner.class) public class DefaultRepositoryConfigurationUnitTests { - @Mock - RepositoryConfigurationSource source; + @Mock RepositoryConfigurationSource source; @Test public void supportsBasicConfiguration() { RepositoryConfiguration configuration = new DefaultRepositoryConfiguration( - source, "com.acme.MyRepository"); + source, new RootBeanDefinition("com.acme.MyRepository")); assertThat(configuration.getConfigurationSource(), is(source)); assertThat(configuration.getImplementationBeanName(), is("myRepositoryImpl")); assertThat(configuration.getImplementationClassName(), is("MyRepositoryImpl")); assertThat(configuration.getRepositoryInterface(), is("com.acme.MyRepository")); assertThat(configuration.getQueryLookupStrategyKey(), is((Object) Key.CREATE_IF_NOT_FOUND)); + assertThat(configuration.isLazyInit(), is(false)); } } diff --git a/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java index fa39038b6..be0316fb4 100644 --- a/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java @@ -19,7 +19,9 @@ import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.test.util.ReflectionTestUtils; /** @@ -29,6 +31,8 @@ import org.springframework.test.util.ReflectionTestUtils; */ public class RepositoryFactoryBeanSupportUnitTests { + public @Rule ExpectedException exception = ExpectedException.none(); + /** * @see DATACMNS-341 */ @@ -40,9 +44,21 @@ public class RepositoryFactoryBeanSupportUnitTests { RepositoryFactoryBeanSupport factoryBean = new DummyRepositoryFactoryBean(); factoryBean.setBeanClassLoader(classLoader); + factoryBean.setLazyInit(true); factoryBean.afterPropertiesSet(); Object factory = ReflectionTestUtils.getField(factoryBean, "factory"); assertThat(ReflectionTestUtils.getField(factory, "classLoader"), is((Object) classLoader)); } + + @Test + @SuppressWarnings("rawtypes") + public void initializationFailsWithMissingRepositoryInterface() { + + exception.expect(IllegalArgumentException.class); + exception.expectMessage("Repository interface"); + + RepositoryFactoryBeanSupport factoryBean = new DummyRepositoryFactoryBean(); + factoryBean.afterPropertiesSet(); + } }