简体   繁体   中英

Using generics and jpa EntityManager methods

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?

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.

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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM