DATACMNS-47 - Guard against @EnableRepositories annotations not carrying @Inherited.
If an @EnableRepository annotation does not carry an @Inherited annotation and the annotation is used in a JavaConfig inheritance scenario the ImportBeanDefinitionRegistrar gets invoked without the annotation metadata available. The RepositoryBeanDefinitionRegistrarSupport now guards against that case and will not invoke registration of repository bean definitions. It's strongly recommended to equip @EnableRepository annotations with @Inherited to accommodate this scenario.
This commit is contained in:
@@ -42,6 +42,11 @@ public abstract class RepositoryBeanDefinitionRegistrarSupport implements Import
|
||||
Assert.notNull(annotationMetadata);
|
||||
Assert.notNull(registry);
|
||||
|
||||
// Guard against calls for sub-classes
|
||||
if (annotationMetadata.getAnnotationAttributes(getAnnotation().getName()) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
AnnotationRepositoryConfigurationSource configuration = new AnnotationRepositoryConfigurationSource(
|
||||
annotationMetadata, getAnnotation());
|
||||
|
||||
@@ -15,13 +15,18 @@
|
||||
*/
|
||||
package org.springframework.data.repository.config;
|
||||
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupportUnitTests.DummyRegistrar;
|
||||
import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Import(DummyRegistrar.class)
|
||||
@Inherited
|
||||
public @interface EnableRepositories {
|
||||
|
||||
String[] value() default {};
|
||||
@@ -34,7 +39,7 @@ public @interface EnableRepositories {
|
||||
|
||||
Filter[] excludeFilters() default {};
|
||||
|
||||
Class<?> repositoryFactoryBeanClass() default RepositoryFactoryBeanSupport.class;
|
||||
Class<?> repositoryFactoryBeanClass() default DummyRepositoryFactoryBean.class;
|
||||
|
||||
String namedQueriesLocation() default "";
|
||||
|
||||
|
||||
@@ -15,70 +15,35 @@
|
||||
*/
|
||||
package org.springframework.data.repository.config;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Integration test for {@link RepositoryBeanDefinitionRegistrarSupport}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RepositoryBeanDefinitionRegistrarSupportIntegrationTests {
|
||||
|
||||
@Mock
|
||||
BeanDefinitionRegistry registry;
|
||||
@Configuration
|
||||
@EnableRepositories
|
||||
static class SampleConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestConfig extends SampleConfig {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registersBeanDefinitionForFoundBean() {
|
||||
public void testBootstrappingWithInheritedConfigClasses() {
|
||||
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(SampleConfiguration.class, true);
|
||||
DummyRegistrar registrar = new DummyRegistrar();
|
||||
registrar.registerBeanDefinitions(metadata, registry);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
|
||||
|
||||
verify(registry, times(1)).registerBeanDefinition(eq("myRepository"), any(BeanDefinition.class));
|
||||
}
|
||||
|
||||
private static class DummyRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation()
|
||||
*/
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
return EnableRepositories.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension()
|
||||
*/
|
||||
@Override
|
||||
protected RepositoryConfigurationExtension getExtension() {
|
||||
return new RepositoryConfigurationExtensionSupport() {
|
||||
|
||||
public String getRepositoryFactoryClassName() {
|
||||
return RepositoryFactoryBeanSupport.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getModulePrefix() {
|
||||
return "commons";
|
||||
}
|
||||
};
|
||||
}
|
||||
assertThat(context.getBean(MyRepository.class), is(notNullValue()));
|
||||
assertThat(context.getBean(MyOtherRepository.class), is(notNullValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.repository.config;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
|
||||
|
||||
/**
|
||||
* Integration test for {@link RepositoryBeanDefinitionRegistrarSupport}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RepositoryBeanDefinitionRegistrarSupportUnitTests {
|
||||
|
||||
@Mock
|
||||
BeanDefinitionRegistry registry;
|
||||
|
||||
@Test
|
||||
public void registersBeanDefinitionForFoundBean() {
|
||||
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(SampleConfiguration.class, true);
|
||||
DummyRegistrar registrar = new DummyRegistrar();
|
||||
registrar.registerBeanDefinitions(metadata, registry);
|
||||
|
||||
verify(registry, times(1)).registerBeanDefinition(eq("myRepository"), any(BeanDefinition.class));
|
||||
}
|
||||
|
||||
static class DummyRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation()
|
||||
*/
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
return EnableRepositories.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension()
|
||||
*/
|
||||
@Override
|
||||
protected RepositoryConfigurationExtension getExtension() {
|
||||
return new RepositoryConfigurationExtensionSupport() {
|
||||
|
||||
public String getRepositoryFactoryClassName() {
|
||||
return RepositoryFactoryBeanSupport.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getModulePrefix() {
|
||||
return "commons";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.repository.core.support;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupportUnitTests.MyRepositoryQuery;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
|
||||
public class DummyRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
private final Object repository;
|
||||
|
||||
public DummyRepositoryFactory(Object repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, ID extends Serializable> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
|
||||
|
||||
return mock(EntityInformation.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
protected Object getTargetRepository(RepositoryMetadata metadata) {
|
||||
return repository;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
return repository.getClass();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key)
|
||||
*/
|
||||
@Override
|
||||
protected QueryLookupStrategy getQueryLookupStrategy(Key key) {
|
||||
|
||||
MyRepositoryQuery queryOne = mock(MyRepositoryQuery.class);
|
||||
RepositoryQuery queryTwo = mock(RepositoryQuery.class);
|
||||
|
||||
QueryLookupStrategy strategy = mock(QueryLookupStrategy.class);
|
||||
when(
|
||||
strategy.resolveQuery(Mockito.any(Method.class), Mockito.any(RepositoryMetadata.class),
|
||||
Mockito.any(NamedQueries.class))).thenReturn(queryOne, queryTwo);
|
||||
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.repository.core.support;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.repository.Repository;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DummyRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends
|
||||
RepositoryFactoryBeanSupport<T, S, ID> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#createRepositoryFactory()
|
||||
*/
|
||||
@Override
|
||||
protected RepositoryFactorySupport createRepositoryFactory() {
|
||||
|
||||
Repository<?, ?> repository = mock(Repository.class);
|
||||
return new DummyRepositoryFactory(repository);
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,9 @@ import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -35,11 +35,6 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.RepositoryDefinition;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
|
||||
/**
|
||||
@@ -50,7 +45,7 @@ import org.springframework.data.repository.query.RepositoryQuery;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RepositoryFactorySupportUnitTests {
|
||||
|
||||
RepositoryFactorySupport factory = new DummyRepositoryFactory();
|
||||
RepositoryFactorySupport factory;
|
||||
|
||||
@Mock
|
||||
PagingAndSortingRepository<Object, Serializable> backingRepo;
|
||||
@@ -62,6 +57,11 @@ public class RepositoryFactorySupportUnitTests {
|
||||
@Mock
|
||||
PlainQueryCreationListener otherListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
factory = new DummyRepositoryFactory(backingRepo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokesCustomQueryCreationListenerForSpecialRepositoryQueryOnly() throws Exception {
|
||||
|
||||
@@ -113,45 +113,6 @@ public class RepositoryFactorySupportUnitTests {
|
||||
assertThat(factory.getRepository(foo), is(notNullValue()));
|
||||
}
|
||||
|
||||
class DummyRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, ID extends Serializable> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
|
||||
|
||||
return mock(EntityInformation.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getTargetRepository(RepositoryMetadata metadata) {
|
||||
|
||||
return backingRepo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
|
||||
return backingRepo.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected QueryLookupStrategy getQueryLookupStrategy(Key key) {
|
||||
|
||||
MyRepositoryQuery queryOne = mock(MyRepositoryQuery.class);
|
||||
RepositoryQuery queryTwo = mock(RepositoryQuery.class);
|
||||
|
||||
QueryLookupStrategy strategy = mock(QueryLookupStrategy.class);
|
||||
when(
|
||||
strategy.resolveQuery(Mockito.any(Method.class), Mockito.any(RepositoryMetadata.class),
|
||||
Mockito.any(NamedQueries.class))).thenReturn(queryOne, queryTwo);
|
||||
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
|
||||
interface ObjectRepository extends Repository<Object, Serializable>, ObjectRepositoryCustom {
|
||||
|
||||
Object findByClass(Class<?> clazz);
|
||||
|
||||
Reference in New Issue
Block a user