diff --git a/Spring Data Commons.sonargraph b/Spring Data Commons.sonargraph index 881e12d26..54f37a727 100644 --- a/Spring Data Commons.sonargraph +++ b/Spring Data Commons.sonargraph @@ -80,6 +80,7 @@ + diff --git a/src/main/java/org/springframework/data/repository/core/CrudInvoker.java b/src/main/java/org/springframework/data/repository/core/CrudInvoker.java new file mode 100644 index 000000000..cffaf14a8 --- /dev/null +++ b/src/main/java/org/springframework/data/repository/core/CrudInvoker.java @@ -0,0 +1,46 @@ +/* + * Copyright 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.data.repository.core; + +import java.io.Serializable; + +import org.springframework.data.repository.CrudRepository; + +/** + * Interface for components that can invoke simple CRUD operations on repositories. Useful to be able to abstract being + * backed by a {@link CrudRepository} implementation or a raw repository declaration with signature compatible methods + * for {@link CrudRepository#findOne(Serializable)} and {@link CrudRepository#save(Object)}. + * + * @author Oliver Gierke + * @since 1.6 + */ +public interface CrudInvoker { + + /** + * Invokes the method equivalent to {@link CrudRepository#save(Object)}. + * + * @param object must not be {@literal null}. + */ + T invokeSave(T object); + + /** + * Invokes the method equivalent to {@link CrudRepository#findOne(Serializable)}. + * + * @param id must not be {@literal null}. + * @return + */ + T invokeFindOne(Serializable id); +} diff --git a/src/main/java/org/springframework/data/repository/core/CrudMethods.java b/src/main/java/org/springframework/data/repository/core/CrudMethods.java new file mode 100644 index 000000000..8a87dbad0 --- /dev/null +++ b/src/main/java/org/springframework/data/repository/core/CrudMethods.java @@ -0,0 +1,95 @@ +/* + * Copyright 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.data.repository.core; + +import java.lang.reflect.Method; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +/** + * Meta-information about the CRUD methods of a repository. + * + * @author Oliver Gierke + * @since 1.6 + */ +public interface CrudMethods { + + /** + * Returns the method to be used for saving entities. Usually siganture compatible to + * {@link CrudRepository#save(Object)}. + * + * @return the method to save entities or {@literal null} if noen exposed. + * @see #hasSaveMethod() + */ + Method getSaveMethod(); + + /** + * Returns whether the repository exposes a save method at all. + * + * @return + */ + boolean hasSaveMethod(); + + /** + * Returns the find all method of the repository. Implementations should prefer more detailled methods like + * {@link PagingAndSortingRepository}'s taking a {@link Pageable} or {@link Sort} instance. + * + * @return the find all method of the repository or {@literal null} if not available. + * @see #hasFindAllMethod() + */ + Method getFindAllMethod(); + + /** + * Returns whether the repository exposes a find all method at all. + * + * @return + */ + boolean hasFindAllMethod(); + + /** + * Returns the find one method of the repository. Usually signature compatible to + * {@link CrudRepository#findOne(java.io.Serializable)} + * + * @return the find one method of the repository or {@literal null} if not available. + * @see #hasFindOneMethod() + */ + Method getFindOneMethod(); + + /** + * Returns whether the repository exposes a find one method. + * + * @return + */ + boolean hasFindOneMethod(); + + /** + * Returns the delete method of the repository. Will prefer a delete-by-id method over a delete-by-entity method. + * + * @return the delete method of the repository or {@literal null} if not available. + * @see #hasDelete() + */ + Method getDeleteMethod(); + + /** + * Returns whether the repository esposes a delete method. + * + * @return + */ + boolean hasDelete(); +} diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryInformation.java b/src/main/java/org/springframework/data/repository/core/RepositoryInformation.java index 0817102e1..8594fd756 100644 --- a/src/main/java/org/springframework/data/repository/core/RepositoryInformation.java +++ b/src/main/java/org/springframework/data/repository/core/RepositoryInformation.java @@ -55,6 +55,15 @@ public interface RepositoryInformation extends RepositoryMetadata { */ boolean isQueryMethod(Method method); + /** + * Returns whether the given method is logically a base class method. This also includes methods (re)declared in the + * repository interface that match the signatures of the base implementation. + * + * @param method must not be {@literal null}. + * @return + */ + boolean isBaseClassMethod(Method method); + /** * Returns all methods considered to be query methods. * @@ -62,6 +71,13 @@ public interface RepositoryInformation extends RepositoryMetadata { */ Iterable getQueryMethods(); + /** + * Returns {@link CrudMethods} meta information for the repository. + * + * @return + */ + CrudMethods getCrudMethods(); + /** * Returns the target class method that is backing the given method. This can be necessary if a repository interface * redeclares a method of the core repository interface (e.g. for transaction behaviour customization). Returns the diff --git a/src/main/java/org/springframework/data/repository/core/support/DefaultCrudMethods.java b/src/main/java/org/springframework/data/repository/core/support/DefaultCrudMethods.java new file mode 100644 index 000000000..22305a281 --- /dev/null +++ b/src/main/java/org/springframework/data/repository/core/support/DefaultCrudMethods.java @@ -0,0 +1,201 @@ +/* + * Copyright 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.data.repository.core.support; + +import java.lang.reflect.Method; + +import org.springframework.core.GenericTypeResolver; +import org.springframework.core.MethodParameter; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudMethods; +import org.springframework.data.repository.core.RepositoryInformation; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +/** + * Default implementation to discover CRUD methods based on a given {@link RepositoryInformation}. Will detect methods + * exposed in {@link CrudRepository} but also hand crafted CRUD methods that are signature compatible with the ones on + * {@link CrudRepository}. + * + * @author Oliver Gierke + * @since 1.6 + */ +class DefaultCrudMethods implements CrudMethods { + + private final RepositoryInformation information; + + private Method findAllMethod; + private boolean findAllHasPaging; + + private Method findOneMethod; + private Method saveMethod; + private Method deleteMethod; + + /** + * Creates a new {@link DefaultCrudMethods} using the given {@link RepositoryInformation}. + * + * @param information must not be {@literal null}. + */ + public DefaultCrudMethods(RepositoryInformation information) { + + Assert.notNull(information, "RepositoryInformation must not be null!"); + this.information = information; + + for (Method method : ReflectionUtils.getAllDeclaredMethods(information.getRepositoryInterface())) { + + if (!information.isBaseClassMethod(method)) { + continue; + } + + if (method.getName().equals("findAll")) { + findAllDetected(method); + continue; + } + + if (method.getName().equals("findOne")) { + this.findOneMethod = method; + } + + if (method.getName().equals("save")) { + this.saveMethod = method; + } + + if (method.getName().equals("delete")) { + deleteDetected(method); + } + } + } + + /** + * Checks whether the given method is a more usable find all method. Will prefer methods taking a {@link Pageable} and + * sort over a simple one. + * + * @param method + */ + private void findAllDetected(Method method) { + + if (findAllMethod != null && findAllHasPaging) { + return; + } + + Class[] parameterType = method.getParameterTypes(); + + if (parameterType.length > 0) { + + if (parameterType[0].equals(Pageable.class)) { + this.findAllMethod = method; + this.findAllHasPaging = true; + return; + } + + if (parameterType[0].equals(Sort.class)) { + this.findAllMethod = method; + } + + return; + } + + if (findAllMethod == null) { + this.findAllMethod = method; + } + } + + /** + * Checks whether the given method is a more usable delete method. Will prefer delete-by-id methods over + * delete-by-instance ones. + * + * @param method + */ + private void deleteDetected(Method method) { + + MethodParameter parameter = new MethodParameter(method, 0); + Class parameterType = GenericTypeResolver.resolveParameterType(parameter, information.getRepositoryInterface()); + + if (information.getIdType().isAssignableFrom(parameterType)) { + this.deleteMethod = method; + } + + if (this.deleteMethod == null) { + this.deleteMethod = method; + } + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.support.CrudMethods#getSaveMethod() + */ + @Override + public Method getSaveMethod() { + return saveMethod; + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.support.CrudMethods#hasSaveMethod() + */ + @Override + public boolean hasSaveMethod() { + return saveMethod != null; + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.support.CrudMethods#getFindAllMethod() + */ + @Override + public Method getFindAllMethod() { + return findAllMethod; + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.support.CrudMethods#hasFindAllMethod() + */ + @Override + public boolean hasFindAllMethod() { + return findAllMethod != null; + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.support.CrudMethods#getFindOneMethod() + */ + @Override + public Method getFindOneMethod() { + return findOneMethod; + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.support.CrudMethods#hasFindOneMethod() + */ + @Override + public boolean hasFindOneMethod() { + return findOneMethod != null; + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.support.CrudMethods#hasDelete() + */ + @Override + public boolean hasDelete() { + return this.deleteMethod != null; + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.support.CrudMethods#getDeleteMethod() + */ + @Override + public Method getDeleteMethod() { + return this.deleteMethod; + } +} 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 02dfb6aa2..d0e75ed4b 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-2012 the original author or authors. + * Copyright 2011-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. @@ -30,6 +30,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.core.MethodParameter; import org.springframework.data.repository.Repository; +import org.springframework.data.repository.core.CrudMethods; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.util.Assert; @@ -42,8 +43,8 @@ import org.springframework.util.ClassUtils; */ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements RepositoryInformation { - @SuppressWarnings("rawtypes") - private static final TypeVariable>[] PARAMETERS = Repository.class.getTypeParameters(); + @SuppressWarnings("rawtypes") private static final TypeVariable>[] PARAMETERS = Repository.class + .getTypeParameters(); private static final String DOMAIN_TYPE_NAME = PARAMETERS[0].getName(); private static final String ID_TYPE_NAME = PARAMETERS[1].getName(); @@ -52,12 +53,13 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements private final RepositoryMetadata metadata; private final Class repositoryBaseClass; private final Class customImplementationClass; + private final CrudMethods crudMethods; /** * Creates a new {@link DefaultRepositoryMetadata} for the given repository interface and repository base class. * - * @param metadata - * @param repositoryBaseClass + * @param metadata must not be {@literal null}. + * @param repositoryBaseClass must not be {@literal null}. * @param customImplementationClass */ public DefaultRepositoryInformation(RepositoryMetadata metadata, Class repositoryBaseClass, @@ -71,12 +73,14 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements this.metadata = metadata; this.repositoryBaseClass = repositoryBaseClass; this.customImplementationClass = customImplementationClass; + this.crudMethods = new DefaultCrudMethods(this); } /* * (non-Javadoc) * @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface() */ + @Override public Class getRepositoryInterface() { return metadata.getRepositoryInterface(); } @@ -85,6 +89,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements * (non-Javadoc) * @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass() */ + @Override public Class getDomainType() { return metadata.getDomainType(); } @@ -93,6 +98,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements * (non-Javadoc) * @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass() */ + @Override public Class getIdType() { return metadata.getIdType(); } @@ -101,6 +107,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements * (non-Javadoc) * @see org.springframework.data.repository.support.RepositoryInformation#getRepositoryBaseClass() */ + @Override public Class getRepositoryBaseClass() { return this.repositoryBaseClass; } @@ -109,6 +116,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements * (non-Javadoc) * @see org.springframework.data.repository.support.RepositoryInformation#getTargetClassMethod(java.lang.reflect.Method) */ + @Override public Method getTargetClassMethod(Method method) { if (methodCache.containsKey(method)) { @@ -152,6 +160,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements * (non-Javadoc) * @see org.springframework.data.repository.support.RepositoryInformation#getQueryMethods() */ + @Override public Set getQueryMethods() { Set result = new HashSet(); @@ -170,6 +179,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements * (non-Javadoc) * @see org.springframework.data.repository.support.RepositoryInformation#isCustomMethod(java.lang.reflect.Method) */ + @Override public boolean isCustomMethod(Method method) { return isTargetClassMethod(method, customImplementationClass); } @@ -178,17 +188,19 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements * (non-Javadoc) * @see org.springframework.data.repository.core.RepositoryInformation#isQueryMethod(java.lang.reflect.Method) */ + @Override public boolean isQueryMethod(Method method) { return getQueryMethods().contains(method); } - /** - * Returns whether the given method is a method covered by the base implementation. - * - * @param method - * @return + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.RepositoryInformation#isBaseClassMethod(java.lang.reflect.Method) */ + @Override public boolean isBaseClassMethod(Method method) { + + Assert.notNull(method, "Method must not be null!"); return isTargetClassMethod(method, repositoryBaseClass); } @@ -234,6 +246,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements * (non-Javadoc) * @see org.springframework.data.repository.support.RepositoryInformation#hasCustomMethod() */ + @Override public boolean hasCustomMethod() { Class repositoryInterface = getRepositoryInterface(); @@ -252,6 +265,15 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements return false; } + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.RepositoryInformation#getCrudMethods() + */ + @Override + public CrudMethods getCrudMethods() { + return crudMethods; + } + /** * 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/init/ResourceReaderRepositoryPopulator.java b/src/main/java/org/springframework/data/repository/init/ResourceReaderRepositoryPopulator.java index 1489447eb..f95a85d3f 100644 --- a/src/main/java/org/springframework/data/repository/init/ResourceReaderRepositoryPopulator.java +++ b/src/main/java/org/springframework/data/repository/init/ResourceReaderRepositoryPopulator.java @@ -16,7 +16,6 @@ package org.springframework.data.repository.init; import java.io.IOException; -import java.io.Serializable; import java.util.Arrays; import java.util.Collection; @@ -27,7 +26,7 @@ import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudInvoker; import org.springframework.data.repository.support.Repositories; import org.springframework.util.Assert; @@ -152,10 +151,12 @@ public class ResourceReaderRepositoryPopulator implements RepositoryPopulator, A * @param object must not be {@literal null}. * @param repositories must not be {@literal null}. */ + @SuppressWarnings({ "unchecked" }) private void persist(Object object, Repositories repositories) { - CrudRepository repository = repositories.getRepositoryFor(object.getClass()); - LOGGER.debug(String.format("Persisting %s using repository %s", object, repository)); - repository.save(object); + CrudInvoker invoker = (CrudInvoker) repositories.getCrudInvoker(object.getClass()); + LOGGER.debug(String.format("Persisting %s using repository %s", object, invoker)); + + invoker.invokeSave(object); } } diff --git a/src/main/java/org/springframework/data/repository/support/CrudRepositoryInvoker.java b/src/main/java/org/springframework/data/repository/support/CrudRepositoryInvoker.java new file mode 100644 index 000000000..8ee93f4c5 --- /dev/null +++ b/src/main/java/org/springframework/data/repository/support/CrudRepositoryInvoker.java @@ -0,0 +1,61 @@ +/* + * Copyright 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.data.repository.support; + +import java.io.Serializable; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudInvoker; +import org.springframework.util.Assert; + +/** + * {@link CrudRepository} based {@link CrudInvoker} calling methods on {@link CrudRepository} directly. + * + * @author Oliver Gierke + * @since 1.6 + */ +class CrudRepositoryInvoker implements CrudInvoker { + + private final CrudRepository repository; + + /** + * Creates a new {@link CrudRepositoryInvoker} using the given {@link CrudRepository}. + * + * @param repository must not be {@literal null}. + */ + public CrudRepositoryInvoker(CrudRepository repository) { + + Assert.notNull(repository, "Repository must not be null!"); + this.repository = repository; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.CrudInvoker#findOne(java.io.Serializable) + */ + @Override + public T invokeFindOne(Serializable id) { + return repository.findOne(id); + } + + /* (non-Javadoc) + * @see org.springframework.data.repository.core.CrudInvoker#save(java.lang.Object) + */ + @Override + public T invokeSave(T object) { + return repository.save(object); + } +} diff --git a/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java b/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java index 2029abc2b..b2ce5242c 100644 --- a/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java +++ b/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java @@ -15,7 +15,6 @@ */ package org.springframework.data.repository.support; -import java.io.Serializable; import java.util.Collections; import java.util.Set; @@ -26,6 +25,7 @@ import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.ConditionalGenericConverter; import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudInvoker; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.util.StringUtils; @@ -65,11 +65,12 @@ public class DomainClassConverter domainType = targetType.getType(); - CrudRepository repository = repositories.getRepositoryFor(targetType.getType()); - Serializable id = conversionService.convert(source, info.getIdType()); - return repository.findOne(id); + RepositoryInformation info = repositories.getRepositoryInformationFor(domainType); + CrudInvoker invoker = repositories.getCrudInvoker(domainType); + + return invoker.invokeFindOne(conversionService.convert(source, info.getIdType())); } /* diff --git a/src/main/java/org/springframework/data/repository/support/DomainClassPropertyEditor.java b/src/main/java/org/springframework/data/repository/support/DomainClassPropertyEditor.java index 0d090dffb..794d14795 100644 --- a/src/main/java/org/springframework/data/repository/support/DomainClassPropertyEditor.java +++ b/src/main/java/org/springframework/data/repository/support/DomainClassPropertyEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 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. @@ -22,6 +22,7 @@ import java.io.Serializable; import org.springframework.beans.PropertyEditorRegistry; import org.springframework.beans.SimpleTypeConverter; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudInvoker; import org.springframework.data.repository.core.EntityInformation; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -33,26 +34,26 @@ import org.springframework.util.StringUtils; */ public class DomainClassPropertyEditor extends PropertyEditorSupport { - private final CrudRepository repository; + private final CrudInvoker invoker; private final EntityInformation information; private final PropertyEditorRegistry registry; /** - * Creates a new {@link DomainClassPropertyEditor} for the given {@link CrudRepository}, {@link EntityInformation} and + * Creates a new {@link DomainClassPropertyEditor} for the given repository, {@link EntityInformation} and * {@link PropertyEditorRegistry}. * - * @param repository must not be {@literal null}. + * @param invoker must not be {@literal null}. * @param information must not be {@literal null}. * @param registry must not be {@literal null}. */ - public DomainClassPropertyEditor(CrudRepository repository, EntityInformation information, + public DomainClassPropertyEditor(CrudInvoker invoker, EntityInformation information, PropertyEditorRegistry registry) { - Assert.notNull(repository); + Assert.notNull(invoker); Assert.notNull(information); Assert.notNull(registry); - this.repository = repository; + this.invoker = invoker; this.information = information; this.registry = registry; } @@ -69,7 +70,7 @@ public class DomainClassPropertyEditor extends Prope return; } - setValue(repository.findOne(getId(idAsString))); + setValue(invoker.invokeFindOne(getId(idAsString))); } /* @@ -142,7 +143,7 @@ public class DomainClassPropertyEditor extends Prope DomainClassPropertyEditor that = (DomainClassPropertyEditor) obj; - return this.repository.equals(that.repository) && this.registry.equals(that.registry) + return this.invoker.equals(that.invoker) && this.registry.equals(that.registry) && this.information.equals(that.information); } @@ -154,7 +155,7 @@ public class DomainClassPropertyEditor extends Prope public int hashCode() { int hashCode = 17; - hashCode += repository.hashCode() * 32; + hashCode += invoker.hashCode() * 32; hashCode += information.hashCode() * 32; hashCode += registry.hashCode() * 32; return hashCode; diff --git a/src/main/java/org/springframework/data/repository/support/DomainClassPropertyEditorRegistrar.java b/src/main/java/org/springframework/data/repository/support/DomainClassPropertyEditorRegistrar.java index 3c5f238d2..1b85b3f88 100644 --- a/src/main/java/org/springframework/data/repository/support/DomainClassPropertyEditorRegistrar.java +++ b/src/main/java/org/springframework/data/repository/support/DomainClassPropertyEditorRegistrar.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. @@ -16,12 +16,14 @@ package org.springframework.data.repository.support; import java.io.Serializable; + import org.springframework.beans.PropertyEditorRegistrar; import org.springframework.beans.PropertyEditorRegistry; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudInvoker; import org.springframework.data.repository.core.RepositoryInformation; +import org.springframework.web.servlet.DispatcherServlet; /** * Simple helper class to use Hades DAOs to provide {@link java.beans.PropertyEditor}s for domain classes. To get this @@ -56,10 +58,10 @@ public class DomainClassPropertyEditorRegistrar implements PropertyEditorRegistr for (Class domainClass : repositories) { RepositoryInformation repositoryInformation = repositories.getRepositoryInformationFor(domainClass); - CrudRepository repository = repositories.getRepositoryFor(domainClass); + CrudInvoker invoker = repositories.getCrudInvoker(domainClass); DomainClassPropertyEditor editor = new DomainClassPropertyEditor( - repository, repositories.getEntityInformationFor(repositoryInformation.getDomainType()), registry); + invoker, repositories.getEntityInformationFor(repositoryInformation.getDomainType()), registry); registry.registerCustomEditor(repositoryInformation.getDomainType(), editor); } diff --git a/src/main/java/org/springframework/data/repository/support/ReflectionRepositoryInvoker.java b/src/main/java/org/springframework/data/repository/support/ReflectionRepositoryInvoker.java new file mode 100644 index 000000000..f51a535ee --- /dev/null +++ b/src/main/java/org/springframework/data/repository/support/ReflectionRepositoryInvoker.java @@ -0,0 +1,77 @@ +/* + * Copyright 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.data.repository.support; + +import static java.lang.String.*; + +import java.io.Serializable; + +import org.springframework.data.repository.core.CrudInvoker; +import org.springframework.data.repository.core.CrudMethods; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +/** + * {@link CrudInvoker} that uses reflection to invoke repository methods based on the {@link CrudMethods} meta + * information. + * + * @author Oliver Gierke + * @since 1.6 + */ +class ReflectionRepositoryInvoker implements CrudInvoker { + + private final Object repository; + private final CrudMethods methods; + + /** + * Creates a new {@link ReflectionRepositoryInvoker} using the given repository and {@link CrudMethods}. + * + * @param repository must not be {@literal null}. + * @param methods must not be {@literal null}. + */ + public ReflectionRepositoryInvoker(Object repository, CrudMethods methods) { + + Assert.notNull(repository, "Repository must not be null!"); + Assert.notNull(methods, "CrudMethods must not be null!"); + + Class type = repository.getClass(); + Assert.isTrue(methods.hasFindOneMethod(), format("Repository %s does not expose a findOne(…) method!", type)); + Assert.isTrue(methods.hasSaveMethod(), format("Repository %s does not expose a save(…) method!", type)); + + this.repository = repository; + this.methods = methods; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.CrudInvoker#save(java.lang.Object) + */ + @Override + @SuppressWarnings("unchecked") + public T invokeSave(T object) { + return (T) ReflectionUtils.invokeMethod(methods.getSaveMethod(), repository, object); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.CrudInvoker#findOne(java.io.Serializable) + */ + @Override + @SuppressWarnings("unchecked") + public T invokeFindOne(Serializable id) { + return (T) ReflectionUtils.invokeMethod(methods.getFindOneMethod(), id); + } +} 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 768d43ce3..e752b6f04 100644 --- a/src/main/java/org/springframework/data/repository/support/Repositories.java +++ b/src/main/java/org/springframework/data/repository/support/Repositories.java @@ -31,6 +31,7 @@ import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudInvoker; import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.support.RepositoryFactoryInformation; @@ -92,8 +93,7 @@ public class Repositories implements Iterable> { * @param domainClass must not be {@literal null}. * @return */ - @SuppressWarnings("unchecked") - public CrudRepository getRepositoryFor(Class domainClass) { + public Object getRepositoryFor(Class domainClass) { RepositoryFactoryInformation information = getRepoInfoFor(domainClass); @@ -101,7 +101,7 @@ public class Repositories implements Iterable> { return null; } - return (CrudRepository) beanFactory.getBean(repositories.get(information)); + return beanFactory.getBean(repositories.get(information)); } /** @@ -118,11 +118,11 @@ public class Repositories implements Iterable> { } /** - * Returns the {@link EntityInformation} for the given domain class. + * Returns the {@link RepositoryInformation} for the given domain class. * * @param domainClass must not be {@literal null}. - * @return the {@link EntityInformation} for the given domain class or {@literal null} if no repository registered for - * this domain class. + * @return the {@link RepositoryInformation} for the given domain class or {@literal null} if no repository registered + * for this domain class. */ public RepositoryInformation getRepositoryInformationFor(Class domainClass) { @@ -156,6 +156,19 @@ public class Repositories implements Iterable> { return information == null ? Collections. emptyList() : information.getQueryMethods(); } + @SuppressWarnings("unchecked") + public CrudInvoker getCrudInvoker(Class domainClass) { + + RepositoryInformation information = getRepositoryInformationFor(domainClass); + Object repository = getRepositoryFor(domainClass); + + if (repository instanceof CrudRepository) { + return new CrudRepositoryInvoker((CrudRepository) repository); + } else { + return new ReflectionRepositoryInvoker(repository, information.getCrudMethods()); + } + } + private RepositoryFactoryInformation getRepoInfoFor(Class domainClass) { Assert.notNull(domainClass); @@ -200,11 +213,6 @@ public class Repositories implements Iterable> { RepositoryFactoryInformation.class); RepositoryInformation info = information.getRepositoryInformation(); - Class repositoryInterface = info.getRepositoryInterface(); - - if (!CrudRepository.class.isAssignableFrom(repositoryInterface)) { - continue; - } repositories.put(information, BeanFactoryUtils.transformedBeanName(repositoryFactoryName)); domainClassToBeanName.put(info.getDomainType(), information); diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryBeanNameGeneratorUnitTest.java b/src/test/java/org/springframework/data/repository/config/RepositoryBeanNameGeneratorUnitTests.java similarity index 95% rename from src/test/java/org/springframework/data/repository/config/RepositoryBeanNameGeneratorUnitTest.java rename to src/test/java/org/springframework/data/repository/config/RepositoryBeanNameGeneratorUnitTests.java index 52fa792a0..10ae062e2 100644 --- a/src/test/java/org/springframework/data/repository/config/RepositoryBeanNameGeneratorUnitTest.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryBeanNameGeneratorUnitTests.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. @@ -34,7 +34,7 @@ import org.springframework.data.repository.core.support.RepositoryFactoryBeanSup * * @author Oliver Gierke */ -public class RepositoryBeanNameGeneratorUnitTest { +public class RepositoryBeanNameGeneratorUnitTests { BeanNameGenerator generator; BeanDefinitionRegistry registry; diff --git a/src/test/java/org/springframework/data/repository/core/support/DefaultCrudMethodsUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/DefaultCrudMethodsUnitTests.java new file mode 100644 index 000000000..ffb661494 --- /dev/null +++ b/src/test/java/org/springframework/data/repository/core/support/DefaultCrudMethodsUnitTests.java @@ -0,0 +1,133 @@ +/* + * Copyright 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.data.repository.core.support; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.io.Serializable; +import java.lang.reflect.Method; + +import org.junit.Test; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.data.repository.Repository; +import org.springframework.data.repository.core.CrudMethods; +import org.springframework.data.repository.core.RepositoryInformation; +import org.springframework.data.repository.core.RepositoryMetadata; + +/** + * Unit tests dor {@link DefaultCrudMethods}. + * + * @author Oliver Gierke + */ +public class DefaultCrudMethodsUnitTests { + + @Test + public void detectsMethodsOnCrudRepository() throws Exception { + + Class type = DomainCrudRepository.class; + + assertFindAllMethodOn(type, type.getMethod("findAll")); + assertDeleteMethodOn(type, type.getMethod("delete", Serializable.class)); + assertSaveMethodOn(type, true); + } + + @Test + public void detectsMethodsOnPagingAndSortingRepository() throws Exception { + + Class type = DomainPagingAndSortingRepository.class; + + assertFindAllMethodOn(type, type.getMethod("findAll", Pageable.class)); + assertDeleteMethodOn(type, type.getMethod("delete", Serializable.class)); + assertSaveMethodOn(type, true); + } + + @Test + public void detectsMethodsOnCustomRepository() throws Exception { + + Class type = RepositoryWithCustomSortingAndPagingFindAll.class; + assertFindAllMethodOn(type, type.getMethod("findAll", Pageable.class)); + + Class type1 = RepositoryWithIterableDeleteOnly.class; + assertDeleteMethodOn(type1, type1.getMethod("delete", Iterable.class)); + } + + @Test + public void doesNotDetectInvalidlyDeclaredMethods() throws Exception { + + Class type = RepositoryWithInvalidPagingFindAll.class; + assertFindAllMethodOn(type, null); + } + + private static CrudMethods getMethodsFor(Class repositoryInterface) { + + RepositoryMetadata metadata = new DefaultRepositoryMetadata(repositoryInterface); + RepositoryInformation information = new DefaultRepositoryInformation(metadata, PagingAndSortingRepository.class, + null); + + return new DefaultCrudMethods(information); + } + + private static void assertFindAllMethodOn(Class type, Method method) { + + CrudMethods methods = getMethodsFor(type); + + assertThat(methods.hasFindAllMethod(), is(method != null)); + assertThat(methods.getFindAllMethod(), is(method)); + } + + private static void assertDeleteMethodOn(Class type, Method method) { + + CrudMethods methods = getMethodsFor(type); + + assertThat(methods.hasDelete(), is(method != null)); + assertThat(methods.getDeleteMethod(), is(method)); + } + + private static void assertSaveMethodOn(Class type, boolean present) { + + CrudMethods methods = getMethodsFor(type); + + assertThat(methods.hasSaveMethod(), is(present)); + assertThat(methods.getSaveMethod(), is(present ? notNullValue() : nullValue())); + } + + interface Domain {} + + interface DomainCrudRepository extends CrudRepository {} + + interface DomainPagingAndSortingRepository extends PagingAndSortingRepository {} + + interface RepositoryWithCustomSortingAndPagingFindAll extends Repository { + + Iterable findAll(Sort sort); + + Iterable findAll(Pageable pageable); + } + + interface RepositoryWithInvalidPagingFindAll extends Repository { + + Iterable findAll(Object pageable); + } + + interface RepositoryWithIterableDeleteOnly extends Repository { + + void delete(Iterable entities); + } +} diff --git a/src/test/java/org/springframework/data/repository/support/DummyRepositoryInformation.java b/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java similarity index 85% rename from src/test/java/org/springframework/data/repository/support/DummyRepositoryInformation.java rename to src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.java index 08b6fb2fc..d16930f50 100644 --- a/src/test/java/org/springframework/data/repository/support/DummyRepositoryInformation.java +++ b/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryInformation.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. @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.repository.support; +package org.springframework.data.repository.core.support; import java.io.Serializable; import java.lang.reflect.Method; import java.util.Collections; import java.util.Set; +import org.springframework.data.repository.core.CrudMethods; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryMetadata; -import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; public final class DummyRepositoryInformation implements RepositoryInformation { @@ -71,4 +71,12 @@ public final class DummyRepositoryInformation implements RepositoryInformation { public Method getTargetClassMethod(Method method) { return method; } + + public boolean isBaseClassMethod(Method method) { + return true; + } + + public CrudMethods getCrudMethods() { + return new DefaultCrudMethods(this); + } } diff --git a/src/test/java/org/springframework/data/repository/init/ResourceReaderRepositoryInitializerUnitTests.java b/src/test/java/org/springframework/data/repository/init/ResourceReaderRepositoryInitializerUnitTests.java index bce48d569..d845d9a35 100644 --- a/src/test/java/org/springframework/data/repository/init/ResourceReaderRepositoryInitializerUnitTests.java +++ b/src/test/java/org/springframework/data/repository/init/ResourceReaderRepositoryInitializerUnitTests.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. @@ -18,7 +18,6 @@ package org.springframework.data.repository.init; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; -import java.io.Serializable; import java.util.Collection; import java.util.Collections; @@ -29,7 +28,7 @@ import org.mockito.runners.MockitoJUnitRunner; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.io.Resource; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudInvoker; import org.springframework.data.repository.support.Repositories; /** @@ -40,17 +39,12 @@ import org.springframework.data.repository.support.Repositories; @RunWith(MockitoJUnitRunner.class) public class ResourceReaderRepositoryInitializerUnitTests { - @Mock - ResourceReader reader; - @Mock - Repositories repositories; - @Mock - Resource resource; - @Mock - CrudRepository repo; + @Mock ResourceReader reader; + @Mock Repositories repositories; + @Mock Resource resource; + @Mock CrudInvoker invoker; - @Mock - ApplicationEventPublisher publisher; + @Mock ApplicationEventPublisher publisher; @Test public void storesSingleObjectCorrectly() throws Exception { @@ -59,7 +53,7 @@ public class ResourceReaderRepositoryInitializerUnitTests { setUpReferenceAndInititalize(reference); - verify(repo, times(1)).save(reference); + verify(invoker, times(1)).invokeSave(reference); } @Test @@ -70,7 +64,7 @@ public class ResourceReaderRepositoryInitializerUnitTests { setUpReferenceAndInititalize(reference); - verify(repo, times(1)).save(object); + verify(invoker, times(1)).invokeSave(object); } /** @@ -89,7 +83,7 @@ public class ResourceReaderRepositoryInitializerUnitTests { throws Exception { when(reader.readFrom(any(Resource.class), any(ClassLoader.class))).thenReturn(reference); - when(repositories.getRepositoryFor(Object.class)).thenReturn(repo); + when(repositories.getCrudInvoker(Object.class)).thenReturn(invoker); ResourceReaderRepositoryPopulator populator = new ResourceReaderRepositoryPopulator(reader); populator.setResources(resource); diff --git a/src/test/java/org/springframework/data/repository/support/DomainClassConverterUnitTests.java b/src/test/java/org/springframework/data/repository/support/DomainClassConverterUnitTests.java index 159213663..7c02af696 100644 --- a/src/test/java/org/springframework/data/repository/support/DomainClassConverterUnitTests.java +++ b/src/test/java/org/springframework/data/repository/support/DomainClassConverterUnitTests.java @@ -39,6 +39,7 @@ import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.support.DummyEntityInformation; import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean; +import org.springframework.data.repository.core.support.DummyRepositoryInformation; /** * Unit test for {@link DomainClassConverter}. diff --git a/src/test/java/org/springframework/data/repository/support/DomainClassPropertyEditorUnitTests.java b/src/test/java/org/springframework/data/repository/support/DomainClassPropertyEditorUnitTests.java index 2982c2c7c..e457c1bf6 100644 --- a/src/test/java/org/springframework/data/repository/support/DomainClassPropertyEditorUnitTests.java +++ b/src/test/java/org/springframework/data/repository/support/DomainClassPropertyEditorUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 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. @@ -29,6 +29,7 @@ import org.mockito.runners.MockitoJUnitRunner; import org.springframework.beans.PropertyEditorRegistry; import org.springframework.data.domain.Persistable; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.core.CrudInvoker; import org.springframework.data.repository.core.EntityInformation; /** @@ -41,12 +42,9 @@ public class DomainClassPropertyEditorUnitTests { DomainClassPropertyEditor editor; - @Mock - PropertyEditorRegistry registry; - @Mock - UserRepository userRepository; - @Mock - EntityInformation information; + @Mock PropertyEditorRegistry registry; + @Mock CrudInvoker userRepository; + @Mock EntityInformation information; @Before public void setUp() { @@ -60,11 +58,11 @@ public class DomainClassPropertyEditorUnitTests { User user = new User(1); when(information.getId(user)).thenReturn(user.getId()); - when(userRepository.findOne(1)).thenReturn(user); + when(userRepository.invokeFindOne(1)).thenReturn(user); editor.setAsText("1"); - verify(userRepository, times(1)).findOne(1); + verify(userRepository, times(1)).invokeFindOne(1); } @Test diff --git a/src/test/java/org/springframework/data/repository/support/ReflectionRepositoryInvokerUnitTests.java b/src/test/java/org/springframework/data/repository/support/ReflectionRepositoryInvokerUnitTests.java new file mode 100644 index 000000000..6459e6595 --- /dev/null +++ b/src/test/java/org/springframework/data/repository/support/ReflectionRepositoryInvokerUnitTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 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.data.repository.support; + +import static org.mockito.Mockito.*; + +import java.io.Serializable; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.repository.Repository; +import org.springframework.data.repository.core.CrudMethods; + +/** + * Unit tests for {@link ReflectionRepositoryInvoker}. + * + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class ReflectionRepositoryInvokerUnitTests { + + @Mock Repository repo; + @Mock CrudMethods methods; + + @Test + public void createsInvokerForRepositoryExposingBothFindAllAndSaveMethod() { + + when(methods.hasFindOneMethod()).thenReturn(true); + when(methods.hasSaveMethod()).thenReturn(true); + + new ReflectionRepositoryInvoker(repo, methods); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsNullRepository() { + + when(methods.hasFindOneMethod()).thenReturn(true); + when(methods.hasSaveMethod()).thenReturn(true); + + new ReflectionRepositoryInvoker(null, methods); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsRepositoryIfItDoesntExposeAFindOneMethod() { + + when(methods.hasFindOneMethod()).thenReturn(false); + when(methods.hasSaveMethod()).thenReturn(true); + + new ReflectionRepositoryInvoker(repo, methods); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsRepositoryIfItDoesntExposeASaveMethod() { + + when(methods.hasFindOneMethod()).thenReturn(true); + when(methods.hasSaveMethod()).thenReturn(false); + + new ReflectionRepositoryInvoker(repo, methods); + } +} diff --git a/src/test/java/org/springframework/data/repository/support/RepositoriesIntegrationTests.java b/src/test/java/org/springframework/data/repository/support/RepositoriesIntegrationTests.java index 8a4f2a986..08115648d 100644 --- a/src/test/java/org/springframework/data/repository/support/RepositoriesIntegrationTests.java +++ b/src/test/java/org/springframework/data/repository/support/RepositoriesIntegrationTests.java @@ -43,8 +43,7 @@ public class RepositoriesIntegrationTests { @Configuration static class Config { - @Autowired - ApplicationContext context; + @Autowired ApplicationContext context; @Bean public Repositories repositories() { @@ -52,22 +51,40 @@ public class RepositoriesIntegrationTests { } @Bean - public RepositoryFactoryBeanSupport, User, Long> repositoryFactory() { + public RepositoryFactoryBeanSupport, User, Long> userRepositoryFactory() { DummyRepositoryFactoryBean, User, Long> factory = new DummyRepositoryFactoryBean, User, Long>(); factory.setRepositoryInterface(UserRepository.class); return factory; } + + @Bean + public RepositoryFactoryBeanSupport, Product, Long> productRepositoryFactory() { + + DummyRepositoryFactoryBean, Product, Long> factory = new DummyRepositoryFactoryBean, Product, Long>(); + factory.setRepositoryInterface(ProductRepository.class); + + return factory; + } } - @Autowired - Repositories repositories; + @Autowired Repositories repositories; @Test - public void foo() { + public void detectsRepositories() { + assertThat(repositories, is(notNullValue())); assertThat(repositories.hasRepositoryFor(User.class), is(true)); + assertThat(repositories.hasRepositoryFor(Product.class), is(true)); + } + + @Test + public void createsCrudInvokersCorrectly() { + + assertThat(repositories, is(notNullValue())); + assertThat(repositories.getCrudInvoker(User.class), is(instanceOf(CrudRepositoryInvoker.class))); + assertThat(repositories.getCrudInvoker(Product.class), is(instanceOf(ReflectionRepositoryInvoker.class))); } static class User { @@ -77,4 +94,13 @@ public class RepositoriesIntegrationTests { interface UserRepository extends CrudRepository { } + + static class Product {} + + interface ProductRepository extends Repository { + + Product findOne(Long id); + + Product save(Product product); + } } 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 fa6a6cd90..fcb06bf77 100644 --- a/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java +++ b/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java @@ -43,6 +43,7 @@ import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.DummyEntityInformation; import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean; +import org.springframework.data.repository.core.support.DummyRepositoryInformation; import org.springframework.data.repository.core.support.RepositoryFactoryInformation; import org.springframework.data.repository.query.QueryMethod; @@ -75,12 +76,12 @@ public class RepositoriesUnitTests { } @Test - public void considersCrudRepositoriesOnly() { + public void doesNotConsiderCrudRepositoriesOnly() { Repositories repositories = new Repositories(context); assertThat(repositories.hasRepositoryFor(Person.class), is(true)); - assertThat(repositories.hasRepositoryFor(Address.class), is(false)); + assertThat(repositories.hasRepositoryFor(Address.class), is(true)); } @Test @@ -103,7 +104,7 @@ public class RepositoriesUnitTests { Repositories repositories = new Repositories(context); assertThat(repositories.getPersistentEntity(Person.class), is(notNullValue())); - assertThat(repositories.getPersistentEntity(Address.class), is(nullValue())); + assertThat(repositories.getPersistentEntity(Address.class), is(notNullValue())); } class Person { diff --git a/src/test/java/org/springframework/data/web/LegacyPageableHandlerArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/LegacyPageableHandlerArgumentResolverUnitTests.java index a379e6b09..f1111333c 100644 --- a/src/test/java/org/springframework/data/web/LegacyPageableHandlerArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/LegacyPageableHandlerArgumentResolverUnitTests.java @@ -41,7 +41,7 @@ import org.springframework.web.context.request.ServletWebRequest; * @author Oliver Gierke */ @SuppressWarnings("deprecation") -public class LegacyPageableHandlerArgumentResolverUnitTests extends PageableDefaultUnitTest { +public class LegacyPageableHandlerArgumentResolverUnitTests extends PageableDefaultUnitTests { Method correctMethod, noQualifiers, invalidQualifiers, defaultsMethod, defaultsMethodWithSort, defaultsMethodWithSortAndDirection, otherMethod; diff --git a/src/test/java/org/springframework/data/web/PageableDefaultUnitTest.java b/src/test/java/org/springframework/data/web/PageableDefaultUnitTests.java similarity index 98% rename from src/test/java/org/springframework/data/web/PageableDefaultUnitTest.java rename to src/test/java/org/springframework/data/web/PageableDefaultUnitTests.java index a9d0c88f0..31e83b325 100644 --- a/src/test/java/org/springframework/data/web/PageableDefaultUnitTest.java +++ b/src/test/java/org/springframework/data/web/PageableDefaultUnitTests.java @@ -17,7 +17,7 @@ package org.springframework.data.web; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; -import static org.springframework.data.web.SortDefaultUnitTest.*; +import static org.springframework.data.web.SortDefaultUnitTests.*; import org.junit.Rule; import org.junit.Test; @@ -40,7 +40,7 @@ import org.springframework.web.util.UriComponentsBuilder; * @since 1.6 * @author Oliver Gierke */ -public abstract class PageableDefaultUnitTest { +public abstract class PageableDefaultUnitTests { static final int PAGE_SIZE = 47; static final int PAGE_NUMBER = 23; diff --git a/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTest.java b/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTests.java similarity index 97% rename from src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTest.java rename to src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTests.java index ca15e4398..ad58dbbc7 100644 --- a/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTest.java +++ b/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTests.java @@ -35,11 +35,11 @@ import org.springframework.web.util.UriComponentsBuilder; /** * Unit tests for {@link PageableHandlerMethodArgumentResolver}. Pulls in defaulting tests from - * {@link PageableDefaultUnitTest}. + * {@link PageableDefaultUnitTests}. * * @author Oliver Gierke */ -public class PageableHandlerMethodArgumentResolverUnitTest extends PageableDefaultUnitTest { +public class PageableHandlerMethodArgumentResolverUnitTests extends PageableDefaultUnitTests { @Test public void buildsUpRequestParameters() { diff --git a/src/test/java/org/springframework/data/web/SortDefaultUnitTest.java b/src/test/java/org/springframework/data/web/SortDefaultUnitTests.java similarity index 99% rename from src/test/java/org/springframework/data/web/SortDefaultUnitTest.java rename to src/test/java/org/springframework/data/web/SortDefaultUnitTests.java index ff0a7c5fc..aa373234b 100644 --- a/src/test/java/org/springframework/data/web/SortDefaultUnitTest.java +++ b/src/test/java/org/springframework/data/web/SortDefaultUnitTests.java @@ -35,7 +35,7 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; * @since 1.6 * @author Oliver Gierke */ -public abstract class SortDefaultUnitTest { +public abstract class SortDefaultUnitTests { static final String SORT_0 = "username"; static final String SORT_1 = "username,asc"; diff --git a/src/test/java/org/springframework/data/web/SortHandlerArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/SortHandlerArgumentResolverUnitTests.java index 7c778ea0d..72dc4d67b 100644 --- a/src/test/java/org/springframework/data/web/SortHandlerArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/SortHandlerArgumentResolverUnitTests.java @@ -38,7 +38,7 @@ import org.springframework.web.util.UriComponentsBuilder; * @since 1.6 * @author Oliver Gierke */ -public class SortHandlerArgumentResolverUnitTests extends SortDefaultUnitTest { +public class SortHandlerArgumentResolverUnitTests extends SortDefaultUnitTests { static final String SORT_0 = "username"; static final String SORT_1 = "username,asc";