1. 程式人生 > >【Spring Data Jpa學習】SimpleJpaRepository原始碼

【Spring Data Jpa學習】SimpleJpaRepository原始碼

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.data.jpa.repository.support;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Map.Entry;
import java.util.function.Consumer;
import java.util.function.LongSupplier;
import java.util.function.Supplier;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.data.jpa.repository.support.QueryHints.NoHints;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

@Repository
@Transactional(
    readOnly = true
)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
    private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!";
    private final JpaEntityInformation<T, ?> entityInformation;
    private final EntityManager em;
    private final PersistenceProvider provider;
    @Nullable
    private CrudMethodMetadata metadata;

    public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        Assert.notNull(entityInformation, "JpaEntityInformation must not be null!");
        Assert.notNull(entityManager, "EntityManager must not be null!");
        this.entityInformation = entityInformation;
        this.em = entityManager;
        this.provider = PersistenceProvider.fromEntityManager(entityManager);
    }

    public SimpleJpaRepository(Class<T> domainClass, EntityManager em) {
        this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
    }

    public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {
        this.metadata = crudMethodMetadata;
    }

    @Nullable
    protected CrudMethodMetadata getRepositoryMethodMetadata() {
        return this.metadata;
    }

    protected Class<T> getDomainClass() {
        return this.entityInformation.getJavaType();
    }

    private String getDeleteAllQueryString() {
        return QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName());
    }

    private String getCountQueryString() {
        String countQuery = String.format("select count(%s) from %s x", this.provider.getCountQueryPlaceholder(), "%s");
        return QueryUtils.getQueryString(countQuery, this.entityInformation.getEntityName());
    }

    @Transactional
    public void deleteById(ID id) {
        Assert.notNull(id, "The given id must not be null!");
        this.delete(this.findById(id).orElseThrow(() -> {
            return new EmptyResultDataAccessException(String.format("No %s entity with id %s exists!", this.entityInformation.getJavaType(), id), 1);
        }));
    }

    @Transactional
    public void delete(T entity) {
        Assert.notNull(entity, "The entity must not be null!");
        this.em.remove(this.em.contains(entity) ? entity : this.em.merge(entity));
    }

    @Transactional
    public void deleteAll(Iterable<? extends T> entities) {
        Assert.notNull(entities, "The given Iterable of entities not be null!");
        Iterator var2 = entities.iterator();

        while(var2.hasNext()) {
            T entity = var2.next();
            this.delete(entity);
        }

    }

    @Transactional
    public void deleteInBatch(Iterable<T> entities) {
        Assert.notNull(entities, "The given Iterable of entities not be null!");
        if (entities.iterator().hasNext()) {
            QueryUtils.applyAndBind(QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName()), entities, this.em).executeUpdate();
        }
    }

    @Transactional
    public void deleteAll() {
        Iterator var1 = this.findAll().iterator();

        while(var1.hasNext()) {
            T element = var1.next();
            this.delete(element);
        }

    }

    @Transactional
    public void deleteAllInBatch() {
        this.em.createQuery(this.getDeleteAllQueryString()).executeUpdate();
    }

    public Optional<T> findById(ID id) {
        Assert.notNull(id, "The given id must not be null!");
        Class<T> domainType = this.getDomainClass();
        if (this.metadata == null) {
            return Optional.ofNullable(this.em.find(domainType, id));
        } else {
            LockModeType type = this.metadata.getLockModeType();
            Map<String, Object> hints = this.getQueryHints().withFetchGraphs(this.em).asMap();
            return Optional.ofNullable(type == null ? this.em.find(domainType, id, hints) : this.em.find(domainType, id, type, hints));
        }
    }

    protected QueryHints getQueryHints() {
        return (QueryHints)(this.metadata == null ? NoHints.INSTANCE : DefaultQueryHints.of(this.entityInformation, this.metadata));
    }

    public T getOne(ID id) {
        Assert.notNull(id, "The given id must not be null!");
        return this.em.getReference(this.getDomainClass(), id);
    }

    public boolean existsById(ID id) {
        Assert.notNull(id, "The given id must not be null!");
        if (this.entityInformation.getIdAttribute() == null) {
            return this.findById(id).isPresent();
        } else {
            String placeholder = this.provider.getCountQueryPlaceholder();
            String entityName = this.entityInformation.getEntityName();
            Iterable<String> idAttributeNames = this.entityInformation.getIdAttributeNames();
            String existsQuery = QueryUtils.getExistsQueryString(entityName, placeholder, idAttributeNames);
            TypedQuery<Long> query = this.em.createQuery(existsQuery, Long.class);
            if (!this.entityInformation.hasCompositeId()) {
                query.setParameter((String)idAttributeNames.iterator().next(), id);
                return (Long)query.getSingleResult() == 1L;
            } else {
                Iterator var7 = idAttributeNames.iterator();

                while(var7.hasNext()) {
                    String idAttributeName = (String)var7.next();
                    Object idAttributeValue = this.entityInformation.getCompositeIdAttributeValue(id, idAttributeName);
                    boolean complexIdParameterValueDiscovered = idAttributeValue != null && !query.getParameter(idAttributeName).getParameterType().isAssignableFrom(idAttributeValue.getClass());
                    if (complexIdParameterValueDiscovered) {
                        return this.findById(id).isPresent();
                    }

                    query.setParameter(idAttributeName, idAttributeValue);
                }

                return (Long)query.getSingleResult() == 1L;
            }
        }
    }

    public List<T> findAll() {
        return this.getQuery((Specification)null, (Sort)Sort.unsorted()).getResultList();
    }

    public List<T> findAllById(Iterable<ID> ids) {
        Assert.notNull(ids, "The given Iterable of Id's must not be null!");
        if (!ids.iterator().hasNext()) {
            return Collections.emptyList();
        } else if (!this.entityInformation.hasCompositeId()) {
            SimpleJpaRepository.ByIdsSpecification<T> specification = new SimpleJpaRepository.ByIdsSpecification(this.entityInformation);
            TypedQuery<T> query = this.getQuery(specification, (Sort)Sort.unsorted());
            return query.setParameter(specification.parameter, ids).getResultList();
        } else {
            List<T> results = new ArrayList();
            Iterator var3 = ids.iterator();

            while(var3.hasNext()) {
                ID id = var3.next();
                this.findById(id).ifPresent(results::add);
            }

            return results;
        }
    }

    public List<T> findAll(Sort sort) {
        return this.getQuery((Specification)null, (Sort)sort).getResultList();
    }

    public Page<T> findAll(Pageable pageable) {
        return (Page)(isUnpaged(pageable) ? new PageImpl(this.findAll()) : this.findAll((Specification)null, pageable));
    }

    public Optional<T> findOne(@Nullable Specification<T> spec) {
        try {
            return Optional.of(this.getQuery(spec, Sort.unsorted()).getSingleResult());
        } catch (NoResultException var3) {
            return Optional.empty();
        }
    }

    public List<T> findAll(@Nullable Specification<T> spec) {
        return this.getQuery(spec, Sort.unsorted()).getResultList();
    }

    public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
        TypedQuery<T> query = this.getQuery(spec, pageable);
        return (Page)(isUnpaged(pageable) ? new PageImpl(query.getResultList()) : this.readPage(query, this.getDomainClass(), pageable, spec));
    }

    public List<T> findAll(@Nullable Specification<T> spec, Sort sort) {
        return this.getQuery(spec, sort).getResultList();
    }

    public <S extends T> Optional<S> findOne(Example<S> example) {
        try {
            return Optional.of(this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)Sort.unsorted()).getSingleResult());
        } catch (NoResultException var3) {
            return Optional.empty();
        }
    }

    public <S extends T> long count(Example<S> example) {
        return executeCountQuery(this.getCountQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType()));
    }

    public <S extends T> boolean exists(Example<S> example) {
        return !this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)Sort.unsorted()).getResultList().isEmpty();
    }

    public <S extends T> List<S> findAll(Example<S> example) {
        return this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)Sort.unsorted()).getResultList();
    }

    public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
        return this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)sort).getResultList();
    }

    public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
        SimpleJpaRepository.ExampleSpecification<S> spec = new SimpleJpaRepository.ExampleSpecification(example);
        Class<S> probeType = example.getProbeType();
        TypedQuery<S> query = this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), probeType, (Pageable)pageable);
        return (Page)(isUnpaged(pageable) ? new PageImpl(query.getResultList()) : this.readPage(query, probeType, pageable, spec));
    }

    public long count() {
        return (Long)this.em.createQuery(this.getCountQueryString(), Long.class).getSingleResult();
    }

    public long count(@Nullable Specification<T> spec) {
        return executeCountQuery(this.getCountQuery(spec, this.getDomainClass()));
    }

    @Transactional
    public <S extends T> S save(S entity) {
        if (this.entityInformation.isNew(entity)) {
            this.em.persist(entity);
            return entity;
        } else {
            return this.em.merge(entity);
        }
    }

    @Transactional
    public <S extends T> S saveAndFlush(S entity) {
        S result = this.save(entity);
        this.flush();
        return result;
    }

    @Transactional
    public <S extends T> List<S> saveAll(Iterable<S> entities) {
        Assert.notNull(entities, "The given Iterable of entities not be null!");
        List<S> result = new ArrayList();
        Iterator var3 = entities.iterator();

        while(var3.hasNext()) {
            S entity = var3.next();
            result.add(this.save(entity));
        }

        return result;
    }

    @Transactional
    public void flush() {
        this.em.flush();
    }

    /** @deprecated */
    @Deprecated
    protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, @Nullable Specification<T> spec) {
        return this.readPage(query, this.getDomainClass(), pageable, spec);
    }

    protected <S extends T> Page<S> readPage(TypedQuery<S> query, Class<S> domainClass, Pageable pageable, @Nullable Specification<S> spec) {
        if (pageable.isPaged()) {
            query.setFirstResult((int)pageable.getOffset());
            query.setMaxResults(pageable.getPageSize());
        }

        return PageableExecutionUtils.getPage(query.getResultList(), pageable, () -> {
            return executeCountQuery(this.getCountQuery(spec, domainClass));
        });
    }

    protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Pageable pageable) {
        Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
        return this.getQuery(spec, this.getDomainClass(), sort);
    }

    protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Pageable pageable) {
        Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
        return this.getQuery(spec, domainClass, sort);
    }

    protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Sort sort) {
        return this.getQuery(spec, this.getDomainClass(), sort);
    }

    protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) {
        CriteriaBuilder builder = this.em.getCriteriaBuilder();
        CriteriaQuery<S> query = builder.createQuery(domainClass);
        Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);
        query.select(root);
        if (sort.isSorted()) {
            query.orderBy(QueryUtils.toOrders(sort, root, builder));
        }

        return this.applyRepositoryMethodMetadata(this.em.createQuery(query));
    }

    /** @deprecated */
    @Deprecated
    protected TypedQuery<Long> getCountQuery(@Nullable Specification<T> spec) {
        return this.getCountQuery(spec, this.getDomainClass());
    }

    protected <S extends T> TypedQuery<Long> getCountQuery(@Nullable Specification<S> spec, Class<S> domainClass) {
        CriteriaBuilder builder = this.em.getCriteriaBuilder();
        CriteriaQuery<Long> query = builder.createQuery(Long.class);
        Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);
        if (query.isDistinct()) {
            query.select(builder.countDistinct(root));
        } else {
            query.select(builder.count(root));
        }

        query.orderBy(Collections.emptyList());
        return this.em.createQuery(query);
    }

    private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass, CriteriaQuery<S> query) {
        Assert.notNull(domainClass, "Domain class must not be null!");
        Assert.notNull(query, "CriteriaQuery must not be null!");
        Root<U> root = query.from(domainClass);
        if (spec == null) {
            return root;
        } else {
            CriteriaBuilder builder = this.em.getCriteriaBuilder();
            Predicate predicate = spec.toPredicate(root, query, builder);
            if (predicate != null) {
                query.where(predicate);
            }

            return root;
        }
    }

    private <S> TypedQuery<S> applyRepositoryMethodMetadata(TypedQuery<S> query) {
        if (this.metadata == null) {
            return query;
        } else {
            LockModeType type = this.metadata.getLockModeType();
            TypedQuery<S> toReturn = type == null ? query : query.setLockMode(type);
            this.applyQueryHints(toReturn);
            return toReturn;
        }
    }

    private void applyQueryHints(Query query) {
        Iterator var2 = this.getQueryHints().withFetchGraphs(this.em).iterator();

        while(var2.hasNext()) {
            Entry<String, Object> hint = (Entry)var2.next();
            query.setHint((String)hint.getKey(), hint.getValue());
        }

    }

    private static long executeCountQuery(TypedQuery<Long> query) {
        Assert.notNull(query, "TypedQuery must not be null!");
        List<Long> totals = query.getResultList();
        long total = 0L;

        Long element;
        for(Iterator var4 = totals.iterator(); var4.hasNext(); total += element == null ? 0L : element) {
            element = (Long)var4.next();
        }

        return total;
    }

    private static boolean isUnpaged(Pageable pageable) {
        return pageable.isUnpaged();
    }

    private static class ExampleSpecification<T> implements Specification<T> {
        private static final long serialVersionUID = 1L;
        private final Example<T> example;

        ExampleSpecification(Example<T> example) {
            Assert.notNull(example, "Example must not be null!");
            this.example = example;
        }

        public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            return QueryByExamplePredicateBuilder.getPredicate(root, cb, this.example);
        }
    }

    private static final class ByIdsSpecification<T> implements Specification<T> {
        private static final long serialVersionUID = 1L;
        private final JpaEntityInformation<T, ?> entityInformation;
        @Nullable
        ParameterExpression<Iterable> parameter;

        ByIdsSpecification(JpaEntityInformation<T, ?> entityInformation) {
            this.entityInformation = entityInformation;
        }

        public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            Path<?> path = root.get(this.entityInformation.getIdAttribute());
            this.parameter = cb.parameter(Iterable.class);
            return path.in(new Expression[]{this.parameter});
        }
    }
}