I'd like to wrap/unwrap my Entity each time it's loaded or persisted. I got to know that I cannot do it using JPA listeners since they can only perform an action on the object and not swap it with the other. The natural solution would be to use an Aspect. But are there particular methods that I can pointcut? The thing is that the entity to be wrapped/unwrapped can be a field of another entity...
EDIT:
I found out that you cannot do this using Spring AOP because EntityManager is not spring-managed (why?) - see here. To make it work I would have to define EntityManager bean explicitely but it is not recommended in that post - again, why? How to do that anyway? On the other hand why does they state that created EntityManager is application-managed? See spring API documentation
Try to pointcut the getters and setter that use the entity class. Methods that retrieve entities from EntityManager, best way to achieve this is create new annotation and put over all the methods that could retrieve a instance for that class, then use the #annotation support pointcut:
#annotation - limits matching to join points where the subject of the
join point (method being executed in Spring AOP) has the given
annotation
Also to obtain the modifying entity you could do something like this.
Get method arguments using spring aop?
Sometimes you need access in the advice body to the actual value that was returned. You can use the form of #AfterReturning that binds the return value
Related
I am reading about JPA, when I came across POJO properties that makes it a jpa entity and one of the properties is "it should be transactional" which means -according to the book- : changes made to the database either succeed or fail atomically, so the persistent view of an entity should indeed be transactional.
And my question is : what in a java object might make it non transactional?
What can make an object non-transactional?
--> No using annotation #Transactional in Java POJO class.
Trying to collect and understand the main points of #Transactional annotation and crossed one point. So, the main things that we need to keep in mind when using Transactional annotation are:
Transactional annotation can be applied only to public methods [according to Does Spring #Transactional attribute work on a private method?
Transactional annotation should be applied to the concrete classes instead of interfaces [according to Where should I put #Transactional annotation: at an interface definition or at an implementing class?
Transactional annotation should be applied on the Service level [according to Spring #Transactional Annotation Best Practice
If you want to exclude some public method from being annotated with Transactional when whole class is annotated you can use some propagation strategies [according to Transactional annotation on whole class + excluding a single method
Unfortunately I didn't find the answer to the question: Where it is better to put Transactional annotation - to the class or method? We can consider different situations, but mostly i am interested in the one when we have several methods which must have this annotation and some which don't.
Plus, maybe you would like to add some points to this list, that would be really great.
Here is a list of pros and (implicitly) cons I can think of.
Pro Method Level:
Easy to read: You look at a method and can tell that it is transactional without having to look at the class, its implemented interfaces or super-classes.
Explicit: The annotation clearly tells you that the method is meant to be transactional. It is not just transactional because all methods in the class are transactional.
Less unintended merging of (otherwise) independent transactions: If you call multiple transactional methods from a method that is (implicitly) transactional, then the outer transaction defines the whole transaction (unless the propagation settings are like REQUIRES_NEW or so). While this is in many cases no problem, I have seen projects getting into serious trouble due to this in the long run. Especially when it comes to pessimistic locking, it is crucial to keep transactions as independent and small as possible, so transactions need only few locks and the locks are released as soon as possible.
Pro Class Level:
Less repetitive: If you put the annotation on the class level, you do not have to annotate each and every transactional method. Some people argue that putting the annotation on each transactional method is against the DRY principle. However, IMHO, if this is against the DRY principle, then Java's private/protected/public modifiers are, too.
In my opinion it is better to mark each method with #Transactional annotation separately (to indicate that this method is updating something) instead of marking whole class. This will produce more code and can be redundant in some cases but imagin that you have for example 10 methods in your service. Nine of those methods are updating something and one is only reading. Your code is using ORM (for example Hibernate) and you have some objects managed by Hibernate in your method. During adding new logic you accidentaly changed one field in object managed by Hibernate. In this case hibernate will fire update sql insturction in method which should only read. It may produce bug which is hard to find.
I need to have a List of clasess that are Persistence Entities, I need have Entity Information, using Reflection API of JPA
I have the EntityManager, But I do not know if that is the way.
I want to do a generic logging for my Entities using a EntityListener. That works well, but I do not have the way to register the listener to all my entities.
Use the JPA2 MetaModel? It has assorted methods to see the entities (or managed types).
Set<javax.persistence.metamodel.EntityType<?>> entityTypes = entityManagerFactory.getMetamodel().getEntities();
for (javax.persistence.metamodel.EntityType entityType : entityTypes){
logger.info(entityType.getName());
logger.info(entityType.getJavaType().getCanonicalName());
logger.info("******************************");
}
Take a look at Configuration#getClassMappings()
Returns: Iterator of the entity mappings currently contained in the configuration.
Correct me if anything is wrong.
Now when we use Spring DAO for ORM templates, when we use #Transactional attribute,
we do not have control over the transaction and/or session when the method is called externally, not within the method.
Lazy loading saves resources - less queries to the db, less memory to keep all the collections fetched in the app memory.
So, if lazy=false, then everything is fetched, all associated collections, that is not effectively, if there are 10,000 records in a linked set.
Now, I have a method in a DAO class that is supposed to return me a User object.
It has collections that represent linked tables of the database.
I need to get a object by id and then query its collections.
Hibernate "failed to lazily initialize a collection" exception occurs when I try to access the linked collection that this DAO method returns.
Explain please, what is a workaround here?
Update: All right, let me ask you this. DAO is an abstract layer, so a method "getUserById(Integer id)" is supposed to return an Object.
What if in some cases I need these linked collections of the User object and in other situation I need those collections.
Are there only two ways:
1) lazy loading = false
2) create different methods: getUserByIdWithTheseCollections(), getUserByIdWithOtherCollections() and inside those methods use your approach?
I mean are there only 2 ways and nothing better?
Update 2: Explain please, what would give me the explicit use of SESSIONFACTORY?
How does it look in practice? We create an instance of DAO object,
then inject it with session factory and this would mean that two consequent
method calls to DAO will run within the same transaction?
It seems to me that anyway, DAO is detached from the classes that make use of it!
The logic and transactions are encapsulated within DAO, right?
You can get the linked collection in transaction to load it while you're still within the transaction:
User user = sessionFactory.getCurrentSession().get(User.class, userId);
user.getLinkedCollection().size();
return user;
As BalusC has pointed out, you can use Hibernate.initialize() instead of size(). That's a lot cleaner.
Then when you return such an entity, the lazy field is already initialized.
Replying to your PS - is using transactions on service level (rather than DAO) level feasible? It seems to be, as doing each DAO call in separate transaction seems to be a waste (and may be incorrect).
I find that it's best to put #Transactional at the service layer, rather than the DAO layer. Otherwise, all your DAO calls are in separate hibernate sessions - all that object equality stuff won't work.
In my opinion best way to solve this problem will be to design application in a session-per-request model. Then, if you even have an object taken from DAO, until your OSIV pattern works you can use the object safely anywhere in application, even in views without bothering this stuff. This is probably better solution that those proposed because:
Hibernate.initialize() or size is a very artificial workaround - what if you want to have User with different collection initialized, would you write another method for getting user?
Service layer transactional model is OK, but the same problem comes when you want to get object extracted from the service layer to use it in controller or view
You could do something like following:
public User getByUserId(Long id, String ... fetch) {
Criteria criteria = createCriteria();
if (fetch != null) {
for (String fieldName : fetch) {
criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly
}
}
return criteria.add(Restrictions.eq("id", id)).list();
}
A question about Java-Hibernate-Validator.
I need to access to a collection attribute when my validation system intercepts an entity insert/update.
I mean, my model defines A class with a set of B elements.
When I call saveOrUpdate(a), the onSave/onFushDirty method of my interceptor is invoked. In that moment I need to know the size of the collection. Is it possible?
Thanks!
Well, according the the docs, your onSave method receives the entity you are persisting. At that point you can cast your entity to what you want. You can either check with instanceof or make overloaded methods that accept your different classes. And from there, access your collection.
Also make sure you have an active session at that point, or that there are no lazy collections.