JPA Generic Repo

This is a generic repo for JPA entities that have an auto generated "id" column

Usage

Create JPA entities that extend IdEntity and have an auto generated id

@Entity
public class Person extends IdEntity
{
    @Id @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;
    private String name;

Create repo beans that extend Repo class

@Named("personRepo") @ApplicationScoped
public class PersonRepo extends Repo<Person> implements Serializable
{
    public PersonRepo()
    {
        super(Person.class);
    }

    public ArrayList<Person> search(String needle) throws Exception
    {
        ArrayList<Person> list = new ArrayList<>();
    
        if(needle == null  || needle.isEmpty())
            return list;

        try
        {
            String sql = "SELECT x FROM Person x WHERE x.name = :needle";

            Query q = this.getEntityManager().createQuery(sql);

            list.addAll(q.getResultList());
        }
        catch(NoResultException nre)
        {
            return list;
        }
        catch(Exception e)
        {
            throw e;
        }

        return list;
    }

This would be an example of usage

@Inject private PersonRepo personRepo;

...

Person person = new Person();

//person has no id

person.setName("John");

person = personRepo.create(person);

//person should now have an id

person.setName("John Doe");

personRepo.update(person);


Files

IdEntity.java

import java.io.Serializable;

public abstract class IdEntity implements Serializable
{
    public abstract Integer getId();
}

Repo.java


import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import javax.sql.DataSource;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Repo<T extends IdEntity> implements Serializable
{
    @Resource(lookup="java:jboss/UserTransaction")
    private UserTransaction tx;

    @PersistenceContext(unitName = "UNIT_NAME_HERE")
    private EntityManager em;

    @Resource(lookup="java:jboss/datasources/DATASOURCE_NAME_HERE")
    private DataSource dataSource;

    private Class<T> type;

    public Repo(Class<T> type)
    {
        this.type = type;
    }

    /**
    * GET ENTITY MANAGER
    */

    public EntityManager getEntityManager()
    {
        return em;
    }

    /**
    * TRANSACTIONS
    */

    private void beginTransaction() throws Exception
    {
        try {
            tx.begin();
        }
        catch (Exception e) {
            rollBackTransaction();
            throw e;
        }
    }

    private void commitTransaction() throws Exception
    {
        try {
            tx.commit();
        } catch (Exception e) {
            rollBackTransaction();
            throw e;
        }
    }

    private void rollBackTransaction() throws SystemException
    {
        try {
            if(tx != null)
            tx.rollback();
        } catch (Exception e) {
            throw e;
        }
    }

    /**
    * CRUDL
    */

    public T create(T obj) throws Exception
    {
        beginTransaction();
        em.persist(obj);
        em.flush();
        commitTransaction();

        if(obj.getId() == null)
        {
            throw new Exception("CHECK FOR @GeneratedValue(strategy=GenerationType.IDENTITY) ON " + obj.getClass().getSimpleName() + "ENTITY");
        }
        else
        {
            return obj;
        }
    }

    public T read(Integer id)
    {
        T obj = null;

        obj =  em.find(type, id);

        return obj;
    }

    public Boolean update(T obj) throws Exception
    {
        beginTransaction();
        em.merge(obj);
        commitTransaction();

        return true;
    }

    public Boolean delete(T obj) throws Exception
    {
        T x =  em.find(type, obj.getId());

        beginTransaction();
        em.remove(em.merge(x));
        commitTransaction();

        return true;
    }

    public List<T> list()
    {
        return filter(0,0,"id", "A", null);
    }

    /**
    * FILTER
    */
    
    public List<T> filter(int start, int limit, String sortField, String sortOrder, Map<String, String> filters)
    {
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<T> query = builder.createQuery(type);
        Root<T> root = query.from(type);
        
        query.select(root);

        Path<T> path = (sortField == null || sortField.isEmpty()) ? root.get("id") : root.get(sortField);

        if(sortOrder != null && sortOrder.toLowerCase().startsWith("d"))
            query.orderBy(builder.desc(path));
        else
            query.orderBy(builder.asc(path));

        /**
        * FILTERING
        */

        if(filters != null)
        {
            Predicate filterCondition = builder.conjunction();

            for(Map.Entry<String, String> filter : filters.entrySet())
            {
                if(! filter.getValue().equals(""))
                {
                    String field = filter.getKey();
                    String value = filter.getValue();

                    Path<String> pathFilter = root.get(field);

                    if(pathFilter != null)
                    {
                        if(value.equals("true") || value.equals("false"))
                        {
                            filterCondition = builder.and(filterCondition, builder.equal(pathFilter, (value.equals("true"))));
                        }
                        else
                        filterCondition = builder.and(filterCondition, builder.like(pathFilter, "" + value + ""));
                    }
                }
            }

            query.where(filterCondition);
        }
        
        /**
        * PAGINATION
        */

        TypedQuery<T> tq = em.createQuery(query);

        if(limit > 0)
            tq.setMaxResults(limit);

        if(start > 0)
            tq.setFirstResult(start);

        List<T> list = new ArrayList<>();
            
        list.addAll(tq.getResultList());

        return list;
    }

    /**
    * NATIVE QUERY
    */

    public List nativeQuery(String sql)
    {
        ArrayList list = new ArrayList<>();

        Query q = em.createNativeQuery(sql, type);

        list.addAll(q.getResultList());

        return list;
    }

}