Applying #PostFilter annotation to a generic Spring Data Jpa repository method - spring

I want to use the #PostFilter annotation on a Spring Data Jpa repository generic method (such as a findAll) as follows:
#PostFilter("filterObject.isActivated()==true")
public List<Advertisement> findAll();
How can I do that bearing in mind the those methods are provided "automagically" by Spring Data Jpa and are therefore not exposed in the application code?

Yes, you can add a #PostFilter to any method provided by a Spring Data Repository. Just override existing method findAll() and add your #PostFilter annotation as depicted in your example. Don't forget to add to your configuration where your repositories are defined
<global-method-security pre-post-annotations="enabled" />
or in a java based configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
respectively.
Keep in mind. This works just for collections and arrays. For every other return type like Page you get an IllegalArgumentException. See DefaultMethodSecurityExpressionHandler#filter for implementation details.

Related

Filter entities in spring repository

It is possible to apply a filter to results with annotations instead of extending method name?
For instance:
#Repository
public interface JobRepository extends JpaRepository<Job, Long> {
List<Job> findAllByUserAndEnabledIsTrue(User u);
}
Here I apply filter 'enabled == true'. But assume we have a lot of methods. Writing them with extended names is inconvenient. Could I apply this filter to whole repository?
I found
#FilterDef but I don't know how to use and also if spring support this annotation.
As far as I know Spring Data JPA is not Hibernate dependent, and it can work with any JPA implementation. Hibernate's #Filters is not a JPA standard, so the simple answer is no! Spring JPA does not support #Filters.
But you can apply #Filters using AOP, and simply applying aspects on your repository methods.
By the way I believe the better solution is to have hand written queries using Spring Data JPA's #Query annotation. Because this way you can name methods after their context meaning, and not about their internal implementation.
For example you can name your method findActiveJobsForUser which could be more meaningful and readable.

How can I check QueryHint work or not?

Spring Data JPA allows placing #QueryHints annotation on the interface method and can be applied to the methods annotated with #Query and without such.
#QueryHints(#javax.persistence.QueryHint(name="org.hibernate.fetchSize", value="50"))
List<Foo> findAll();
How can I check know for sure that hint was honored?

Spring Data MongoDB: Specifying a hint on a Spring Data Repository find method

I am implementing a Spring Data Repository and having my repository extend the MongoRepository. I am looking for a way to specify a hint on my findBy methods so I can be control. I have seen several times when a non-optimal index would be picked as the winning plan.
This is what my repository looks like right now:
public interface AccountRepository extends MongoRepository<Account, ObjectId> {
#Meta(maxExcecutionTime = 60000L, comment = "Comment" )
public List<Account> findByUserIdAndBrandId(Long userId, Long brandId);
}
I researched a bunch and found that the JPARepository from spring data supports the #QueryHint annotation but I do not believe that annotation is supported for MongoDb. Is there a similar annotation I can specify on top of my findBy method to specify the hint?
MongoTemplate allows to specify a hint, however, I have a ton of findBy methods and I would hate to add an implementation underneath just to specify a hint.

How to manage transactions with JAX-RS, Spring and JPA

I'm using JAX-RS to provide an HTTP-based interface to manage a data model. The data model is stored in a database and interacted with via JPA.
This allows me to modify the interface to the data model to suit REST clients and mostly seems to work quite well. However, I'm not sure how to handle the scenario where a method provided by a JAX-RS resource requires a transaction, which affects the JPA get, update, commit-on-tx-end pattern, because there is only a transaction wrapping the get operation, so the update is never committed. I can see the same problem occurring if a single REST operation requires multiple JPA operations.
As I'm using Spring's transaction support, the obvious thing to do is to apply #Transactional to these methods in the JAX-RS resources. However, in order for this to work, Spring needs to manage the lifecycle of the JAX-RS resources, and the useage examples I'm aware of have resources being created via `new' when needed, which makes me a little nervous anyway.
I can think of the following solutions:
update my JPA methods to provide a transaction-managed version of everything I want to do from my REST interface atomically. Should work, keeps transactions out of the JAX-RS layer, but prevents the get, update, commit-on-tx-end pattern and means I need to create a very granular JPA interface.
Inject Resource objects; but they are typically stateful holding at least the ID of the object being interacted with
Ditch the hierarchy of resources and inject big, stateless super resources at the root that manage the entire hierarchy from that root; not cohesive, big services
Have a hierarchy of injected, stateless, transaction-supporting helper objects that 'shadow' the actual resources; the resources are instantiated and hold ths state but delegate method invocations to the helper objects
Anyone got any suggestions? It's quite possible I've missed some key point somewhere.
Update - to work around the lack of a transaction around the get, update, commit-on-tx-close flow, I can expose the EntityManager merge(object) method and call it manually. Not neat and doesn't solve the larger problem though.
Update 2 #skaffman
Code example:
In JPA service layer, injected, annotations work
public class MyEntityJPAService {
...
#Transactional(readOnly=true) // do in transaction
public MyEntity getMyEntity(final String id) {
return em.find(MyEntity.class, id);
}
In JAX-RS resource, created by new, no transactions
public class MyEntityResource {
...
private MyEntityJPAService jpa;
...
#Transactional // not injected so not effective
public void updateMyEntity(final String id, final MyEntityRepresentation rep) {
MyEntity entity = jpa.getMyEntity(id);
MyEntity.setSomeField(rep.getSomeField());
// no transaction commit, change not saved...
}
I have a few suggestions
Introduce a layer between your JPA and JAX-RS layers. This layer would consist of Spring-managed #Transactional beans, and would compose the various business-level operations from their component JPA calls. This is somewhat similar to your (1), but keeps the JPA layer simple.
Replace JAX-RS with Spring-MVC, which provides the same (or similar) functionality, including #PathVariable, #ResponseBody, etc.
Programmatically wrap your JAX-RS objects in transactional proxies using TransactionProxyFactorybean. This would detct your #Transactional annotations and generate a proxy that honours them.
Use #Configurable and AspectJ LTW to allow Spring to honour #Transactional even if you create the object using `new. See 8.8.1 Using AspectJ to dependency inject domain objects with Spring

How to control spring #transactional Annotation precedence?

The situation is that I am using Aspectj with spring aop,I define a aspect(After advice) to do some data opration for a method.And I also use the spring #transactional for the same method.
Now the question comes,how can I control the order for them to aspectj?
(I know how to control the two aspect defined by myself ,but I have no idea if one of them is spring #transactional )
Thank you very much for your help.
You can define relative order of transactional aspect using order attribute of <tx:annotation-driven>, it works the same way as orders of other aspects.

Resources