com.alon.spring.crud.domain.repository.NestedRepository Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of crud-api-base Show documentation
Show all versions of crud-api-base Show documentation
Fornece implementação básica e expansível para criação API's CRUD com Spring Boot e Spring Data JPA.
package com.alon.spring.crud.domain.repository;
import com.alon.spring.crud.domain.model.BaseEntity;
import com.alon.spring.crud.domain.service.SearchCriteria;
import com.cosium.spring.data.jpa.entity.graph.repository.support.EntityGraphSimpleJpaRepository;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.query.QueryUtils;
import javax.persistence.*;
import javax.persistence.criteria.*;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.springframework.data.domain.Sort.unsorted;
public class NestedRepository<
MASTER_ENTITY_ID_TYPE extends Serializable,
NESTED_ENTITY_ID_TYPE extends Serializable,
NESTED_ENTITY_TYPE extends BaseEntity>
extends EntityGraphSimpleJpaRepository {
private static final String EXPAND_HINT = "javax.persistence.loadgraph";
protected final EntityManager entityManager;
protected final CriteriaBuilder builder;
protected final String masterFieldName;
protected final String masterIdFieldName;
protected final String nestedIdFieldName;
protected final Class nestedEntityType = extractNestedEntityType();
protected final Class nestedEntityIdType = extractNestedEntityIdType();
/**
* Uses "id" as the field name for the master and nested id fields
*/
public NestedRepository(Class entityType, EntityManager entityManager, String masterFieldName) {
this(entityType, entityManager, masterFieldName, "id", "id");
}
public NestedRepository(Class entityType, EntityManager entityManager,
String masterFieldName, String masterIdFieldName, String nestedIdFieldName) {
super(entityType, entityManager);
this.entityManager = entityManager;
builder = entityManager.getCriteriaBuilder();
this.masterFieldName = masterFieldName;
this.masterIdFieldName = masterIdFieldName;
this.nestedIdFieldName = nestedIdFieldName;
}
public String getMasterFieldName() {
return masterFieldName;
}
public List search(
MASTER_ENTITY_ID_TYPE masterId, SearchCriteria searchCriteria) {
CriteriaQuery criteriaQuery = builder.createQuery(nestedEntityType);
Root from = criteriaQuery.from(nestedEntityType);
criteriaQuery.select(from);
Predicate predicate = builder.equal(from.get(masterFieldName).get(masterIdFieldName), masterId);
if (searchCriteria.getFilter() != null)
predicate = builder.and(predicate,
searchCriteria.getFilter().toPredicate(from, criteriaQuery, builder));
criteriaQuery.where(predicate);
if (searchCriteria.getPageable() != null) {
Sort sort = searchCriteria
.getPageable()
.getSortOr(unsorted());
List orders = QueryUtils.toOrders(sort, from, builder);
criteriaQuery.orderBy(orders);
}
TypedQuery typedQuery = entityManager.createQuery(criteriaQuery);
if (searchCriteria.getPageable() != null) {
typedQuery.setFirstResult((int) searchCriteria.getPageable().getOffset());
typedQuery.setMaxResults(searchCriteria.getPageable().getPageSize());
}
if (searchCriteria.getExpand() != null && !searchCriteria.getExpand().isEmpty()) {
List expand = new ArrayList<>();
expand.addAll(searchCriteria.getExpand());
typedQuery.setHint(EXPAND_HINT, resolveExpand(expand));
}
return typedQuery.getResultList();
}
public Optional findById(
MASTER_ENTITY_ID_TYPE masterId, NESTED_ENTITY_ID_TYPE nestedId) {
return findById(masterId, nestedId, null);
}
public Optional findById(
MASTER_ENTITY_ID_TYPE masterId, NESTED_ENTITY_ID_TYPE nestedId, List expand) {
CriteriaQuery criteriaQuery = builder.createQuery(nestedEntityType);
Root from = criteriaQuery.from(nestedEntityType);
criteriaQuery.select(from);
criteriaQuery.where(builder.and(
builder.equal(from.get(masterFieldName).get(masterIdFieldName), masterId),
builder.equal(from.get(nestedIdFieldName), nestedId)));
TypedQuery typedQuery = entityManager.createQuery(criteriaQuery);
if (expand != null && !expand.isEmpty())
typedQuery.setHint(EXPAND_HINT, resolveExpand(expand));
try {
return Optional.of(typedQuery.getSingleResult());
} catch (NoResultException ex) {
return Optional.empty();
}
}
public boolean existsById(MASTER_ENTITY_ID_TYPE masterId, NESTED_ENTITY_ID_TYPE nestedId) {
CriteriaQuery criteriaQuery = builder.createQuery(nestedEntityIdType);
Root from = criteriaQuery.from(nestedEntityType);
criteriaQuery.multiselect(from.get(nestedIdFieldName));
criteriaQuery.where(builder.and(
builder.equal(from.get(masterFieldName).get(masterIdFieldName), masterId),
builder.equal(from.get(nestedIdFieldName), nestedId)));
TypedQuery typedQuery = entityManager.createQuery(criteriaQuery);
try {
typedQuery.getSingleResult();
return true;
} catch (NoResultException ex) {
return false;
}
}
private EntityGraph resolveExpand(List expand) {
EntityGraph graph = entityManager.createEntityGraph(nestedEntityType);
expand.stream()
.filter(property -> !property.contains("."))
.forEach(property -> graph.addAttributeNodes(property));
expand.stream()
.filter(property -> property.contains("."))
.map(property -> property.split("\\."))
.map(Stream::of)
.map(stream -> stream.collect(Collectors.toList()))
.forEach(expandComposition -> resolveCompoundExpand(graph, expandComposition));
return graph;
}
private void resolveCompoundExpand(EntityGraph graph, List expandComposition) {
Subgraph subgraph = graph.addSubgraph(expandComposition.remove(0));
resolveExpandSubProperty(subgraph, expandComposition);
}
private void resolveExpandSubProperty(Subgraph parentGraph, List expandComposition) {
if (expandComposition.size() > 1) {
Subgraph subgraph = parentGraph.addSubgraph(expandComposition.remove(0));
resolveExpandSubProperty(subgraph, expandComposition);
} else {
parentGraph.addAttributeNodes(expandComposition.get(0));
}
}
private final Class extractNestedEntityIdType() {
ParameterizedType classType = (ParameterizedType) getClass().getGenericSuperclass();
Type type = classType.getActualTypeArguments()[1];
if (type instanceof Class)
return (Class) type;
return null;
}
private final > Class extractNestedEntityType() {
ParameterizedType classType = (ParameterizedType) getClass().getGenericSuperclass();
Type type = classType.getActualTypeArguments()[2];
if (type instanceof Class)
return (Class) type;
return null;
}
}