Reputation: 23
Can I use generics and JPA together?
I am trying to persist objects of four classes to my db. Here's my PersistService class:
public class PersistService<T> {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("fileUploadProject");
public static EntityManager getEntityManager() {
return emf.createEntityManager();
}
// Write Client to Database
public static <T> void persist(T obj) {
EntityManager em = getEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
em.persist(obj);
et.commit();
em.close();
}
}
But then I get into a problem with removing the object. I have the following method in the PersistService class in addition to the above:
// Remove an object from the Database if they exist
public static <T> void remove(Long id) {
EntityManager em = getEntityManager();
EntityTransaction et = em.getTransaction();
<T> obj = em.find(<T>.class, id);
}
The final line is giving me a compile time error. I've tried <T>.class
T
Class<T>
and T.class
as well, but it still gives me a compile time error. Just learning about Type Erasure, is this error because of that? How do I resolve this issue?
Upvotes: 2
Views: 3545
Reputation: 2968
I may have the answer you are searching for, well, to have generic type during compile time isn't something that easy. Since java don't allow you to do that directly.
I have a hack myself, can you try something like this ?
Be sure to handle your exceptions.
static <T> Class getGenericType(T t){
return getType(t);
}
static Class<?> getType(Object o){
return o.getClass();
}
Upvotes: 0
Reputation: 6507
You have started using a good pattern. The next step is to create a subclass of PersistService for each of your entity types. I will also mention that in the long run you probably want to have a common base class or interface for each of your entities. For example, I will call it Entity
. This base class (if it is a class rather than interface) can be abstract and can define common methods for all of your entities.
public interface Entity {
long getId();
}
You can use the methods defined by Entity
in your implementation of PersistService
(which you may find handy as you add more generic entity-related business logic in this base service or elsewhere in your code).
Your entity A
looks like
public class A extends Entity {
}
Your PersistService
becomes
public abstract class PersistService<T extends Entity> {
// Your common methods (persist, remove, etc.).
public abstract Class<T> getEntityClass();
}
Your entity-specific services look like this
public class APersistService extends PersistService<A> {
public Class<A> getEntityClass() {
return A.class;
}
}
You then use the getEntityClass()
method when you implement PersistService.remove()
.
While the entity-specific subclasses solve the problem of getting the specific class object in the face of type erasure, you will find that you end up wanting the subclass to support entity-specific queries as well.
Upvotes: 3