net.sf.gazpachoquest.qbe.ByExampleSpecification.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.gazpachoquest.qbe.ByExampleSpecification.java

Source

/*******************************************************************************
 * Copyright (c) 2014 antoniomariasanchez at gmail.com.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     antoniomaria - initial API and implementation
 ******************************************************************************/
package net.sf.gazpachoquest.qbe;

import static javax.persistence.metamodel.Attribute.PersistentAttributeType.EMBEDDED;
import static javax.persistence.metamodel.Attribute.PersistentAttributeType.MANY_TO_ONE;
import static javax.persistence.metamodel.Attribute.PersistentAttributeType.ONE_TO_ONE;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.SetJoin;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;

import net.sf.gazpachoquest.domain.support.Persistable;

import org.apache.commons.lang3.Validate;
import org.eclipse.persistence.indirection.ValueHolderInterface;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.ReflectionUtils;

public class ByExampleSpecification {

    private final EntityManager em;

    public ByExampleSpecification(final EntityManager em) {
        this.em = em;
    }

    public <T extends Persistable> Specification<T> byExampleOnEntity(final T example, final SearchParameters sp) {
        Validate.notNull(example, "example must not be null");

        return new Specification<T>() {

            @Override
            public Predicate toPredicate(final Root<T> rootPath, final CriteriaQuery<?> query,
                    final CriteriaBuilder builder) {
                Class<T> type = rootPath.getModel().getBindableJavaType();

                ManagedType<T> mt = em.getMetamodel().entity(type);

                List<Predicate> predicates = new ArrayList<Predicate>();
                predicates.addAll(byExample(mt, rootPath, example, sp, builder));
                predicates.addAll(byExampleOnXToOne(mt, rootPath, example, sp, builder));
                // 1 level deep only
                predicates.addAll(byExampleOnManyToMany(mt, rootPath, example, sp, builder));
                // order by
                query.orderBy(JpaUtil.buildJpaOrders(sp.getOrders(), rootPath, builder));
                return JpaUtil.andPredicate(builder, predicates);
            }

            //https://github.com/jaxio/generated-projects/tree/master/jsf2-spring-conversation/src/main/generated-java/com/jaxio/appli/repository/support

            public <T extends Persistable> List<Predicate> byExample(final ManagedType<T> mt, final Path<T> mtPath,
                    final T mtValue, final SearchParameters sp, final CriteriaBuilder builder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                for (SingularAttribute<? super T, ?> attr : mt.getSingularAttributes()) {
                    if (attr.getPersistentAttributeType() == MANY_TO_ONE
                            || attr.getPersistentAttributeType() == ONE_TO_ONE
                            || attr.getPersistentAttributeType() == EMBEDDED
                            || attr.getJavaType().isAssignableFrom(Map.class)) {
                        continue;
                    }
                    Object attrValue = getValue(mtValue, attr);

                    if (attrValue != null) {
                        if (attr.getJavaType() == String.class) {
                            if (isNotEmpty((String) attrValue)) {
                                SingularAttribute<? super T, String> stringAttribute = mt
                                        .getSingularAttribute(attr.getName(), String.class);
                                predicates.add(JpaUtil.stringPredicate(mtPath.get(stringAttribute), attrValue, sp,
                                        builder));
                            }
                        } else {
                            SingularAttribute<? super T, ?> attribute = mt.getSingularAttribute(attr.getName(),
                                    attr.getJavaType());
                            // apply equal
                            predicates.add(builder.equal(mtPath.get(attribute), attrValue));
                        }
                    }
                }
                return predicates;
            }

            /**
             * Construct a join predicate on collection (eg many to many, List)
             */
            public <T extends Persistable> List<Predicate> byExampleOnManyToMany(final ManagedType<T> mt,
                    final Root<T> mtPath, final T mtValue, final SearchParameters sp,
                    final CriteriaBuilder builder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                for (PluralAttribute<T, ?, ?> pa : mt.getDeclaredPluralAttributes()) {
                    if (pa.getCollectionType() == PluralAttribute.CollectionType.LIST) {
                        List<?> value = (List<?>) getValue(mtValue, mt.getAttribute(pa.getName()));

                        if (value != null && !value.isEmpty()) {
                            ListJoin<T, ?> join = mtPath.join(mt.getDeclaredList(pa.getName()));
                            predicates.add(join.in(value));
                        }
                    }
                    if (pa.getCollectionType() == PluralAttribute.CollectionType.SET) {
                        Set<?> value = (Set<?>) getValue(mtValue, mt.getAttribute(pa.getName()));

                        if (value != null && !value.isEmpty()) {
                            SetJoin<T, ?> join = mtPath.join(mt.getDeclaredSet(pa.getName()));
                            predicates.add(join.in(value));
                        }
                    }
                }
                return predicates;
            }

            /**
             * Invoke byExample method for each not null x-to-one association
             * when their pk is not set. This allows you
             * to search entities based on an associated entity's properties
             * value.
             */
            @SuppressWarnings("unchecked")
            public <T extends Persistable, M2O extends Persistable> List<Predicate> byExampleOnXToOne(
                    final ManagedType<T> mt, final Root<T> mtPath, final T mtValue, final SearchParameters sp,
                    final CriteriaBuilder builder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                for (SingularAttribute<? super T, ?> attr : mt.getSingularAttributes()) {
                    if (attr.getPersistentAttributeType() == MANY_TO_ONE
                            || attr.getPersistentAttributeType() == ONE_TO_ONE) { //
                        M2O m2oValue = (M2O) getValue(mtValue, mt.getAttribute(attr.getName()));

                        if (m2oValue != null) {
                            Class<M2O> m2oType = (Class<M2O>) attr.getBindableJavaType();
                            ManagedType<M2O> m2oMt = em.getMetamodel().entity(m2oType);
                            Path<M2O> m2oPath = (Path<M2O>) mtPath.get(attr);
                            predicates.addAll(byExample(m2oMt, m2oPath, m2oValue, sp, builder));
                        }
                    }
                }
                return predicates;
            }

            private <T> Object getValue(final T example, final Attribute<? super T, ?> attr) {
                Object value = null;
                try {
                    if (attr.getJavaMember() instanceof Method) {
                        value = ((Method) attr.getJavaMember()).invoke(example, new Object[0]);
                    } else if (attr.getJavaMember() instanceof Field) {
                        value = ReflectionUtils.getField((Field) attr.getJavaMember(), example);
                    }

                    if (value instanceof ValueHolderInterface) {
                        value = ((ValueHolderInterface) value).getValue();
                    }

                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
                return value;
            }

        };

    }

}