How to implement generic business logic methods from JPA database entity class? - java

I want suggestion regarding a scenario I've been thinking of doing if possible. Suppose I have some JPA database entity class like:
#Entity
public class Person {
#Column(name = "ID")
private Long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
public String getFirstName(){
return this.firstName;
}
public void setFirstName(String firstName){
this.firstName = firstName;
}
public String getLastName(){
return this.lastName;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
}
I am using EJB services. I can use separate business logic methods to make CRUD operation over these entities. Is it possible to use a generic template CRUD operations for these entity classes? Like if I want to create new person I will provide the Person entity class and fields to set as parameter and my generic method will create a new Person record and will do the same job for Read, Update and Delete operation as well.
Any respective example will be highly appreciated.
Thank You

Using EJB and JPA
You can consider an abstract class for the service layer:
public abstract class AbstractFacade<E extends Serializable,
PK extends Serializable> {
private final transient Class<E> entityClass;
public AbstractFacade(final Class<E> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(final E entity) {
final EntityManager entityManager = getEntityManager();
entityManager.persist(entity);
}
public final E find(final PK id) {
return getEntityManager().find(entityClass, id);
}
// Other common operations
}
And a particular service:
#Stateless
public class PersonFacade extends AbstractFacade<Person, Long> {
#PersistenceContext(unitName = "MyPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public PersonFacade() {
super(Person.class);
}
// Other methods of this service
}
Using Spring and Hibernate
You could have a abstract base class for common DAO methods.
public abstract class AbstractDAO<E extends Serializable,
PK extends Serializable> {
private final transient Class<E> entityClass;
public AbstractDAO(final Class<E> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public final E find(final PK id) {
return getEntityManager().find(entityClass, id);
}
// Another common methods
}
In every DAO implementation, you can put particular methods for that DAO.
#Repository
public final class PersonDAO extends AbstractDAO<Person, Long> {
#Autowired
private transient EntityManagerFactory emf;
public PersonDAO() {
super(Person.class);
}
#Override
protected EntityManager getEntityManager() {
return emf.createEntityManager();
}
// particular methods for this DAO
}
What about if the user not exists? Put this logic in the service layer.
#Service
public final class PersonService {
private static final Logger LOG = LoggerFactory.getLogger(PersonService.class);
#Autowired
private transient PersonDAO personDAO;
public Person findPerson(final Long id) {
return personDAO.find(id);
}
}

If you are using Spring then use Spring Data which will do all this for you.
http://docs.spring.io/spring-data/jpa/docs/1.4.2.RELEASE/reference/html/repositories.html#repositories.core-concepts

Related

Implementing a base dao, I get error Type of the parameter must be a class annotated with #Entity or a collection/array of it

I am struggeling with creating a base DAO in Java using Room in Android.
There are several posts out there but not one solves the error I get.
This is the error I get at compile time:
error: Type of the parameter must be a class annotated with #Entity or a collection/array of it.
This is my entity / model class:
#Entity (tableName = "user")
public class User {
#PrimaryKey
#ColumnInfo (name = "user_id")
private int userId;
#ColumnInfo (name = "lastname")
private String lastName;
#ColumnInfo (name = "firstname")
private String firstName;
public User(int userId, String lastName, String firstName) {
this.userId = userId;
this.lastName = lastName;
this.firstName = firstName;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
This is my base DAO:
#Dao
public abstract class BaseDao<T> {
#Insert
public abstract long insert(T object); // error here
#Insert
public abstract long[] insertAll(List<T> object); // error here
#Update
public abstract int update(T object); // error here
#Update
public abstract int updateAll(List<T> object); // error here
#Delete
public abstract int delete(T object); // error here
#Delete
public abstract int deleteAll(List<T> object); // error here
}
This is my User DAO:
#Dao
public abstract class UserDao extends BaseDao<User> {
#Query ("select * from user")
public abstract LiveData<List<User>> getAll();
#Query("delete from user")
public abstract int deleteAll();
}
I get six compilation errors of the same type. That ist the number of functions in my base DAO. Of course generic type T is not annotated with #Entity, but how to deal with that fact?
What I tried to solve this:
Read all posts about this topic carefully over days. Most posts use Kotlin, and I believe that it works for Kotlin, but I use Java.
Tried to implement the Base DAO as an interface or abstract class
Tried to annotate / not annotate the base DAO with #Dao (as mentioned in some posts)
Tried to create a Base Entity annotated with #Entity and have my model classes extend that like so:
#Entity
public class BaseEntity { ... } // Base entity annotated with #Entity
public class User extends BaseEntity { ... } // subclass the model class from BaseEntity
public abstract class BaseDao<T extends BaseEntity> { ...} // type parameterize BaseDao with base type BaseEntity
public abstract class UserDao extends BaseDao<User> { ...} // type T should now be an descendant of BaseEntity which is an #Entity
None of this worked for me!
Some of the posts tell, that it has worked for them this way, but not for me.
I hope someone can tell me what I'm doing wrong!
Finally I found the error!
Among my model classes I have one model, that is just a DTO for a joined query result.
public class SessionAndUser {
#Embedded
private Session session;
#Relation(parentColumn = "user_id", entityColumn = "user_id")
private User user;
}
The DAO implementation looks like this:
#Dao
public abstract class SessionAndUserDao { //extends BaseDao<SessionAndUser> { <-- this caused the error
#Transaction
#Query("select * from session")
public abstract LiveData<List<SessionandUser>> getAll();
}
Because of SessionAndUser is not in the database it must not be annotated with #Entity.
The error was, that I extended the DAO from my base DAO. So the solution for me was, to just create the dao without extending the base DAO (in fact it does not need the functionality of the base DAO).
After figuring out that, I could see that every kind of tested implementations (using interfaces or abstract classes, using Java or Kotlin) worked as expected.

Is it possible in Hibernate to override entity field name in a child entity?

I'm writing an app using Spring Boot, Hiberane and Spring Data.
I have two tables in the db: tableA and tableB.
They have some common fields but their id's,name's are different, also I've created a basic model for them to contain some common fields, right now it looks something like this:
// BaseModel
#MappedSuperclass
public abstract class BaseModel implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name="common_field_1")
private String commonField1;
#Column(name="common_field_2")
private String commonField2;
#Column(name="common_field_3")
private String commonField3;
}
// ExactModel 1
#Entity
#Table(name="table1" ,schema="schema")
public class ExactModel1 extends BaseModel {
#Id
#Basic(fetch=FetchType.EAGER)
#Column(name="exact_model_id_1", nullable=false)
private long exactModel1Id;
private String exactField1;
}
// ExactModel 2
#Entity
#Table(name="table2" ,schema="schema")
public class ExactModel2 extends BaseModel {
#Id
#Basic(fetch=FetchType.EAGER)
#Column(name="exact_model_id_2", nullable=false)
private long exactModel2Id;
private String exactField2;
}
And I have some generic logic which implements some general crud logic which works for classes which extend BaseModel:
public abstract class BaseServiceImpl<M extends BaseModel, R extends BaseRepository<M>> implements BaseService<M, Long> {
private final R repository;
public BaseServiceImpl(R repository) {
this.repository = repository;
}
#Override
public M save(M model) {
return repository.save(model);
}
#Override
public List<M> saveAll(List<M> models) {
return repository.saveAll(models);
}
#Override
public M findById(Long id) {
return repository.getOne(id);
}
#Override
public List<M> findAllById(List<Long> ids) {
return repository.findAllById(ids);
}
#Override
public List<M> findAll() {
return repository.findAll();
}
#Override
public M update(M model) {
return repository.save(model);
}
#Override
public List<M> updateAll(List<M> models) {
return repository.saveAll(models);
}
#Override
public void delete(M model) {
repository.delete(model);
}
#Override
public void delteById(Long id) {
repository.deleteById(id);
}
#Override
public void deleteInBatch(List<M> models) {
repository.deleteInBatch(models);
}
#Override
public Long countModels() {
return repository.count();
}
}
The thing is now I need to get somehow the id of the entity I work with in this generic logic, but there is no id field in BaseModel, so I can't just use baseModel.getId().
The question: is it possible to define a mock id field in BaseModel and override it in the child classes, so I can use this id in the generic methods but Hibernate fills the actual ids on the runtime for me?

How to reset the AutoGenerated Key in JPA in case of rollback?

I have a situation where i need to reset the auto-Increment key to the previous value in case of roll back. I have a series of create statement in my controller class. If any exception occurs I am able to roll back all the create statements. But the the auto-Increment generated doesn't reset for a particular successfully entity. Kindly help
The following is my contoller class.
#EJB
private jpa.session.ClassMasterFacade ejbFacadeCM;
#EJB
private jpa.session.StudentMasterFacade ejbFacadeSM;
#EJB
private jpa.session.ParentsMasterFacade ejbFacadePM;
#EJB
private jpa.session.AddressMasterFacade ejbFacadeAM;
#Resource
UserTransaction tran;
public String confirmData() {
try {
tran.begin();
ejbFacadeSM;.create(selectedSM);
ejbFacadeCM;.create(selectedCM)
ejbFacadeAM;.create(selectedAM);
ejbFacadePM;.create(selectedPM);
} catch (Exception e) {
tran.rollback();
JsfUtil.addErrorMessage(e, ResourceBundle.getBundle ("/resources/Bundle").getString("PersistenceErrorOccured"));
return null;
}
}
Example Facade Class
#Stateless
public class ClassMasterFacade extends AbstractFacade<ClassMaster> {
#PersistenceContext(unitName = "sdjv_smsPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public ClassMasterFacade() {
super(ClassMaster.class);
}
}
All other facade classes are similar to the above class. The abstract class is:
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
}
The autogenerated key in each enityclass is similar to
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "class_group_id")
private Integer classGroupId;

Generic Hibernate Dao with Interface model object

I meet some problems with genericDao and model Interface.
I implemented the following GenericHibernateDao :
#Repository
public abstract class GenericHibernateDao<T, PK extends Serializable> implements IGenericDao<T, PK> {
#Autowired
private SessionFactory sessionFactory;
private Class<T> type;
#SuppressWarnings({ "unchecked", "rawtypes" })
public GenericHibernateDao() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class) pt.getActualTypeArguments()[0];
}
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
#Transactional
public T add(T obj){
getSession().persist(obj);
return obj;
}
#Transactional
#SuppressWarnings("unchecked")
public T getById(PK id){
T result = (T) getSession().load(type, id);
return result;
}
#Transactional
#SuppressWarnings("unchecked")
public List<T> list(){
Criteria crit = getSession().createCriteria(type);
return (List<T>) crit.list();
}
...
This works perfectly fine for "normal" objects.
I'm trying to use Interface as type T (ex: IBattery):
public class BatteryDao extends GenericHibernateDao<IBattery, Integer> implements IBatteryDao {
}
-
public interface IBattery {
public int getId();
public double getLevel();
public void setLevel(double _level);
}
-
#Entity
public class SimulationBattery implements IBattery {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(unique = true, nullable = false)
private int id;
#Column(unique = false, nullable = false)
private double level;
#Override
public int getId() {
return id;
}
#Override
public double getLevel() {
return level;
}
#Override
public void setLevel(double _level) {
level = _level;
}
I instanciate IBattery through Spring applicationContext file to load a SimulationBattery implementation.
It works for persist, list (with criteria) but fail with "getById" cause of load, sending :
org.hibernate.MappingException: Unknown entity: ***.***.****.IBattery
That's right cause only implementation (SimulationBattery) are mapped in hibernate.cfg.xml, but I don't understand why I can add, list, but not load...
Someone has explanation ?
Thank you.
Fabien.
(I'm using Hibernate, Spring and Java8)
When you persist an entity, you pass a concrete entity instance to Hibernate. So Hibernate receives an instance of SimulationBattery, for example, and thus knows the type of the entity you're persisting: SimulationBattery.
When you list, you rely on the polymorphic feature of Hibernate: you ask Hibernate to return all the entity instances of IBattery. Hibernate knows all the concrete entity classes that implement this interface (SimulationBattery and ProductionBattery, for example). So it loads them all from the database, and returns them.
But when you ask for one specific entity by ID, all Hibernate knows is that the entity is one of the entities that implement IBattery, and that its ID is the one you pass (42 for example). That is not sufficient. You might want the SimulationBattery 42, or the ProductionBattery 42, and Hibernate doesn't know. Hence the failure.

Why GET (JAX-RS) doesn't return inherited entity specific information?

I am running a RESTful web service on Glassfish 3.1.2 server. I use Jersey as JAX-RS implementation, Jackson as it's JSON provider, and (JPA) EclipseLink 2.5 as persistence provider for MySQL.
I'll introduce some context and then ask my question.
Let's assume we have the following hierarchy: Item entity and CraftableItem entity that inherits it (see code samples below). They both do have corresponding EAO and Resource classes: ItemEAO, CraftableItemEAO + ItemResource, CraftableItemResource (see code samples below).
Let's have two records in items table:
id | name
1 | "craftable"
2 | "non craftable"
and one corresponding record for "craftable" in crafting_items_joined:
id | crafting_time
1 | 120000
I want to get as more specific information about each entity from GET /item request as possible. I want it to return [{"id":1,"name":"craftable", "crafting_time":120000}, {"id":2,"name":"non craftable"}]. At the momment, GET /item/1 returns {"id":1,"name":"craftable", "crafting_time":120000} and GET /item/2 returns just {"id":2,"name":"non craftable"} which is the behavior i want, but for GET /item. Getting all information about entity present.
Code samples (setters are omitted for sanity's sake).
#MappedSuperclass
public abstract class BaseEntity {
protected Long id;
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "items")
public class Item extends BaseEntity implements Serializable {
private String name;
#Column(name = "name", nullable = false, unique = true)
public String getName() {
return name;
}
}
#Entity
#DiscriminatorValue("craftable")
#Table(name = "craftable_items_joined")
public class CraftableItem extends Item {
protected long craftingTime;
#Column(name = "crafting_time", nullable = false)
public long getCraftingTime() {
return craftingTime;
}
}
EAO then:
public abstract class AbstractEAO<T> {
private Class<T> entityClass;
public AbstractEAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
public Class<T> getEntityClass() {
return entityClass;
}
protected abstract EntityManager getEntityManager();
// create, edit, remove
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
}
#Stateless
#LocalBean
public class ItemEAO extends AbstractEAO<Item> {
#PersistenceContext(unitName = "primary")
private EntityManager entityManager;
public ItemEAO() {
super(Item.class);
}
#Override
protected EntityManager getEntityManager() {
return entityManager;
}
}
#Stateless
#LocalBean
public class CraftableItemEAO extends AbstractEAO<CraftableItem> {
#PersistenceContext(unitName = "primary")
private EntityManager entityManager;
public CraftableItemEAO() {
super(CraftableItem.class);
}
#Override
protected EntityManager getEntityManager() {
return entityManager;
}
}
Resource finally:
public abstract class AbstractResource<T extends BaseEntity> {
protected abstract AbstractEAO<T> getEAO();
#GET
public List<T> findAll() {
return getEAO().findAll();
}
#GET
#Path("{id}")
public T find(#PathParam("id") Long id) {
return getEAO().find(id);
}
// create, edit, remove
}
#Stateless
#Path("item")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class ItemResource extends AbstractResource<Item> {
#EJB private ItemEAO itemEAO;
#Override
protected AbstractEAO<Item> getEAO() {
return itemEAO;
}
}
#Stateless
#Path("item/craftable")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class CraftableItemResource extends AbstractResource<CraftableItem> {
#EJB private CraftableItemEAO craftableItemEAO;
#Override
protected AbstractEAO<CraftableItem> getEAO() {
return craftableItemEAO;
}
}

Categories

Resources