/* * Copyright 2013-2017 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.springframework.data.util.Optionals.*; import java.util.HashMap; import java.util.Map; import java.util.Optional; 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.format.support.DefaultFormattingConversionService; 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 * @author Christoph Strobl * @since 1.10 */ public class DefaultRepositoryInvokerFactory implements RepositoryInvokerFactory { private final Repositories repositories; private final ConversionService conversionService; private final Map<Class<?>, RepositoryInvoker> invokers; /** * Creates a new {@link DefaultRepositoryInvokerFactory} for the given {@link Repositories}. * * @param repositories must not be {@literal null}. */ public DefaultRepositoryInvokerFactory(Repositories repositories) { this(repositories, new DefaultFormattingConversionService()); } /** * 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<>(); } /* * (non-Javadoc) * @see org.springframework.data.rest.core.invoke.RepositoryInvokerFactory#getInvokerFor(java.lang.Class) */ @Override public RepositoryInvoker getInvokerFor(Class<?> domainType) { return invokers.computeIfAbsent(domainType, this::prepareInvokers); } /** * Creates a {@link RepositoryInvoker} for the repository managing the given domain type. * * @param domainType * @return */ private RepositoryInvoker prepareInvokers(Class<?> domainType) { Optional<RepositoryInformation> information = repositories.getRepositoryInformationFor(domainType); Optional<Object> repository = repositories.getRepositoryFor(domainType); return mapIfAllPresent(information, repository, this::createInvoker)// .orElseThrow( () -> new IllegalArgumentException(String.format("No repository found for domain type: %s", domainType))); } @SuppressWarnings("unchecked") protected RepositoryInvoker createInvoker(RepositoryInformation information, Object repository) { if (repository instanceof PagingAndSortingRepository) { return new PagingAndSortingRepositoryInvoker((PagingAndSortingRepository<Object, Object>) repository, information, conversionService); } else if (repository instanceof CrudRepository) { return new CrudRepositoryInvoker((CrudRepository<Object, Object>) repository, information, conversionService); } else { return new ReflectionRepositoryInvoker(repository, information, conversionService); } } }