From 9b4b111d23f0fdb38de72ef404f0c63229a53363 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 13 Nov 2013 15:08:24 +0000 Subject: [PATCH] DATAREST-93 - Cleanups in repository invoker area. Made RepositoryInvokerFactory an interface and renamed the previously existing implementation class to DefaultRepositoryInvokerFactory. Removed instantiation of the class from ResourceMetadataHandlerMethodArgumentResolver to keep the logic which implementation to use solely in the configuration. --- .../DefaultRepositoryInvokerFactory.java | 102 ++++++++++++++++++ .../rest/core/invoke/RepositoryInvoker.java | 2 +- .../core/invoke/RepositoryInvokerFactory.java | 64 ++--------- ...tRequestHandlerMethodArgumentResolver.java | 15 +-- .../RepositoryRestMvcConfiguration.java | 5 +- 5 files changed, 123 insertions(+), 65 deletions(-) create mode 100644 spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/DefaultRepositoryInvokerFactory.java diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/DefaultRepositoryInvokerFactory.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/DefaultRepositoryInvokerFactory.java new file mode 100644 index 000000000..58f2e40eb --- /dev/null +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/DefaultRepositoryInvokerFactory.java @@ -0,0 +1,102 @@ +/* + * 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.rest.core.invoke; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.core.convert.ConversionService; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.data.repository.core.RepositoryInformation; +import org.springframework.data.repository.support.Repositories; +import org.springframework.util.Assert; + +/** + * Default implementation of {@link RepositoryInvokerFactory} to inspect the requested repository type and create a + * matching {@link RepositoryInvoker} that suits the repository best. That means, the more concrete the base interface + * of the repository is, the more concrete will the actual invoker become - which means it will favor concrete method + * invocations over reflection ones. + * + * @author Oliver Gierke + */ +public class DefaultRepositoryInvokerFactory implements RepositoryInvokerFactory { + + private final Repositories repositories; + private final ConversionService conversionService; + private final Map, RepositoryInvoker> invokers; + + /** + * Creates a new {@link DefaultRepositoryInvokerFactory} for the given {@link Repositories} and + * {@link ConversionService}. + * + * @param repositories must not be {@literal null}. + * @param conversionService must not be {@literal null}. + */ + public DefaultRepositoryInvokerFactory(Repositories repositories, ConversionService conversionService) { + + Assert.notNull(repositories, "Repositories must not be null!"); + Assert.notNull(conversionService, "ConversionService must not be null!"); + + this.repositories = repositories; + this.conversionService = conversionService; + this.invokers = new HashMap, RepositoryInvoker>(); + + } + + /** + * Creates a {@link RepositoryInvoker} for the repository managing the given domain type. + * + * @param domainType + * @return + */ + @SuppressWarnings("unchecked") + private RepositoryInvoker prepareInvokers(Class domainType) { + + Object repository = repositories.getRepositoryFor(domainType); + RepositoryInformation information = repositories.getRepositoryInformationFor(domainType); + + if (repository instanceof PagingAndSortingRepository) { + return new PagingAndSortingRepositoryInvoker((PagingAndSortingRepository) repository, + information, conversionService); + } else if (repository instanceof CrudRepository) { + return new CrudRepositoryInvoker((CrudRepository) repository, information, + conversionService); + } else { + return new ReflectionRepositoryInvoker(repository, information, conversionService); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.rest.core.invoke.RepositoryInvokerFactory#getInvokerFor(java.lang.Class) + */ + @Override + public RepositoryInvoker getInvokerFor(Class domainType) { + + RepositoryInvoker invoker = invokers.get(domainType); + + if (invoker != null) { + return invoker; + } + + invoker = prepareInvokers(domainType); + invokers.put(domainType, invoker); + + return invoker; + } +} diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/RepositoryInvoker.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/RepositoryInvoker.java index 6b4c733f9..db370a339 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/RepositoryInvoker.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/RepositoryInvoker.java @@ -33,7 +33,7 @@ public interface RepositoryInvoker extends RepositoryInvocationInformation { Iterable invokeFindAll(Pageable pageable); - Iterable invokeFindAll(Sort pageable); + Iterable invokeFindAll(Sort sort); void invokeDelete(Serializable serializable); diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/RepositoryInvokerFactory.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/RepositoryInvokerFactory.java index abfd8179a..fddd280fe 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/RepositoryInvokerFactory.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/invoke/RepositoryInvokerFactory.java @@ -15,65 +15,19 @@ */ package org.springframework.data.rest.core.invoke; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.core.convert.ConversionService; -import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.PagingAndSortingRepository; -import org.springframework.data.repository.core.RepositoryInformation; -import org.springframework.data.repository.support.Repositories; - /** + * Interface for a factory to create {@link RepositoryInvoker} instances for repositories managing a particular domain + * type. + * * @author Oliver Gierke */ -public class RepositoryInvokerFactory { - - private final Repositories repositories; - private final ConversionService conversionService; - - private final Map, RepositoryInvoker> invokers; +public interface RepositoryInvokerFactory { /** - * @param repositories + * Returns the {@link RepositoryInvoker} for a repository managing the given domain type. + * + * @param domainType must not be {@literal null}. + * @return */ - public RepositoryInvokerFactory(Repositories repositories, ConversionService conversionService) { - - this.repositories = repositories; - this.conversionService = conversionService; - this.invokers = new HashMap, RepositoryInvoker>(); - - } - - @SuppressWarnings("unchecked") - private RepositoryInvoker prepareInvokers(Class domainType) { - - Object repository = repositories.getRepositoryFor(domainType); - RepositoryInformation information = repositories.getRepositoryInformationFor(domainType); - - if (repository instanceof PagingAndSortingRepository) { - return new PagingAndSortingRepositoryInvoker((PagingAndSortingRepository) repository, - information, conversionService); - } else if (repository instanceof CrudRepository) { - return new CrudRepositoryInvoker((CrudRepository) repository, information, - conversionService); - } else { - return new ReflectionRepositoryInvoker(repository, information, conversionService); - } - } - - public RepositoryInvoker getInvokerFor(Class domainType) { - - RepositoryInvoker invoker = invokers.get(domainType); - - if (invoker != null) { - return invoker; - } - - invoker = prepareInvokers(domainType); - invokers.put(domainType, invoker); - - return invoker; - } + RepositoryInvoker getInvokerFor(Class domainType); } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestRequestHandlerMethodArgumentResolver.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestRequestHandlerMethodArgumentResolver.java index 341e9979c..765fca83d 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestRequestHandlerMethodArgumentResolver.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestRequestHandlerMethodArgumentResolver.java @@ -16,7 +16,6 @@ package org.springframework.data.rest.webmvc; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.repository.support.Repositories; import org.springframework.data.rest.core.invoke.RepositoryInvoker; @@ -39,20 +38,22 @@ public class RepositoryRestRequestHandlerMethodArgumentResolver implements Handl private final ResourceMetadataHandlerMethodArgumentResolver resourceMetadataResolver; /** - * Creates a new {@link RepositoryRestRequestHandlerMethodArgumentResolver} using the given {@link Repositories} and - * {@link ConversionService}. + * Creates a new {@link RepositoryRestRequestHandlerMethodArgumentResolver} using the given {@link Repositories}, + * {@link RepositoryInvokerFactory} and {@link ResourceMetadataHandlerMethodArgumentResolver}. * * @param repositories must not be {@literal null}. - * @param conversionService must not be {@literal null}. + * @param invokerFactory must not be {@literal null}. + * @param resourceMetadataResolver must not be {@literal null}. */ public RepositoryRestRequestHandlerMethodArgumentResolver(Repositories repositories, - ConversionService conversionService, ResourceMetadataHandlerMethodArgumentResolver resourceMetadataResolver) { + RepositoryInvokerFactory invokerFactory, ResourceMetadataHandlerMethodArgumentResolver resourceMetadataResolver) { Assert.notNull(repositories, "Repositories must not be null!"); - Assert.notNull(conversionService, "ConversionService must not be null!"); + Assert.notNull(invokerFactory, "invokerFactory must not be null!"); + Assert.notNull(resourceMetadataResolver, "ResourceMetadataHandlerMethodArgumentResolver must not be null!"); this.repositories = repositories; - this.invokerFactory = new RepositoryInvokerFactory(repositories, conversionService); + this.invokerFactory = invokerFactory; this.resourceMetadataResolver = resourceMetadataResolver; } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java index b1d02f0db..c850b7007 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java @@ -38,6 +38,7 @@ import org.springframework.data.rest.core.UriDomainClassConverter; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.core.event.AnnotatedHandlerBeanPostProcessor; import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener; +import org.springframework.data.rest.core.invoke.DefaultRepositoryInvokerFactory; import org.springframework.data.rest.core.invoke.RepositoryInvokerFactory; import org.springframework.data.rest.core.mapping.ResourceMappings; import org.springframework.data.rest.core.support.DomainObjectMerger; @@ -204,7 +205,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon */ @Bean public RepositoryRestRequestHandlerMethodArgumentResolver repoRequestArgumentResolver() { - return new RepositoryRestRequestHandlerMethodArgumentResolver(repositories(), defaultConversionService(), + return new RepositoryRestRequestHandlerMethodArgumentResolver(repositories(), repositoryInvokerFactory(), resourceMetadataHandlerMethodArgumentResolver()); } @@ -376,7 +377,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon @Bean public RepositoryInvokerFactory repositoryInvokerFactory() { - return new RepositoryInvokerFactory(repositories(), defaultConversionService()); + return new DefaultRepositoryInvokerFactory(repositories(), defaultConversionService()); } private List> defaultMessageConverters() {