package io.github.gasparbarancelli; import org.hibernate.Session; import org.hibernate.query.NativeQuery; import org.hibernate.transform.Transformers; import org.hibernate.type.LongType; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.data.domain.PageImpl; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Supplier; public class NativeQueryMethodInterceptorImpl implements NativeQueryMethodInterceptor { @Override public Object executeQuery(NativeQueryInfo info) { if (!info.isUseJdbcTemplate()) { return executeWithEntityManager(info); } return executeWithJdbcTemplate(info); } private Object executeWithJdbcTemplate(NativeQueryInfo info) { NamedParameterJdbcTemplate jdbcTemplate = ApplicationContextProvider.getApplicationContext().getBean(NamedParameterJdbcTemplate.class); Map<String, Object> parametroList = new HashMap<>(); for (NativeQueryParameter parametro : info.getParameterList()) { if (parametro.getValue() != null && info.getSql().contains(":" + parametro.getName())) { parametroList.put(parametro.getName(), parametro.getValue()); } } BeanPropertyRowMapper<?> beanPropertyRowMapper = new BeanPropertyRowMapper<>(info.getAliasToBean()); if (info.getReturnType().getSimpleName().equals(Void.TYPE.getName())) { jdbcTemplate.update(info.getSql(), parametroList); return null; } if (info.isSingleResult()) { if (info.isJavaObject()) { return jdbcTemplate.queryForObject(info.getSql(), parametroList, info.getAliasToBean()); } if (info.returnTypeIsOptional()) { return getOptionalReturn(() -> jdbcTemplate.queryForObject(info.getSql(), parametroList, beanPropertyRowMapper)); } return jdbcTemplate.queryForObject(info.getSql(), parametroList, beanPropertyRowMapper); } if (info.isJavaObject()) { return jdbcTemplate.queryForList(info.getSql(), parametroList, info.getAliasToBean()); } return jdbcTemplate.query(info.getSql(), parametroList, beanPropertyRowMapper); } private Object executeWithEntityManager(NativeQueryInfo info) { EntityManager entityManager = ApplicationContextProvider.getApplicationContext().getBean(EntityManager.class); Session session = entityManager.unwrap(Session.class); NativeQuery<?> query; if (info.isEntity()) { query = session.createNativeQuery(info.getSql(), info.getAliasToBean()); } else { query = session.createNativeQuery(info.getSql()); } addParameterJpa(query, info); if (info.hasPagination()) { query.setFirstResult(info.getFirstResult()); query.setMaxResults(info.getMaxResult()); } query.getQueryString(); if (!info.isJavaObject() && !info.isEntity()) { query.setResultTransformer(Transformers.aliasToBean(info.getAliasToBean())); } if (info.getReturnType().getSimpleName().equals(Void.TYPE.getName())) { query.executeUpdate(); return null; } if (info.returnTypeIsOptional()) { return getOptionalReturn(query::getSingleResult); } if (info.isSingleResult()) { return query.getSingleResult(); } List<?> resultList = query.list(); if (info.isPagination()) { return new PageImpl(resultList, info.getPageable(), getTotalRecords(info, session)); } return resultList; } private Object getOptionalReturn(Supplier<Object> result) { try { return Optional.ofNullable(result.get()); } catch (NoResultException | EmptyResultDataAccessException e) { return Optional.empty(); } } private Long getTotalRecords(NativeQueryInfo info, Session session) { NativeQuery<?> query = session.createNativeQuery(info.getSqlTotalRecord()); query.unwrap(NativeQuery.class).addScalar("totalRecords", LongType.INSTANCE); addParameterJpa(query, info); return (Long) query.getSingleResult(); } private void addParameterJpa(NativeQuery<?> query, NativeQueryInfo info) { info.getParameterList().forEach(p -> { if (p.getValue() != null && info.getSql().contains(":" + p.getName())) { query.setParameter(p.getName(), p.getValue()); } }); } }