Is it possible to use Spring Data JPA projections together with QueryDSL? - spring

Is there a way in Spring Data JPA to combine out of box its support for QueryDSL and Projections (projections being inferred from the defined classes/interfaces).
Even though I read here and there that the support was added in 2.6 (the version I am using in the project) I am not able to make it work with various attempts like:
Using projection type as QuerydslPredicateExecutor type parameter.
Problem: the returned instances are of the entity class type not of the projection class type.
Using findAllProjectedBy. Problem: java.lang.IllegalArgumentException: At least 1 parameter(s) provided but only 0 parameter(s) present in query. on startup (repo creation phase).
public interface FooRepo extends JpaRepository<Foo, Long>, QuerydslPredicateExecutor<FooProjection> { //(1)
List<FooProjection> findAllProjectedBy(Predicate p); //(2)
}
Spring Data JPA version - 2.6.1.
I saw also some SO answers with custom solutions but I am not interested in that approach (some even use deprecated Spring Data JPA implementation components).

Related

List<List<String>> mapped to List<String>

I'm learning how to use Mapstruct in a Spring Boot and Kotlin project.
I've got a generated DTO (ThessaurusDTO) that has a List and I need this mapped into a List on my model (Vocab).
It makes sense that MapStruct can't map this automatically, but I know for a fact that the first list will always be size = 1. I have no control on the API the DTO model belongs to.
I found on the documentation that I can create define a default method implementation within the interface, which would loosely translate to a normal function in Kotlin
My mapper interface:
#Mapper
interface VocabMapper {
#Mappings(
// ...
)
fun thessaurusToVocab(thessaurusDTO: ThessaurusDTO): Vocab
fun metaSyns(nestedList: List<List<String>>): List<String>
= nestedList.flatten()
}
When I try to do a build I get the following error:
VocabMapper.java:16: error: Can't map collection element "java.util.List<java.lang.String>" to "java.lang.String ". Consider to declare/implement a mapping method: "java.lang.String map(java.util.List<java.lang.String> value)".
It looks like mapStruct is still trying to automatically do the mapping while ignoring my custom implementation. Am I missing something trivial here?
I found on the documentation that I can create define a default method implementation within the interface, which would loosely translate to a normal function in Kotlin
From my understand of what I found online, Kotlin does not properly translate an interface function into a default method in Java, but actually generates a class that implements the interface.
If that's the problem, you can annotate metaSyns with #JvmDefault:
Specifies that a JVM default method should be generated for non-abstract Kotlin interface member.
Usages of this annotation require an explicit compilation argument to be specified: either -Xjvm-default=enable or -Xjvm-default=compatibility.
See the link for the difference, but you probably need -Xjvm-default=enable.
I've seen to have fixed this by relying on an abstract based implementation, instead of using an interface.
From my understand of what I found online, Kotlin does not properly translate an interface function into a default method in Java, but actually generates a class that implements the interface.
https://github.com/mapstruct/mapstruct/issues/1577

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 to use declare Stream as return type when dealing with JPA Specification and spring-data-jpa

I'm wondering if I can use JPA specification predicates in custom queries?
I've tried but with no success.
Let's say I have an Entity Customer and a repository:
#Repository
public interface CustomerRepository
extends JpaRepository<Customer, Long>,
JpaSpecificationExecutor<Customer> {
}
Querying like this is OK
#Query("select c from Customer c")
Stream<Customer> streamAllCustomers();
This is Not OK
Stream<Customer> streamAllCustomersWithFilter(Specification<Customer> filter);
Is there a way to achieve this ?
NB I know I can put params in the #Query but I would like to stay in the design of the current app and use Specifications all the way.
There is the way to stream data from Spring Data JPA that I use.
This approach is useful to process huge amount of data while avoiding high memory consumption, because whole query result is not loaded to memory.
Create custom individual repository with following implementation
public class YourCustomRepositoryImpl implements YourCustomRepository {
#PersistenceContext(unitName = "yorEntityManagerFactory")
private EntityManager em;
#Override
public Stream<SomeEntity> streamAll(Specification<SomeEntity> spec) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SomeEntity> query = cb.createQuery(SomeEntity.class);
Root<SomeEntity> root = query.from(SomeEntity.class);
query.where(spec.toPredicate(root, query, cb));
return em.createQuery(query).getResultStream();
}
}
Sure, this requires JPA 2.2 supporting ORM framework (I used Hibernate 5.3).
Also, you should care to provide a connection to be alive while stream is being processed.
TL;DR;
No, and No, but manually Yes
I think issue DATAJPA-906 answers both of your questions
Question (from the title): How to use declare Stream as return type when dealing with JPA Specification and spring-data-jpa?
You don't, at least not in a directly supported way:
Support Java 8 Streams on JpaSpecificationExecutor
[..]
This unfortunately will have to wait for a 2.0 revamp as a Stream in the method signature would render the interface unloadable on versions of Java < 8.
Of course you can always add your custom methods including implementation.
Question Can I use JPA specification predicates in custom queries? (custom queries being queries defined using the #Query annotation
how would you even combine a CriteriaQuery defined through a Specification and a manually defined JPQL query?
In case the problem is not clear: If your custom query contains an inner select, wher should the Criteria from the specification go?
What you can do
Implement a custom method, returning a Stream and taking a specification as an argument, combine it with prepared specifications to call an existing method of the JpaSpecificationExecutor interface and convert the result to a Stream

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.

Confused about Spring-Data DDD repository pattern

I don't know so much about DDD repository pattern but the implementation in Spring is confusion me.
public interface PersonRepository extends JpaRepository<Person, Long> { … }
As the interface extends JpaRepository (or MongoDBRepository...), if you change from one db to another, you have to change the interface as well.
For me an interface is there to provide some abstraction, but here it's not so much abstract...
Do you know why Spring-Data works like that?
You are right, an Interface is an abstraction about something that works equals for all implementing classes, from an outside point of view.
And that is exactly what happens here:
JpaRepository is a common view of all your JPA Repositories (for all the different Entities), while MongoDBRepository is the same for all MongoDB Entities.
But JpaRepository and MongoDBRepository have nothing in common, except the stuff that is defined in there common super Interfaces:
org.springframework.data.repository.PagingAndSortingRepository
org.springframework.data.repository.Repository
So for me it looks normal.
If you use the classes that implement your Repository then use PagingAndSortingRepository or Repository if you want to be able to switch from an JPA implementation to an Document based implementation (sorry but I can not imagine such a use case - anyway). And of course your Repository implementation should implement the correct interface (JpaRepository, MongoDBRepository) depending on what it is.
The reasoning behind this is pretty clearly stated in this blog post http://blog.springsource.com/2011/02/10/getting-started-with-spring-data-jpa/.
Defining this interface serves two purposes: First, by extending JpaRepository we get a bunch of generic CRUD methods into our type that allows saving Accounts, deleting them and so on. Second, this will allow the Spring Data JPA repository infrastructure to scan the classpath for this interface and create a Spring bean for it.
If you do not trust sources so close to the source (pun intended) it might be a good idea to read this post as well http://www.brucephillips.name/blog/index.cfm/2011/3/25/Using-Spring-Data-JPA-To-Reduced-Data-Access-Coding.
What I did not need to code is an implementation of the PersonRepository interface. Spring will create an implementation of this interface and make a PersonRepository bean available to be autowired into my Service class. The PersonRepository bean will have all the standard CRUD methods (which will be transactional) and return Person objects or collection of Person objects. So by using Spring Data JPA, I've saved writing my own implementation class.
Until M2 of Spring Data we required users to extend JpaRepository due to the following reasons:
The classpath scanning infrastructure only picked up interfaces extending that interface as one might use Spring Data JPA and Spring Data Mongo in parallel and have both of them pointed to the very same package it would not be clear which store to create the proxy for. However since RC1 we simply leave that burden to the developer as we think it's a rather exotic case and the benefit of just using Repository, CrudRepository or the like outweights the effort you have to take in the just described corner case. You can use exclude and include elements in the namespace to gain finer-grained control over this.
Until M2 we had transactionality applied to the CRUD methods by redeclaring the CRUD methods and annotating them with #Transactional. This decision in turn was driven by the algorithm AnnotationTransactionAttributeSource uses to find transaction configuration. As we wanted to provide the user with the possibility to reconfigure transactions by just redeclaring a CRUD method in the concrete repository interface and applying #Transactional on it. For RC1 we decided to implement a custom TransactionAttributeSource to be able to move the annotations back to the repository CRUD implementation.
Long story short, here's what it boils down to:
As of RC1 there's no need to extend the store specific repository interface anymore, except you want to…
Use List-based access to findAll(…) instead of the Iterable-based one in the more core repository interfaces (allthough you could simply redeclare the relevant methods in a common base interface to return Lists as well)
You want to make use of the JPA-specific methods like saveAndFlush(…) and so on.
Generally you are much more flexible regarding the exposure of CRUD methods since RC1 as you can even only extend the Repository marker interface and selectively add the CRUD methods you want to expose. As the backing implementation will still implement all of the methods of PagingAndSortingRepository we can still route the calls to the instance:
public interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> {
List<T> findAll();
T findOne(ID id);
}
public interface UserRepository extends MyBaseRepository<User, Long> {
List<T> findByUsername(String username);
}
In that example we define MyBaseRepository to only expose findAll() and findOne(…) (which will be routed into the instance implementing the CRUD methods) and the concrete repository adding a finder method to the two CRUD ones.
For more details on that topic please consult the reference documentation.

Resources