diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java b/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java index 3b283340b..1d2c72d07 100644 --- a/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java +++ b/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2015 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. @@ -18,6 +18,9 @@ package org.springframework.data.repository.core; import java.io.Serializable; import java.lang.reflect.Method; import java.util.Collection; +import java.util.Set; + +import org.springframework.data.repository.support.Repositories; /** * Metadata for repository interfaces. @@ -69,4 +72,15 @@ public interface RepositoryMetadata { * @return */ boolean isPagingRepository(); + + /** + * Returns the set of types the repository shall be discoverable for when trying to look up a repository by domain + * type. + * + * @see Repositories#getRepositoryFor(Class) + * @return the set of types the repository shall be discoverable for when trying to look up a repository by domain + * type, must not be {@literal null}. + * @since 1.11 + */ + Set> getAlternativeDomainTypes(); } diff --git a/src/main/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadata.java b/src/main/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadata.java index 46d32815d..190dc129d 100644 --- a/src/main/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadata.java +++ b/src/main/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadata.java @@ -17,6 +17,8 @@ package org.springframework.data.repository.core.support; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Collections; +import java.util.Set; import org.springframework.data.domain.Pageable; import org.springframework.data.repository.Repository; @@ -115,6 +117,15 @@ public abstract class AbstractRepositoryMetadata implements RepositoryMetadata { return Arrays.asList(findAllMethod.getParameterTypes()).contains(Pageable.class); } + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.RepositoryMetadata#getAlternativeDomainTypes() + */ + @Override + public Set> getAlternativeDomainTypes() { + return Collections.emptySet(); + } + /** * Recursively unwraps well known wrapper types from the given {@link TypeInformation}. * diff --git a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java index c06fa6561..26f35da51 100644 --- a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java +++ b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2015 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. @@ -315,6 +315,15 @@ class DefaultRepositoryInformation implements RepositoryInformation { return metadata.isPagingRepository(); } + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.RepositoryMetadata#getAlternativeDomainTypes() + */ + @Override + public Set> getAlternativeDomainTypes() { + return metadata.getAlternativeDomainTypes(); + } + /** * Checks the given method's parameters to match the ones of the given base class method. Matches generic arguments * agains the ones bound in the given repository interface. diff --git a/src/main/java/org/springframework/data/repository/support/Repositories.java b/src/main/java/org/springframework/data/repository/support/Repositories.java index 199a52ace..3ed318879 100644 --- a/src/main/java/org/springframework/data/repository/support/Repositories.java +++ b/src/main/java/org/springframework/data/repository/support/Repositories.java @@ -18,9 +18,11 @@ package org.springframework.data.repository.support; import java.io.Serializable; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryUtils; @@ -79,19 +81,33 @@ public class Repositories implements Iterable> { populateRepositoryFactoryInformation(factory); } - @SuppressWarnings({ "rawtypes", "unchecked" }) private void populateRepositoryFactoryInformation(ListableBeanFactory factory) { for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(factory, RepositoryFactoryInformation.class, false, false)) { + cacheRepositoryFactory(name); + } + } - RepositoryFactoryInformation repositoryFactoryInformation = beanFactory.getBean(name, - RepositoryFactoryInformation.class); - Class userDomainType = ClassUtils.getUserClass(repositoryFactoryInformation.getRepositoryInformation() - .getDomainType()); + @SuppressWarnings({ "rawtypes", "unchecked" }) + private synchronized void cacheRepositoryFactory(String name) { - this.repositoryFactoryInfos.put(userDomainType, repositoryFactoryInformation); - this.repositoryBeanNames.put(userDomainType, BeanFactoryUtils.transformedBeanName(name)); + RepositoryFactoryInformation repositoryFactoryInformation = beanFactory.getBean(name, + RepositoryFactoryInformation.class); + Class domainType = ClassUtils.getUserClass(repositoryFactoryInformation.getRepositoryInformation() + .getDomainType()); + + RepositoryInformation information = repositoryFactoryInformation.getRepositoryInformation(); + Set> alternativeDomainTypes = information.getAlternativeDomainTypes(); + String beanName = BeanFactoryUtils.transformedBeanName(name); + + Set> typesToRegister = new HashSet>(alternativeDomainTypes.size() + 1); + typesToRegister.add(domainType); + typesToRegister.addAll(alternativeDomainTypes); + + for (Class type : typesToRegister) { + this.repositoryFactoryInfos.put(type, repositoryFactoryInformation); + this.repositoryBeanNames.put(type, beanName); } } diff --git a/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java b/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java index a2d497a1a..bea708e63 100644 --- a/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java +++ b/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java @@ -29,7 +29,11 @@ public final class DummyRepositoryInformation implements RepositoryInformation { private final RepositoryMetadata metadata; public DummyRepositoryInformation(Class repositoryInterface) { - this.metadata = new DefaultRepositoryMetadata(repositoryInterface); + this(new DefaultRepositoryMetadata(repositoryInterface)); + } + + public DummyRepositoryInformation(RepositoryMetadata metadata) { + this.metadata = metadata; } public Class getIdType() { @@ -84,4 +88,9 @@ public final class DummyRepositoryInformation implements RepositoryInformation { public boolean isPagingRepository() { return false; } + + @Override + public Set> getAlternativeDomainTypes() { + return metadata.getAlternativeDomainTypes(); + } } diff --git a/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java b/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java index 1e8af754d..643fd630c 100644 --- a/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java +++ b/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java @@ -23,6 +23,7 @@ import static org.junit.Assert.*; import java.io.Serializable; import java.util.Collections; import java.util.List; +import java.util.Set; import org.junit.Before; import org.junit.Test; @@ -45,6 +46,7 @@ import org.springframework.data.repository.core.support.DummyRepositoryFactoryBe import org.springframework.data.repository.core.support.DummyRepositoryInformation; import org.springframework.data.repository.core.support.RepositoryFactoryInformation; import org.springframework.data.repository.query.QueryMethod; +import org.springframework.util.ClassUtils; /** * Unit tests for {@link Repositories}. @@ -116,6 +118,27 @@ public class RepositoriesUnitTests { assertThat(new Repositories(context).getPersistentEntity(AdvancedAddress.class), is(notNullValue())); } + /** + * @see DATACMNS-673 + */ + @Test + public void discoversRepositoryForAlternativeDomainType() { + + RepositoryMetadata metadata = new CustomRepositoryMetadata(SampleRepository.class); + RepositoryFactoryInformation information = new SampleRepoFactoryInformation(metadata); + + GenericApplicationContext context = new GenericApplicationContext(); + context.getBeanFactory().registerSingleton("foo", information); + context.refresh(); + + Repositories repositories = new Repositories(context); + + assertThat(repositories.getRepositoryFor(Sample.class), is(notNullValue())); + assertThat(repositories.getRepositoryFor(SampleEntity.class), is(notNullValue())); + + context.close(); + } + class Person {} class Address {} @@ -132,7 +155,11 @@ public class RepositoriesUnitTests { private final SampleMappingContext mappingContext; public SampleRepoFactoryInformation(Class repositoryInterface) { - this.repositoryMetadata = new DefaultRepositoryMetadata(repositoryInterface); + this(new DefaultRepositoryMetadata(repositoryInterface)); + } + + public SampleRepoFactoryInformation(RepositoryMetadata metadata) { + this.repositoryMetadata = metadata; this.mappingContext = new SampleMappingContext(); } @@ -142,7 +169,7 @@ public class RepositoriesUnitTests { } public RepositoryInformation getRepositoryInformation() { - return new DummyRepositoryInformation(repositoryMetadata.getRepositoryInterface()); + return new DummyRepositoryInformation(repositoryMetadata); } public PersistentEntity getPersistentEntity() { @@ -153,4 +180,49 @@ public class RepositoriesUnitTests { return Collections.emptyList(); } } + + static class CustomRepositoryMetadata extends DefaultRepositoryMetadata { + + private final Class domainType; + + /** + * @param repositoryInterface + */ + public CustomRepositoryMetadata(Class repositoryInterface) { + + super(repositoryInterface); + + String domainType = super.getDomainType().getName().concat("Entity"); + + try { + this.domainType = ClassUtils.forName(domainType, CustomRepositoryMetadata.class.getClassLoader()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.DefaultRepositoryMetadata#getDomainType() + */ + @Override + public Class getDomainType() { + return this.domainType; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.AbstractRepositoryMetadata#getAlternativeDomainTypes() + */ + @Override + public Set> getAlternativeDomainTypes() { + return Collections.> singleton(super.getDomainType()); + } + } + + interface Sample {} + + static class SampleEntity implements Sample {} + + interface SampleRepository extends Repository {} }