org.springframework.data.repository.support.DefaultRepositoryInvokerFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.data.repository.support.DefaultRepositoryInvokerFactory.java

Source

/*
 * Copyright 2013-2019 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
 *
 *      https://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.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

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 ConcurrentHashMap<>();
    }

    /*
     * (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);
        }
    }
}