Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.earchitecture.reuse.model.specification.Specs Maven / Gradle / Ivy
package com.github.earchitecture.reuse.model.specification;
import com.github.earchitecture.reuse.model.annotation.GreaterThan;
import com.github.earchitecture.reuse.model.annotation.GreaterThanOrEqualTo;
import com.github.earchitecture.reuse.model.annotation.Ignore;
import com.github.earchitecture.reuse.model.annotation.LessThan;
import com.github.earchitecture.reuse.model.annotation.LessThanOrEqualTo;
import com.github.earchitecture.reuse.model.annotation.StartsWith;
import com.github.earchitecture.reuse.model.annotation.UseForeignKeySearch;
import com.github.earchitecture.reuse.model.annotation.UseLikeForSearch;
import com.github.earchitecture.reuse.model.entity.Identifiable;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.jpa.domain.Specification;
/**
* Classe que descreve implementação de pesquisa generica para consultas com criteria
*
* @author Cleber Barcelos Costa
*/
public class Specs {
protected static Specs specs = new Specs();
public Specs() {
}
/**
* Recupera por atributos da classe.
*
* @param clazz
* clazz
*
* @param entity
* entity
* @param
* Tipo da classe
* @param
* entidade
* @return ret {@link Specification}
*
*/
public static Specification byExample(final Class clazz, final B entity) {
return specs.new ByExampleSpecification(entity);
}
/**
* Implementação de specificarion por exemplo.
*
* @param
* t
* @param
* b
*/
public class ByExampleSpecification implements Specification {
private final B entity;
public ByExampleSpecification(B entity) {
this.entity = entity;
}
@Override
public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
List predicates = this.findPredicate(root, query, cb, this.entity, null);
Predicate ret = null;
if (predicates != null && !predicates.isEmpty()) {
for (Predicate predicate : predicates) {
if (ret == null) {
ret = cb.and(predicate);
} else {
ret = cb.and(ret, predicate);
}
}
}
return ret;
}
/**
* Recupera predicate e sub predicate.
*
* @param root
* root
* @param query
* query
* @param cb
* cb
* @param entity
* entity
* @param expression
* expression
* @return List de predicate
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public List findPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb, Object entity, Path expression) {
List predicates = new ArrayList();
PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(entity.getClass());
for (PropertyDescriptor pd : pds) {
try {
/* Caso seja Transient ou Ignore não vai ser considerado para pesquisa de banco de dados. */
if (pd.getReadMethod().isAnnotationPresent(Transient.class) || pd.getReadMethod().isAnnotationPresent(Ignore.class)) {
continue;
}
/* Caso seja getClass, ignora a leitura */
if (pd.getReadMethod() != null && !pd.getName().equalsIgnoreCase("class")) {
Object val = pd.getReadMethod().invoke(entity);
if ((val != null && !(val instanceof ArrayList)) || (val instanceof ArrayList && !((ArrayList>) val).isEmpty())) {
Field field = this.getField(entity.getClass(), pd.getName());
/* Trata regra para enum */
if (val.getClass().isEnum()) {
Expression exp = this.getExpressionParam(root, expression, pd.getName());
predicates.add(cb.equal(exp, val));
continue;
/* Trata regra para Foreign Key */
} else if (expression == null
&& (pd.getReadMethod().isAnnotationPresent(UseForeignKeySearch.class) || field.isAnnotationPresent(ManyToOne.class) || field.isAnnotationPresent(OneToOne.class))) {
List predis = this.findPredicate(root, query, cb, val, root.get(pd.getName()));
if (predis != null && !predis.isEmpty()) {
predicates.addAll(predis);
}
continue;
} else if (val instanceof String) {
/* Se for string e for em branco e para desconsiderar esta condição */
if (StringUtils.isNotBlank((CharSequence) val)) {
this.stringProcessor(root, cb, pd, (String) val, predicates);
}
continue;
} else if (val instanceof Comparable) {
Class extends Comparable> clazz = (Class extends Comparable>) val.getClass();
if (this.comparableProcessor(root, cb, predicates, root.getModel(), pd, val, clazz)) {
continue;
}
}
if (!(val instanceof Identifiable) && !(val instanceof Collection)) {
predicates.add(cb.equal(this.getExpressionParam(root, expression, pd.getName()), val));
}
}
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException exception) {
// logger.warn("Erro ao montar clausula para: " + pd.getName(), exception);
} catch (NoSuchFieldException | SecurityException exception) {
// logger.warn("Erro ao montar clausula para: " + pd.getName(), exception);
}
}
return predicates;
}
private Field getField(Class> clazz, String fieldName) throws NoSuchFieldException {
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException exp) {
field = this.getField(clazz.getSuperclass(), fieldName);
}
return field;
}
/**
* Trata expressão de path, para considerar hierarquia de objeto.
*
* @param root
* Root element
* @param path
* path de subobjetos
* @param name
* nome da propriedade
* @return path da propriedade
*/
private Path getExpressionParam(Root root, Path path, String name) {
if (path != null) {
return path.get(name);
} else {
return root.get(name);
}
}
/**
* Processa condição para string.
*
* @param cb
* {@link CriteriaBuilder}
* @param pd
* {@link PropertyDescriptor}
* @param value
* {@link String}
* @param predicates
* Lista de Predicate a serem adicionados na query
*/
@SuppressWarnings("unchecked")
private void stringProcessor(Root root, CriteriaBuilder cb, PropertyDescriptor pd, String value, List predicates) {
EntityType entity = root.getModel();
Expression exp = (Expression) root.get(entity.getSingularAttribute(pd.getName()));
/* Trata condição que inicia com a palavrea */
StartsWith annStart = pd.getReadMethod().getAnnotation(StartsWith.class);
if (annStart != null) {
/* Ignora espaço */
if (annStart.trim()) {
exp = cb.trim(exp);
value = value.trim();
}
/* Trata lowercase caso seja verdadeiro */
if (annStart.lowercase()) {
exp = cb.lower(exp);
value = value.toLowerCase();
}
predicates.add(cb.like(exp, value + "%"));
}
/* Trata condição de like */
UseLikeForSearch annLike = pd.getReadMethod().getAnnotation(UseLikeForSearch.class);
if (annLike != null) {
/* Ignora espaço */
if (annLike.trim()) {
exp = cb.trim(exp);
value = value.trim();
}
/* Trata lowercase caso seja verdadeiro */
if (annLike.lowercase()) {
exp = cb.lower(exp);
value = value.toLowerCase();
}
predicates.add(cb.like(exp, "%" + value + "%"));
}
if (annLike == null && annStart == null) {
predicates.add(cb.equal(exp, value));
}
}
@SuppressWarnings("unchecked")
private > boolean comparableProcessor(Root root, CriteriaBuilder cb, List predicates, EntityType entity, PropertyDescriptor pd, Object val,
Class clazz) {
boolean ret = false;
if (pd.getReadMethod().isAnnotationPresent(GreaterThanOrEqualTo.class)) {
String field = pd.getReadMethod().getAnnotation(GreaterThanOrEqualTo.class).field();
predicates.add(cb.lessThanOrEqualTo(root.get(entity.getSingularAttribute(field, clazz)), (C) val));
ret = true;
} else if (pd.getReadMethod().isAnnotationPresent(LessThanOrEqualTo.class)) {
String field = pd.getReadMethod().getAnnotation(LessThanOrEqualTo.class).field();
predicates.add(cb.greaterThanOrEqualTo(root.get(entity.getSingularAttribute(field, clazz)), (C) val));
ret = true;
} else if (pd.getReadMethod().isAnnotationPresent(GreaterThan.class)) {
String field = pd.getReadMethod().getAnnotation(GreaterThan.class).field();
predicates.add(cb.lessThan(root.get(entity.getSingularAttribute(field, clazz)), (C) val));
ret = true;
} else if (pd.getReadMethod().isAnnotationPresent(LessThan.class)) {
String field = pd.getReadMethod().getAnnotation(LessThan.class).field();
predicates.add(cb.greaterThan(root.get(entity.getSingularAttribute(field, clazz)), (C) val));
ret = true;
}
return ret;
}
}
}