com.bld.commons.service.BaseJpaService Maven / Gradle / Ivy
The newest version!
/**
* @author Francesco Baldi
* @mail [email protected]
* @class bld.commons.persistence.base.service.BaseJpaService.java
*/
package com.bld.commons.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.text.StringSubstitutor;
import org.springframework.beans.factory.annotation.Autowired;
import com.bld.commons.exception.JpaServiceException;
import com.bld.commons.exception.OrderByException;
import com.bld.commons.reflection.model.BuildJpqlQueryParameter;
import com.bld.commons.reflection.model.BuildNativeQueryParameter;
import com.bld.commons.reflection.model.ConditionsZoneModel;
import com.bld.commons.reflection.model.OrderBy;
import com.bld.commons.reflection.model.QueryParameter;
import com.bld.commons.reflection.model.TupleParameter;
import com.bld.commons.reflection.utils.ReflectionCommons;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.Tuple;
import jakarta.persistence.TupleElement;
import jakarta.persistence.TypedQuery;
/**
* The Class BaseJpaService.
*
* @param the generic type
* @param the generic type
*/
@SuppressWarnings("unchecked")
public abstract class BaseJpaService {
/** The Constant JOIN_ZONE. */
public final static String JOIN_ZONE = "joinZone";
/** The Constant END_LINE. */
private static final String END_LINE = "\n";
/** The classe. */
private Class classEntity = null;
private Class classId = null;
/** The Constant FETCH. */
private static final String fetch = "(?i)fetch";
/** The Constant logger. */
private static final Log logger = LogFactory.getLog(BaseJpaService.class);
/** The Constant ORDER_BY. */
private static final String ORDER_BY = " order by ";
/** The Constant ONE_TO_MANY. */
public static final CharSequence ONE_TO_MANY = "";
/** The Constant KEY_PROPERTY. */
public final static String KEY_PROPERTY = "";
/** The Constant WHERE_1_1. */
public static final String WHERE_CONDITION = "\nWHERE ";
/** The map one to many. */
private Map> mapOneToMany;
/**
* Gets the entity manager.
*
* @return the entity manager
*/
protected abstract EntityManager getEntityManager();
/**
* Sets the map one to many.
*
* @param mapOneToMany the map one to many
*/
protected void setMapOneToMany(Map> mapOneToMany) {
this.mapOneToMany = mapOneToMany;
}
/**
* Gets the map one to many.
*
* @return the map one to many
*/
protected Map> getMapOneToMany() {
return mapOneToMany;
}
/** The reflection commons. */
@Autowired
protected ReflectionCommons reflectionCommons;
/**
* Instantiates a new base jpa service.
*/
public BaseJpaService() {
super();
this.classEntity = ReflectionCommons.getGenericTypeClass(this);
this.classId = ReflectionCommons.getGenericTypeClass(this, 1);
}
/**
* Gets the clazz.
*
* @return the clazz
*/
protected Class getClassEntity() {
return classEntity;
}
/**
* Sets the query parameters.
*
* @param the generic type
* @param mapParameters the map parameters
* @param query the query
* @return the q
*/
private void setQueryParameters(Map mapParameters, Q query) {
for (Entry entry : mapParameters.entrySet()) {
Object value = entry.getValue();
logger.debug("----------------------------------------------------------");
logger.debug("Key: " + entry.getKey());
logger.debug("Value: " + value);
if (value != null)
logger.debug("Class: " + value.getClass().getName());
query.setParameter(entry.getKey(), entry.getValue());
}
}
/**
* Gets the where condition.
*
* @param mapParameters the map parameters
* @param where the select
* @param mapConditions the map conditions
* @return the where condition
*/
private void getWhereCondition(Map mapParameters, StringBuilder where, Map mapConditions) {
for (String key : mapParameters.keySet())
this.setCondition(where, mapConditions, key);
}
private void getWhereTupleCondition(Map mapParameters, StringBuilder where, Map mapConditions) {
for (Entry entry : mapParameters.entrySet()) {
String condition=this.buildTupleCondition(entry.getKey(), mapConditions, entry.getValue());
where.append(condition);
}
}
private void setCondition(StringBuilder where, Map mapConditions, String key) {
String condition = mapConditions.get(key);
if (StringUtils.isBlank(condition))
throw new JpaServiceException("The \"" + key + "\" parameter is not mappend in condition");
where.append(condition);
}
/**
* Gets the where condition.
*
* @param nullables the nullables
* @param where the select
* @param mapConditions the map conditions
* @return the where condition
*/
private void getWhereCondition(Set nullables, StringBuilder where, Map mapConditions) {
if (nullables != null) {
for (String key : nullables) {
this.setCondition(where, mapConditions, key);
}
}
}
/**
* Delete by filter.
*
* @param buildQueryFilter the build query filter
*/
public void deleteByFilter(BuildJpqlQueryParameter buildQueryFilter) {
QueryParameter queryParameter = buildQueryFilter.getQueryParameter();
StringBuilder sql = buildQueryFilter.getSql();
buildWhere(buildQueryFilter, sql);
queryParameter.mergeParameters();
final String delete = sql.toString();
logger.debug("Query= " + delete);
Query query = this.getEntityManager().createQuery(delete);
setQueryParameters(queryParameter.getParameters(), query);
query.executeUpdate();
}
public List findIdByFilter(BuildJpqlQueryParameter buildQueryFilter) {
TypedQuery query = buildQuery(buildQueryFilter, this.classId, true);
return query.getResultList();
}
/**
* Find by filter.
*
* @param buildQueryFilter the build query filter
* @return the list
*/
public List findByFilter(BuildJpqlQueryParameter buildQueryFilter) {
TypedQuery query = buildQuery(buildQueryFilter, this.classEntity, false);
return query.getResultList();
}
/**
* Builds the query.
*
* @param buildQueryFilter the build query filter
* @return the typed query
*/
private TypedQuery buildQuery(BuildJpqlQueryParameter buildQueryFilter, Class clazz, boolean removeFetch) {
QueryParameter queryParameter = buildQueryFilter.getQueryParameter();
Map mapParameters = queryParameter.getParameters();
StringBuilder sql = addRelationshipsOneToMany(mapParameters, buildQueryFilter.getSql(), queryParameter.getNullables());
buildWhere(buildQueryFilter, sql);
addOrderBy(queryParameter.getListOrderBy(), sql, buildQueryFilter.getMapOrders());
queryParameter.mergeParameters();
String select = sql.toString();
if (removeFetch)
select = select.replaceAll(fetch, "");
logger.debug("\nQuery: \n" + select);
TypedQuery query = this.getEntityManager().createQuery(select, clazz);
setQueryParameters(mapParameters, query);
if (queryParameter.getPageable() != null) {
query.setFirstResult(queryParameter.getPageable().getPageNumber() * queryParameter.getPageable().getPageSize());
query.setMaxResults(queryParameter.getPageable().getPageSize());
}
return query;
}
// /**
// * Gets the class filter parameter.
// *
// * @param queryFilter the query filter
// * @return the class filter parameter
// */
// private Class extends BaseParameter> getClassFilterParameter(QueryParameter queryFilter) {
// Class extends BaseParameter> classFilterParameter = null;
// if (queryFilter.getBaseParameter() != null)
// classFilterParameter = (Class extends BaseParameter>) queryFilter.getBaseParameter().getClass();
// return classFilterParameter;
// }
/**
* Builds the sql.
*
* @param buildQueryFilter the build query filter
* @param sql the sql
* @return the string
*/
private void buildWhere(BuildJpqlQueryParameter buildQueryFilter, StringBuilder sql) {
QueryParameter queryFilter = buildQueryFilter.getQueryParameter();
StringBuilder where = new StringBuilder("");
getWhereCondition(queryFilter.getNullables(), where, buildQueryFilter.getMapConditions());
getWhereCondition(queryFilter.getParameters(), where, buildQueryFilter.getMapConditions());
getWhereTupleCondition(queryFilter.getTupleParamenters(), where, buildQueryFilter.getMapConditions());
if (where.length() > 0)
sql.append("where\n").append(where.substring(4));
}
/**
* Adds the order by.
*
* @param listOrderBy the list order by
* @param sql the sql
* @param mapOrders the map orders
*/
private void addOrderBy(List listOrderBy, StringBuilder sql, Map mapOrders) {
if (!sql.toString().toLowerCase().contains(ORDER_BY.trim()) && CollectionUtils.isNotEmpty(listOrderBy)) {
StringBuilder writeOrderBy = new StringBuilder("");
int substring = 0;
if (CollectionUtils.isNotEmpty(listOrderBy)) {
for (OrderBy orderBy : listOrderBy) {
if (!mapOrders.containsKey(orderBy.getSortKey()))
throw new OrderByException("The \"" + orderBy.getSortKey() + "\" sort key is not found");
writeOrderBy.append(",").append(mapOrders.get(orderBy.getSortKey())).append(" ").append(orderBy.getOrderType().name());
}
substring = 1;
}
sql.append(END_LINE).append(ORDER_BY).append(writeOrderBy.substring(substring));
}
}
/**
* Adds the relationships one to many.
*
* @param mapParameters the map parameters
* @param select the select
* @param nullables the nullables
* @return the manage one to many
*/
private StringBuilder addRelationshipsOneToMany(Map mapParameters, StringBuilder select, Set nullables) {
StringBuilder innerJoin = new StringBuilder("");
if (nullables == null)
nullables = new HashSet<>();
Set listJoin = new HashSet<>();
for (String key : this.mapOneToMany.keySet()) {
if (mapParameters.containsKey(key) || nullables.contains(key)) {
Set joins = mapOneToMany.get(key);
for (String join : joins) {
join = ReflectionCommons.removeExtraSpace(join);
if (!listJoin.contains(join)) {
listJoin.add(join);
innerJoin.append(END_LINE).append(join);
}
}
}
}
select.append(innerJoin).append(END_LINE);
return select;
}
/**
* Count by filter.
*
* @param buildQueryFilter the build query filter
* @return the long
*/
public Long countByFilter(BuildJpqlQueryParameter buildQueryFilter) {
QueryParameter queryParameter = buildQueryFilter.getQueryParameter();
StringBuilder sql = addRelationshipsOneToMany(queryParameter.getParameters(), buildQueryFilter.getSql(), queryParameter.getNullables());
buildWhere(buildQueryFilter, sql);
queryParameter.mergeParameters();
final String count = sql.toString().replaceAll(fetch, "");
logger.debug("\nQuery: \n" + count);
Query query = this.getEntityManager().createQuery(count, Long.class);
setQueryParameters(queryParameter.getParameters(), query);
return (Long) query.getSingleResult();
}
/**
* Find single result by filter.
*
* @param buildQueryFilter the build query filter
* @return the t
*/
public T findSingleResultByFilter(BuildJpqlQueryParameter buildQueryFilter) {
TypedQuery query = buildQuery(buildQueryFilter, this.classEntity, false);
T t = null;
try {
t = query.getSingleResult();
} catch (Exception e) {
logger.warn("Record not found");
}
return t;
}
/**
* Find by id.
*
* @param buildQueryFilter the build query filter
* @return the t
*/
public T findById(BuildJpqlQueryParameter buildQueryFilter) {
QueryParameter queryFilter = buildQueryFilter.getQueryParameter();
queryFilter.getParameters().put(QueryParameter.ID, queryFilter.getId());
return findSingleResultByFilter(buildQueryFilter);
}
public List findByFilter(BuildNativeQueryParameter buildQueryFilter) {
StringBuilder sql = buildNativeQuery(buildQueryFilter);
addOrderBy(buildQueryFilter.getQueryParameter().getListOrderBy(), sql, buildQueryFilter.getMapOrders());
final String select = sql.toString();
logger.debug(select);
Query query = this.getEntityManager().createNativeQuery(select, Tuple.class);
setNativeQueryParameters(buildQueryFilter.getQueryParameter().getMapConditionsZone(), query);
if (buildQueryFilter.getQueryParameter().getPageable() != null) {
query.setFirstResult(buildQueryFilter.getQueryParameter().getPageable().getPageNumber() * buildQueryFilter.getQueryParameter().getPageable().getPageSize());
query.setMaxResults(buildQueryFilter.getQueryParameter().getPageable().getPageSize());
}
List results = query.getResultList();
List listK = new ArrayList<>();
for (Tuple row : results) {
List> elements = row.getElements();
Map mapRow = new HashMap<>();
for (TupleElement> element : elements) {
Object value = row.get(element.getAlias());
if (value != null)
mapRow.put(element.getAlias(), value);
}
K k = this.reflectionCommons.reflection(buildQueryFilter.getQueryParameter().getResultClass(), mapRow);
listK.add(k);
}
return listK;
}
/**
* Sets the native query parameters.
*
* @param the generic type
* @param mapZone the map zone
* @param query the query
*/
private void setNativeQueryParameters(Map mapZone, Q query) {
for (ConditionsZoneModel zone : mapZone.values()) {
for (Entry entry : zone.getParameters().entrySet()) {
logger.debug("Parameter: " + entry.getKey() + "= " + entry.getValue());
logger.debug("Class: " + (entry.getValue() != null ? entry.getValue().getClass().getName() : " null"));
query.setParameter(entry.getKey(), entry.getValue());
}
}
}
/**
* Native query count by filter.
*
* @param the key type
* @param buildQueryFilter the build query filter
* @return the long
*/
public Long countByFilter(BuildNativeQueryParameter buildQueryFilter) {
StringBuilder sql = buildNativeQuery(buildQueryFilter);
final String count = sql.toString();
logger.debug(count);
Query query = this.getEntityManager().createNativeQuery(count);
setNativeQueryParameters(buildQueryFilter.getQueryParameter().getMapConditionsZone(), query);
Number size = (Number) query.getSingleResult();
return size.longValue();
}
/**
* Builds the native query.
*
* @param the key type
* @param buildQueryFilter the build query filter
* @return the string
*/
private StringBuilder buildNativeQuery(BuildNativeQueryParameter buildQueryFilter) {
StringBuilder sql = buildQueryFilter.getSql();
Set zones = ReflectionCommons.extractVariables(sql.toString());
Map map = new HashMap<>(buildQueryFilter.getQueryParameter().getMapConditionsZone());
map.remove(JOIN_ZONE);
Map mapConditions = buildQueryFilter.getQueryParameter().getEmptyZones();
for (String key : map.keySet()) {
ConditionsZoneModel conditionsZoneModel = map.get(key);
Map conditions = buildQueryFilter.getMapConditions().get(key);
if (!mapConditions.containsKey(key))
mapConditions.put(key, new StringBuilder(conditionsZoneModel.getWhere()));
for (String parameter : conditionsZoneModel.getParameters().keySet())
mapConditions.get(key).append(conditions.get(parameter)).append(END_LINE);
for (String nullable : conditionsZoneModel.getNullables())
mapConditions.get(key).append(conditions.get(nullable)).append(END_LINE);
for (Entry entry: conditionsZoneModel.getTupleParamenters().entrySet()) {
String tupleKey=entry.getKey();
TupleParameter tupleParameter=entry.getValue();
String condition = buildTupleCondition(tupleKey, conditions, tupleParameter);
mapConditions.get(key).append(condition).append(END_LINE);
}
conditionsZoneModel.mergeParameters();
}
StringSubstitutor stringSubstitutor = new StringSubstitutor(mapConditions);
sql = new StringBuilder(stringSubstitutor.replace(sql));
for (String zone : zones) {
zone = "${" + zone + "}";
int startIndex = sql.indexOf(zone);
if (startIndex >= 0) {
int endIndex = startIndex + zone.length();
sql = sql.replace(startIndex, endIndex, "");
}
}
return sql;
}
private String buildTupleCondition(String tupleKey, Map conditions, TupleParameter tupleParameter) {
String condition=conditions.get(tupleKey);
if (StringUtils.isBlank(condition))
throw new JpaServiceException("The \"" + tupleKey + "\" parameter is not mappend in condition");
String refactorCondition="";
for(int i=0;i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy