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();
}
Related
i have a few DAOs in my app which access a database for CRUD operations. Lets say there News, weather and , sports DAO. So im confused on how many Repositories i would need. should i just use one repository say DataRepository and let me hold my database and all dao's. and encapsulate methods for the CRUD operations in it ? or should each DAO have its own repository ?
I mean a repository should return only data objects that the calling layer understands. so its like a encapsulation over the DAOs but im not sure if i should create one per DAO or just have one repo per app, etc.
If you read this article we begin to understand that the pattern is over engineered or over abstracted. Its turned into hiding detail vs minimizing query statements.
But it seems There should be a Repo per DAO as the interface itself looks like this:
interface Repository<T> {
void add(T item);
void remove(Specification specification);
List<T> query(Specification specification);
}
where T can be the type/table of data DAO accesses. Just need clarification now. Can you imagine i have 30 different types, so then i need 30 different Repo implementations. this is ridiculous. It seems the repository pattern itself is like a DAO, no different. im so confused.
I am not sure this is what all you looking for but In my application I am using described DAO pattern with Spring
So im confused on how many Repositories i would need.
IMHO you will need at least single Repository for each entity as they lead to simple design but since you are making them generic and they are up in hierarchy, can be used simply with child classes/interfaces
Below is the example
Interface to define all basic methods that to use commonly
public interface GenericDAO<T, ID extends Serializable> {
T findById(ID id, LockModeType lock);
void save(T entity);
T update(T entity);
List<T> findAll();
}
Generic Implementation
public abstract class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID> {
#PersistenceContext
protected EntityManager em;
private final Class<T> entityClass;
public GenericDAOImpl(Class<T> entityClass) {
this.entityClass = entityClass;
}
#Override
public T findById(ID id, LockModeType lock) {
return em.find(entityClass, id, lock);
}
#Override
public void save(T entity) {
em.persist(entity);
}
#Override
public T update(T entity) {
return em.merge(entity);
}
#Override
public List<T> findAll() {
CriteriaQuery<T> c = em.getCriteriaBuilder().createQuery(entityClass);
c.select(c.from(entityClass));
return em.createQuery(c).getResultList();
}
.
.
.
}
Foo class
#Entity
public class Foo implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String text;
}
Foo Repositiry
public interface FooRepositiry extends GenericDAO<Foo, Long> {
Foo findTextById(Long id);
}
Implemented Foo Repositiry
#Transactional
#Repository
public class FooRepoImpl extends GenericDAOImpl<Foo, Long> implements FooRepositiry {
public FooRepoImpl() {
super(Foo.class);
}
#Override
public Foo findTextById(Long id) {
CriteriaQuery<Foo> c = em.getCriteriaBuilder().createQuery(Foo.class);
// .
// .
// .
return em.createQuery(c).getSingleResult();
}
}
Same for Bar class
#Transactional
#Repository
public class BarRepoImpl extends GenericDAOImpl<Bar, Long> implements BarRepo {
public BarRepoImpl() {
super(Bar.class);
}
#Override
public List<Bar> findAllBarWithText(String text) {
CriteriaQuery<Bar> c = em.getCriteriaBuilder().createQuery(Bar.class);
return em.createQuery(c).getResultList();
}
}
Here this generic implementation needs two things to work: an EntityManager and an
entity class. A subclass must provide the entity class as a constructor argument. EntityManager is provided by using PersistenceContext or you can use getter-setter methods for the same. Since GenericDAOImpl is abstract threfore you cannot use it directly but Indirectly and most of the commnoly used methods are generic and up in hierarchy which makes them Ideal candidate to be reused.
You can read more about this from book Java Persistence with Hibernate 2nd Edition
I need to write java generic method that gets no parameter and returns a List.
This generic method is used hibernate:
public <T> List list() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
List result = session.createQuery("from " + T.class.getName()).list();
return result;
}
I am tring to invoke this method. I tried the following but it creates compilation errors:
mgr.list<User>();
mgr.list()<User>;
mgr.list(<User>);
How can I call this method?
You forgot this one:
mgr.<User>list()
I believe what you're trying to accomplish requires some refactoring. It looks like you're trying to create a generic Dao class that you can reuse to query any Model object. The problem is that without passing the class to the method, you can't get the type of the <T> generic at runtime.
One way to accomplish what you want is to create a base dao, which is extended by specific implementations that know the class they're dealing with at compile time.
public abstract class AbstractDao<T>{
private Class<T> clazz;
public AbstractDao(Class<T> clazz){
this.clazz = clazz;
}
public List<T> list() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
List result = session.createQuery("from " + clazz.getName()).list();
return (List<T>) result;
}
}
Then extend the class:
class UserDao extends AbstractDao<User>{
public UserDao(){
super(User.class);
}
}
Then call the method:
List<User> users = userDao.list();
It may have something to do with "type erasure", because of using generics. When you call
T.class.getName()
that T type is erased before run time. It is not available at runtime, it is only used at compile time to make sure type safety. You probably need to write some code to get thy type of the persitence class at runtime, and then use that in mgr class. An exmaple is
public abstract class GenericHibernateDAO<T, ID extends Serializable>
implements GenericDAO<T, ID> {
private Class<T> persistentClass;
private Session session;
public GenericHibernateDAO() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
// more methods
}
from https://community.jboss.org/wiki/GenericDataAccessObjects?_sscc=t
Here, it has persistentClass which is set to parameter type at construction time, then that persistentClass is in the class, whenever needed.
I have set of classes which inherit from a single super class:
Super
|
+------+-------+
Aaaa Bbbb Cccc
Each of the Aaaa,Bbbb,Cccc then should contain method findByTag. The problem is that I can't manage to define it generally. Following example defines specific findByTag for Aaaa.
public interface AaaaRepository extends SuperRepository<Aaaa> {
#Query("select distinct a from Aaaa a " +
"join a.tags t " +
"join fetch a.locale where t = ?1")
public List<Event> findByTag(Tag t);
}
Note that the Superclass is #MappedSuperclass and does not have its own table in database.
I would like to use some kind of "Super" in the query which would be replaced in each class by its name.
My second problem is that I don't know how to force #ElementCollection to be Eagerly fetched. I have to always explicitly say "join fetch" in the query. If it is not fetched, once the transaction is finished, I can't access those objects, which I did not explicitly fetched. (LazyFetch Exceptions...)
Thanks
Looking at the documentation, custom implementations section, what about this approach:
Create an interface that extends repository and has your findByTag method, without annotations.
Create an implementation of that class, and in the method implementation you use the JPA criteria. You also need a class field to hold the actual class for the domain object, because generics are erased at compilation time. Then you use that field to build the criteria.
Read the documentation to use this implementation as a base class for the repository factory, then Spring Data will build implementations for the other repositories based on this custom one.
public interface MyRepository<T, ID> extends JpaRepository<T, ID> {
public List<Event> findByTag(Tag t);
}
public class MyRepositoryImpl<T, ID> implements MyRepository<T, ID> {
private Class<T> actualClass; // initialized in the constructor
public List<Event> findByTag(Tag t) {
// here you build the criteria using actualClass field, and execute it.
}
}
public interface AaaaRepository extends MyRepository <Aaaa, Integer> {
// other methods...
}
Look at "Example 1.16. Custom repository factory bean" of the documentation to create the factory bean.
When Spring instantiates the implementation of AaaaRepository, it will use MyRepositoryImpl as base class.
Will this work for you?
Instead of writing it this way, I would create a data access object that resembles the pseudo java code below:
class DAO<T> {
private Class<T> clazz;
DAO( Class<T> class) { this.clazz = t; }
#PersistenceContext
private EntityManager em;
public List<T> findByTag(Tag t ) {
Query q = em.createQuery( "select from " + clazz.getSimpleName + "....";
...
return q.getResultList();
}
}
Hope it helps!
In the end, I was so unhappy about the behaviour and inflexibility of the Spring Data JPA, so that I wrote myself a small tool for building the queries in a simple way. An example of using is here:
https://github.com/knyttl/Maite/wiki/Maite-Persistence
There are two children classes and the parent class which define the functionality. But the trick is in a fluent interface of building the query.
It is just in the beggining, but it already works so that I have no duplicity and correct inheritance.
Small example of the parent class - check the link above for detail:
#Autowired
EntityManager em;
protected abstract String getName();
protected Clause select() {
return em
.select("DISTINCT i")
.from(this.getName(), "i")
.joinFetch("i.locale lf")
}
public List<T> findByTag(Tag tag) {
return (T) this.select()
.join("i.tags t")
.where("t = ?", tag)
.fetchAll();
}
Using the generic dao pattern, I define the generic interface:
public interface GenericDao<T extends DataObject, ID extends Serializable> {
T save(T t);
void delete(ID id);
T findById(ID id);
Class<T> getPersistentClass();
}
I then implemented an default GenericDaoImpl implementation to perform these functions with the following constructor:
public GenericDaoImpl(Class<T> clazz) {
this.persistentClass = clazz;
DaoRegistry.getInstance().register(clazz, this);
}
The point of the DaoRegistry is to look up a Dao by the class associating to it. This allows me to extend GenericDaoImpl and overwrite methods for objects that requires special handling:
DaoRegistry.getInstance().getDao(someClass.getClass()).save(someClass);
While it works, there are a few things that I don't like about it:
DaoRegistry is an singleton
The logic of calling save is complicated
Is there a better way to do this?
Edit
I am not looking to debate whether Singleton is an anti-pattern or not.
First of all, what is your problem with DaoRegistry being singleton?
Anyway, you could have an abstract base class for your entities that'd implement save like this
public T save(){
DaoRegistry.getInstance().getDao(this.getClass()).save(this);
}
then you could simply call someEntity.save()
Or it may be more straightforward if the entity classes itself implemented the whole GenericDao interface (save, delete and find methods), so the contents of your GenericDaoImpl would be in the base class of your entities.
It could be better to use instance of DaoRegistry instead of static methods. It would make it more manageable for test configurations. You could implement it as
#Component("daoRegistry")
public class DaoRegistry {
#Autowired
private List<GenericDao> customDaos;
private GenericDao defaultDao = new GenericDaoImpl();
public <T> T getDao(Class<T> clazz) {
// search customDaos for matching clazz, return default dao otherwise
}
}
Also you could add save method to it and rename accordingly. All customised daos should be available as beans.
Using Hibernate 3.6.8.Final and Spring 3.0.5.RELEASE , I'm trying to add some Common DAO functionality for classes that have multiple implementations overridden higher up to implement the specific classes however it doesn't work for DetachedCriteria.
Example:
In base class:
public interface ICat {
public void setMeowSound(String meow);
public String getMeowSound();
}
Then each inherited project would define the hibernate annotations.
e.g.
#Entity
#Table(name="SQUAWKY_CATS")
public class SquawkyMeowingCat implements ICat, Serializable {
#Id
#Column(name="SQUAWK_NAME")
private String meow;
public String getMeowSound() {
return meow;
}
public void setMeowString(String meow) {
this.meow = meow;
}
}
This means I can use:
Criteria criteria = Session.createCriteria(ICat.class);
And Spring/Hibernate knows that it pulls the annotations for ICat from the concrete inheritance in the particular project.
However if I try to do:
DetachedCriteria subQuery = DetachedCriteria.forClass(ICat.class,"inner"); // etcetera
then I get an Unknown entity at runtime for ICat.
Now this makes sense as in the first instance is creating it off the Session so it has all the configuration that it needs whereas the DetachedCriteria is a static method however it errors when trying to do the
criteria.list()
by which time it has picked up the Session and should know that ICat is actually a SquawkyMeowingCat which has all the annotations.
So my questions are two part:
1) Is this known behaviour and will be like this forever more?
2) Can anyone think of a simple way around it without using an Interface and concrete ClassHolder which hands back the instance of the class it needs to create?
I'm not sure about the case of the DetachedCriteria, but one way to avoid explicit dependence on the concrete class might be to query Hibernate's metadata using the interface:
public <T> Class<? extends T> findEntityClassForEntityInterface(
SessionFactory sessionFactory,
Class<T> entityInterface
) {
for (ClassMetadata metadata : sessionFactory.getAllClassMetadata().values()) {
Class entityClass = metadata.getMappedClass(EntityMode.POJO);
if (entityInterface.isAssignableFrom(entityClass)) {
return entityClass;
}
}
return null;
}
With the usual caveats about the robustness of illustrative code spippets.