/* * Copyright 2015 JAXIO http://www.jaxio.com * * 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 com.jaxio.jpa.querybyexample; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import javax.persistence.Embeddable; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.SingularAttribute; import java.io.Serializable; import java.util.List; import static com.google.common.collect.Lists.newArrayList; import static java.util.Collections.emptyList; /** * @author Nicolas Romanetti * @author Florent Ramière * @author Sébastien Péralta * @author Jean-Louis Boudart */ @Named @Singleton public class ByFullTextUtil { @PersistenceContext private EntityManager em; @Inject protected HibernateSearchUtil hibernateSearchUtil; @Inject private JpaUtil jpaUtil; public <T extends Identifiable<?>> Predicate byFullText(Root<T> root, CriteriaBuilder builder, SearchParameters sp, T entity, List<SingularAttribute<?, ?>> indexedAttributes) { if (!hasNonEmptyTerms(sp)) { return null; } if (jpaUtil.hasSimplePk(entity)) { return onSimplePrimaryKey(root, builder, sp, indexedAttributes); } else { return onCompositePrimaryKeys(root, builder, sp, indexedAttributes); } } private boolean hasNonEmptyTerms(SearchParameters sp) { for (TermSelector termSelector : sp.getTerms()) { if (termSelector.isNotEmpty()) { return true; } } return false; } private <T extends Identifiable<?>> Predicate onCompositePrimaryKeys(Root<T> root, CriteriaBuilder builder, SearchParameters sp, List<SingularAttribute<?, ?>> properties) { List<? extends T> found = hibernateSearchUtil.find(root.getJavaType(), sp, properties); if (found == null) { return null; } else if (found.isEmpty()) { return builder.disjunction(); } List<Predicate> predicates = newArrayList(); for (T t : found) { predicates.add(byExampleOnEntity(root, t, sp, builder)); } return jpaUtil.concatPredicate(sp, builder, jpaUtil.orPredicate(builder, predicates)); } private <T> Predicate onSimplePrimaryKey(Root<T> root, CriteriaBuilder builder, SearchParameters sp, List<SingularAttribute<?, ?>> properties) { List<Serializable> ids = hibernateSearchUtil.findId(root.getJavaType(), sp, properties); if (ids == null) { return null; } else if (ids.isEmpty()) { return builder.disjunction(); } return jpaUtil.concatPredicate(sp, builder, root.get("id").in(ids)); } public <T extends Identifiable<?>> Predicate byExampleOnEntity(Root<T> rootPath, T entityValue, SearchParameters sp, CriteriaBuilder builder) { if (entityValue == null) { return null; } Class<T> type = rootPath.getModel().getBindableJavaType(); ManagedType<T> mt = em.getMetamodel().entity(type); List<Predicate> predicates = newArrayList(); predicates.addAll(byExample(mt, rootPath, entityValue, sp, builder)); predicates.addAll(byExampleOnCompositePk(rootPath, entityValue, sp, builder)); return jpaUtil.orPredicate(builder, predicates); } protected <T extends Identifiable<?>> List<Predicate> byExampleOnCompositePk(Root<T> root, T entity, SearchParameters sp, CriteriaBuilder builder) { String compositePropertyName = jpaUtil.compositePkPropertyName(entity); if (compositePropertyName == null) { return emptyList(); } else { return newArrayList(byExampleOnEmbeddable(root.get(compositePropertyName), entity.getId(), sp, builder)); } } public <E> Predicate byExampleOnEmbeddable(Path<E> embeddablePath, E embeddableValue, SearchParameters sp, CriteriaBuilder builder) { if (embeddableValue == null) { return null; } Class<E> type = embeddablePath.getModel().getBindableJavaType(); ManagedType<E> mt = em.getMetamodel().embeddable(type); // note: calling .managedType() does not work return jpaUtil.orPredicate(builder, byExample(mt, embeddablePath, embeddableValue, sp, builder)); } /* * Add a predicate for each simple property whose value is not null. */ public <T> List<Predicate> byExample(ManagedType<T> mt, Path<T> mtPath, T mtValue, SearchParameters sp, CriteriaBuilder builder) { List<Predicate> predicates = newArrayList(); for (SingularAttribute<? super T, ?> attr : mt.getSingularAttributes()) { if (!isPrimaryKey(mt, attr)) { continue; } Object attrValue = jpaUtil.getValue(mtValue, attr); if (attrValue != null) { predicates.add(builder.equal(mtPath.get(jpaUtil.attribute(mt, attr)), attrValue)); } } return predicates; } private <T> boolean isPrimaryKey(ManagedType<T> mt, SingularAttribute<? super T, ?> attr) { if (mt.getJavaType().getAnnotation(Embeddable.class) != null) { return true; } return jpaUtil.isPk(mt, attr); } }