Dynamic Queries in Spring Data JPA - spring

I am looking for a solution to dynamically build queries using Spring Data JPA. I have a GameController which has a RESTful service endpoint /games which takes 4 optional parameters: genre, platform, year, title. The API may be passed none of those, all 4, and every combination in between. If any parameter is not passed it defaults to null. I need a method in the Repository that will build the appropriate query and ideally also still allow Spring Data JPA Paging, although I'm not sure if that is possible.
I found this article but this doesn't seem to be what I need unless I am misunderstanding. http://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
I know JPA has a Query Criteria API but really have no idea how to implement this.
I realize I could create a method for each possible scenario but that seems like really bad practice and a lot of unnecessary code.
GameRepository:
package net.jkratz.igdb.repository;
import net.jkratz.igdb.model.Game;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface GameRepository extends JpaRepository<Game, Long> {
#Query("select g from Game g, GamePlatformMap gpm, Platform p where g = gpm.game and gpm.platform = p and p.id = :platform")
Page<Game> getGamesByPlatform(#Param("platform") Long platformId, Pageable pageable);
#Query("select g from Game g where g.title like :title")
Page<Game> getGamesByTitle(#Param("title") String title, Pageable pageable);
#Query("select g from Game g, GameGenreMap ggm, Genre ge where g = ggm.game and ggm.genre = ge and ge.id = :genreId")
Page<Game> getGamesByGenre(#Param("genre") Long genreId, Pageable pageable);
}

I would say that using QueryDSL is one way of doing what you want.
For example I have a repository defined as below:
public interface UserRepository extends PagingAndSortingRepository<User, Long>, QueryDslPredicateExecutor<User> {
public Page<User> findAll(Predicate predicate, Pageable p);
}
I can call this method with any combination of parameters, like below:
public class UserRepositoryTest{
#Autowired
private UserRepository userRepository;
#Test
public void testFindByGender() {
List<User> users = userRepository.findAll(QUser.user.gender.eq(Gender.M));
Assert.assertEquals(4, users.size());
users = userRepository.findAll(QUser.user.gender.eq(Gender.F));
Assert.assertEquals(2, users.size());
}
#Test
public void testFindByCity() {
List<User> users = userRepository.findAll(QUser.user.address.town.eq("Edinburgh"));
Assert.assertEquals(2, users.size());
users = userRepository.findAll(QUser.user.address.town.eq("Stirling"));
Assert.assertEquals(1, users.size());
}
#Test
public void testFindByGenderAndCity() {
List<User> users = userRepository.findAll(QUser.user.address.town.eq("Glasgow").and(QUser.user.gender.eq(Gender.M)));
Assert.assertEquals(2, users.size());
users = userRepository.findAll(QUser.user.address.town.eq("Glasgow").and(QUser.user.gender.eq(Gender.F)));
Assert.assertEquals(1, users.size());
}
}

For those using Kotlin (and Spring Data JPA), we've just open-sourced a Kotlin JPA Specification DSL library which lets you create type-safe dynamic queries for a JPA Repository.
It uses Spring Data's JpaSpecificationExecutor (i.e. JPA criteria queries), but without the need for any boilerplate or generated metamodel.
The readme has more details on how it works internally, but here's the relevant code examples for a quick intro.
import au.com.console.jpaspecificationsdsl.* // 1. Import Kotlin magic
////
// 2. Declare JPA Entities
#Entity
data class TvShow(
#Id
#GeneratedValue
val id: Int = 0,
val name: String = "",
val synopsis: String = "",
val availableOnNetflix: Boolean = false,
val releaseDate: String? = null,
#OneToMany(cascade = arrayOf(javax.persistence.CascadeType.ALL))
val starRatings: Set<StarRating> = emptySet())
#Entity
data class StarRating(
#Id
#GeneratedValue
val id: Int = 0,
val stars: Int = 0)
////
// 3. Declare JPA Repository with JpaSpecificationExecutor
#Repository
interface TvShowRepository : CrudRepository<TvShow, Int>, JpaSpecificationExecutor<TvShow>
////
// 4. Kotlin Properties are now usable to create fluent specifications
#Service
class MyService #Inject constructor(val tvShowRepo: TvShowRepository) {
fun findShowsReleasedIn2010NotOnNetflix(): List<TvShow> {
return tvShowRepo.findAll(TvShow::availableOnNetflix.isFalse() and TvShow::releaseDate.equal("2010"))
}
/* Fall back to spring API with some extra helpers for more complex join queries */
fun findShowsWithComplexQuery(): List<TvShow> {
return tvShowRepo.findAll(where { equal(it.join(TvShow::starRatings).get(StarRating::stars), 2) })
}
}
For more complex and dynamic queries it's good practice to create functions that use the DSL to make queries more readable (as you would for QueryDSL), and to allow for their composition in complex dynamic queries.
fun hasName(name: String?): Specifications<TvShow>? = name?.let {
TvShow::name.equal(it)
}
fun availableOnNetflix(available: Boolean?): Specifications<TvShow>? = available?.let {
TvShow::availableOnNetflix.equal(it)
}
fun hasKeywordIn(keywords: List<String>?): Specifications<TvShow>? = keywords?.let {
or(keywords.map { hasKeyword(it) })
}
fun hasKeyword(keyword: String?): Specifications<TvShow>? = keyword?.let {
TvShow::synopsis.like("%$keyword%")
}
These functions can be combined with and() and or() for complex nested queries:
val shows = tvShowRepo.findAll(
or(
and(
availableOnNetflix(false),
hasKeywordIn(listOf("Jimmy"))
),
and(
availableOnNetflix(true),
or(
hasKeyword("killer"),
hasKeyword("monster")
)
)
)
)
Or they can be combined with a service-layer query DTO and mapping extension function
/**
* A TV show query DTO - typically used at the service layer.
*/
data class TvShowQuery(
val name: String? = null,
val availableOnNetflix: Boolean? = null,
val keywords: List<String> = listOf()
)
/**
* A single TvShowQuery is equivalent to an AND of all supplied criteria.
* Note: any criteria that is null will be ignored (not included in the query).
*/
fun TvShowQuery.toSpecification(): Specifications<TvShow> = and(
hasName(name),
availableOnNetflix(availableOnNetflix),
hasKeywordIn(keywords)
)
for powerful dynamic queries:
val query = TvShowQuery(availableOnNetflix = false, keywords = listOf("Rick", "Jimmy"))
val shows = tvShowRepo.findAll(query.toSpecification())
JpaSpecificationExecutor supports paging, so you can achieve pageable, type-safe, dynamic queries!

I have got a solution for this. I wrote some code to extend the spring-data-jpa .
I call it spring-data-jpa-extra
spring-data-jpa-extra comes to solve three problem:
dynamic native query support like mybatis
return type can be anything
no code, just sql
You can try it : )

Related

Get fields of spring jpa interface projection

I have this stored procedure that I am calling in spring jpa repository and I am using interface based projection.
Whenever I try to call the interface projection method i get this error
Invoked method public abstract java.lang.Long
ConfirmationDTO.memberID() is no accessor method!
Here is my projection Interface
public interface ConfirmationDTO {
Long memberID();
LocalDate dateEntry();
}
and the DAO
#Query(value=" CALL get_confirmation(:startDate) ", nativeQuery=true)
List<ConfirmationDTO> getConfirmation(LocalDate startDate);
Is it possible to get the field values from the interface projection ?
I found another SO thread which uses Tuple, this helped me to achieve the goal of my above question.
how-to-map-sql-native-query-result-into-dto-in-spring-jpa-repository
Here is the sample code from that thread :
#Repository
public interface StockRepository extends RevisionRepository<Stock, Long, Integer>, JpaRepository<Stock, Long> {
#Query(value = "SELECT stock_akhir.product_id AS productId, stock_akhir.product_code AS productCode, SUM(stock_akhir.qty) as stockAkhir "
+ "FROM book_stock stock_akhir "
+ "where warehouse_code = (:warehouseCode) "
+ "AND product_code IN (:productCodes) "
+ "GROUP BY product_id, product_code, warehouse_id, warehouse_code", nativeQuery = true)
List findStockAkhirPerProductIn(#Param("warehouseCode") String warehouseCode, #Param("productCodes") Set productCode); }
and them map the Tuple in the service:
public List<StockTotalResponseDto> findStocktotal() {
List<Tuple> stockTotalTuples = stockRepository.findStocktotal();
List<StockTotalResponseDto> stockTotalDto = stockTotalTuples.stream()
.map(t -> new StockTotalResponseDto(
t.get(0, String.class),
t.get(1, String.class),
t.get(2, BigInteger.class)
))
.collect(Collectors.toList());
return stockTotalDto;
}
Let me try to explain how you can easily do this.
public class Confirmation {
private Long memberId;
private LocalDate dateEntry;
//add other fields
//provide getters and setters
}
//tuple
public inteface ConfirmationTuple {
Long getMemberId ();
LocalDate getDateEntry ();
}
//Your repository
#Query(value = " CALL get_confirmation(:startDate) ", nativeQuery = true)
List<ConfirmationTuple> getConfirmation (LocalDate startDate);
Spring will do the rest for you. To get the memberId from the first tuple, all you do is
yourDAO.getConfirmation(startDate).get(0).getMemberId();
The catch here is the get methods in your tuple must correspond to the field names being returned by your query in your repository. For example, if your query is returning the following columns [memberName,myDate] your Tuple interface must have getMemberName and getMyDate() for these values to be assigned.
You could create an implementation component and it would be autowired, but it's not recommended to annotate DTO classes.
The easiest way is to turn your interface into a class.
At the end of the day it's just a DTO, it have no logic, and on tests you can mock it as you wish just filling the properties.
I don't see the point on your DTO being an interface, unless a Class somewhere is implementing more than one interface and this one is among them.
If this is the case, I would rethink the implementation - e.g. implement TheOtherInterface extend Person.

custom sql queries in JPA Criteria Predicate, StringPath, Querydsl

I have a Spring boot project with hibernate 5.4.12, Java 11 and Postgres.
I am trying to build a custom Sort/Filter mechanism using JPA and Querydsl, here is one blog for reference.
We have a gin index column which is used for full text search feature by postgres. In jpa repository, I can query the column easily as below
#Query(value = "select * from products where query_token ## plainto_tsquery(:query)", nativeQuery = true)
Page<Product> findAllByTextSearch(#Param("query") String query, Pageable pageable);
I am aware that fts queries are not yet supported by JPA criteria or querydsl APIs (I may be wrong). Since normal filtering logic will go through criteria API, how do add fts capabilities in criteria API? Is there a way to add custom native query as predicate or StringPath or any other Qtype paths?
UPDATE
My SearchPredicate class
public class SearchPredicate<E extends Enum<E>> {
private SearchCriteria<E> searchCriteria;
public <T> BooleanExpression getPredicate(Class<T> entityClass, String entityName) {
PathBuilder<T> entityPath = new PathBuilder<>(entityClass, entityName);
switch (searchCriteria.getPathType()) {
case String:
StringPath stringPath = entityPath.getString(searchCriteria.getKey());
return stringPath.eq(searchCriteria.getStringValue());
case Enum:
return entityPath.getEnum(searchCriteria.getKey(), searchCriteria.getEnumClass())
.eq(Enum.valueOf(searchCriteria.getEnumClass(), searchCriteria.getStringValue()));
case Float:
NumberPath<Float> floatPath = entityPath.getNumber(searchCriteria.getKey(), Float.class);
Float floatValue = Float.parseFloat(searchCriteria.getStringValue());
return floatPath.eq(floatValue);
case Integer:
NumberPath<Integer> integerPath = entityPath.getNumber(searchCriteria.getKey(), Integer.class);
Integer integerValue = Integer.parseInt(searchCriteria.getStringValue());
return integerPath.eq(integerValue);
}
return null;
}
}
My SearchCriteria class
public class SearchCriteria<E extends Enum<E>> {
private String key;
private Object value;
private PathType pathType;
private Class<E> enumClass;
public String getStringValue() {
return value.toString();
}
}
And My PathType Enum
public enum PathType {
String, Enum, Integer, Float;
}
On these same lines, I am assuming/expecting something for text search as well e.g.
case Search:
FtsPath ftsPath = entityPath.getFtsPath("query_token");
return ftsPath.search("some search string")
You should first make the ## operator available by registering a custom function for your ORM. Then you can do plainto_tsquery(query_token, :query) in your JPQL query. How to register a custom function depends on the ORM you use. Assuming you use Hibernate, you're probably best of using the MetadataContributor SPI because functions registered through the Dialect have less flexibility with regard to the underlying SQL rendering AFAIK.
Then, if you want to use this in QueryDSL, you'd have to create a custom Operator and register a Template for that Operator in a subclass of JPQLTemplates. Alternatively, you can bypass the Operation expressions using a simple TemplateExpression: Expressions.booleanTemplate("plainto_tsquery({0}, {1})", QProduct.product.queryToken, query), which returns a predicate.

Spring boot JPA: search entities by field that represent list of embedded objects

I have an entity Order with List of options inside, like this:
#Entity
#Table(name = "orders")
public class OrderEntity extends AuditableEntity {
private Long passengerId;
private OrderType type;
private OrderStatus status;
#ElementCollection()
#CollectionTable(name = "options", joinColumns = #JoinColumn(name = "order_id"))
private List<OrderOptionEntity> options = new ArrayList<>(0);
...
And I want to find all orders, matches specified list of options. I'm using JpaRepository<OrderEntity, Long> for CRUD operations. Unfortunately, when I add method findByOptions, like this:
public interface OrderRepository extends JpaRepository<OrderEntity, Long> {
List<OrderEntity> findAllByOptions(List<OrderOptionEntity> options);
}
In tests it throws
SqlNode's text did not reference expected number of columns;
So now I just do findAll() and filter all orders manually. Is there any more elegant way for obtain entities, matching by all elements of list inside it?
UPDATE:
When I run
#Query("SELECT ord FROM OrderEntity ord WHERE :options MEMBER OF ord.options")
List<OrderEntity> findAllByOptions(#Param(value = "options") List<OrderOptionEntity> options);
It works fine, but only if ord.options and options in query has size 1, if more - it throws
o.h.engine.jdbc.spi.SqlExceptionHelper : Invalid argument in JDBC
call: parameter index out of range: 3
Generated SQL is
/* SELECT
ord
FROM
OrderEntity ord
WHERE
:options MEMBER OF ord.options */ select
orderentit0_.id as id1_3_,
orderentit0_.version as version2_3_,
orderentit0_.create_time as create_t3_3_,
orderentit0_.update_time as update_t4_3_,
orderentit0_.comment as comment5_3_,
orderentit0_.distance_to_order as distance6_3_,
orderentit0_.passenger_id as passenge7_3_,
orderentit0_.price as price8_3_,
orderentit0_.route_distance as route_di9_3_,
orderentit0_.status as status10_3_,
orderentit0_.type as type11_3_
from
orders orderentit0_
where
(
? , ?
) in (
select
options1_.key,
options1_.value
from
options options1_
where
orderentit0_.id=options1_.order_id
)
All what I want - get all Orders, containing some subset of options.
You probably forgot the In keyword in your query method.
Try this
public interface OrderRepository extends JpaRepository<OrderEntity, Long> {
List<OrderEntity> findAllByOptionsIn(List<OrderOptionEntity> options);
}
Take a look at the docs.

Create a Dynamic Query in Spring

I have been using the standard JPA implementation for a while and had no problems creating dynamic queries resulting from algorithms to search for users in a database. However, we are moving to the Spring Framework (an older version - 3.2, unfortunately) and I simply cannot figure out how to create a dynamic query in Spring.
With javax.persistance.EntityManager, I could call createQuery and give it a string to work with. However, I have found that in Spring I can only use something like the following code where I define the query in an annotation.
#Repository
#SuppressWarnings("unused")
public interface PersonRepository extends JpaRepository<Person, Long>, CrudRepository<Person, Long> {
#Override
List<Person> findAll(Sort sort);
#Override
List<Person> findAll();
#Query("SELECT p FROM Person p ORDER BY p.lname ASC, p.fname ASC, p.mname ASC")
List<Person> findAllSort();
#Query("SELECT p FROM Person p WHERE UPPER(p.userName) = UPPER(?1)")
Person findPersonByUsername(String username);
}
Here is the simplest dynamic query example I could give you that I would like to replicate for Spring:
public List<Person> getPersons(List<Long> perIds) {
List<Person> persons;
String whereClause = "";
for (int i = 0; i < perIds.size(); i++) {
if (i != 0)
whereClause += " OR ";
whereClause += "p.perId = '" + perIds.get(i) + "'";
}
persons = em.createQuery("SELECT p FROM Person p WHERE " + whereClause).getResultList();
return persons;
}
Maybe a better question here is to ask if it is possible or if I should just keep my implementation using the Entity Manager. That being said, would anyone recomend me to change my code from using the EntityManager over to using the Spring Framework?
I do not know if we can do what you request.
But I have an alternative to your method.
public List<Person> getPersons(List<Long> perIds) {
return em.createQuery(
"SELECT p FROM Person p WHERE p.perId = "
+ org.springframework.util.StringUtils.collectionToDelimitedString(perIds, " OR p.perId = ", "'", "'")
).getResultList();
}
Why not use the IN query condition instead?
Spring should allow you to do:
#Query( "SELECT p FROM Person p WHERE p.perId in :ids" )
findPersonsInIdList(#Param("ids") List<Long> perIds);
Spring allows you to use #Repository, but does not force you to do so. Spring even offers a nice interfacing of JPA that separates the low level concerns (Datasource definition, and transaction management) from the high level ones (DAO, with declarative transactions).
There is a chapter in Spring Framework Reference Manual about JPA. You should also read the part about transaction management in previous chapters.
Please consider the below example.May be you are looking something like this.Though your question is not pretty straight forward what do you want.Using criteria or specification you can achieve many cool things.
#Service
Optional<Person> findByEmail(String email);
#NoRepositoryBean
public interface PersonRepositoryCustom {
Optional<Person> findByEmail(String email);
}
#Repository
public class PersonRepositoryImpl extends QuerydslRepositorySupport implements PersonRepositoryCustom {
public PersonRepositoryImpl() {
super(Person.class);
}
#Override
public Optional<Person> findByEmail(String email) {
JPAQuery<Person> query = getQuerydsl()
.createQuery()
.from(QPerson.person)
.where(QPerson.person.email.equalsIgnoreCase(email))
.select(QPerson.person);
return query.fetch().stream().findFirst();
}
}

Spring Data JPA. How to get only a list of IDs from findAll() method

I have a very complicated model. Entity has a lot relationship and so on.
I try to use Spring Data JPA and I prepared a repository.
but when I invoke a method findAll() with specification for the object a have a performance issue because objects are very big. I know that because when I invoke a method like this:
#Query(value = "select id, name from Customer ")
List<Object[]> myFindCustomerIds();
I didn't have any problems with performance.
But when I invoke
List<Customer> findAll();
I had a big problem with performance.
The problem is that I need to invoke findAll method with Specifications for Customer that is why I cannot use method which returns a list of arrays of objects.
How to write a method to finding all customers with specifications for Customer entity but which returns only an IDs.
like this:
List<Long> findAll(Specification<Customer> spec);
I cannot use in this case pagination.
Please help.
Why not using the #Query annotation?
#Query("select p.id from #{#entityName} p")
List<Long> getAllIds();
The only disadvantage I see is when the attribute id changes, but since this is a very common name and unlikely to change (id = primary key), this should be ok.
This is now supported by Spring Data using Projections:
interface SparseCustomer {
String getId();
String getName();
}
Than in your Customer repository
List<SparseCustomer> findAll(Specification<Customer> spec);
EDIT:
As noted by Radouane ROUFID Projections with Specifications currently doesn't work beacuse of bug.
But you can use specification-with-projection library which workarounds this Spring Data Jpa deficiency.
I solved the problem.
(As a result we will have a sparse Customer object only with id and name)
Define their own repository:
public interface SparseCustomerRepository {
List<Customer> findAllWithNameOnly(Specification<Customer> spec);
}
And an implementation (remember about suffix - Impl as default)
#Service
public class SparseCustomerRepositoryImpl implements SparseCustomerRepository {
private final EntityManager entityManager;
#Autowired
public SparseCustomerRepositoryImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public List<Customer> findAllWithNameOnly(Specification<Customer> spec) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> tupleQuery = criteriaBuilder.createTupleQuery();
Root<Customer> root = tupleQuery.from(Customer.class);
tupleQuery.multiselect(getSelection(root, Customer_.id),
getSelection(root, Customer_.name));
if (spec != null) {
tupleQuery.where(spec.toPredicate(root, tupleQuery, criteriaBuilder));
}
List<Tuple> CustomerNames = entityManager.createQuery(tupleQuery).getResultList();
return createEntitiesFromTuples(CustomerNames);
}
private Selection<?> getSelection(Root<Customer> root,
SingularAttribute<Customer, ?> attribute) {
return root.get(attribute).alias(attribute.getName());
}
private List<Customer> createEntitiesFromTuples(List<Tuple> CustomerNames) {
List<Customer> customers = new ArrayList<>();
for (Tuple customer : CustomerNames) {
Customer c = new Customer();
c.setId(customer.get(Customer_.id.getName(), Long.class));
c.setName(customer.get(Customer_.name.getName(), String.class));
c.add(customer);
}
return customers;
}
}
Unfortunately Projections does not work with specifications. JpaSpecificationExecutor return only a List typed with the aggregated root managed by the repository ( List<T> findAll(Specification<T> var1); )
An actual workaround is to use Tuple. Example :
#Override
public <D> D findOne(Projections<DOMAIN> projections, Specification<DOMAIN> specification, SingleTupleMapper<D> tupleMapper) {
Tuple tuple = this.getTupleQuery(projections, specification).getSingleResult();
return tupleMapper.map(tuple);
}
#Override
public <D extends Dto<ID>> List<D> findAll(Projections<DOMAIN> projections, Specification<DOMAIN> specification, TupleMapper<D> tupleMapper) {
List<Tuple> tupleList = this.getTupleQuery(projections, specification).getResultList();
return tupleMapper.map(tupleList);
}
private TypedQuery<Tuple> getTupleQuery(Projections<DOMAIN> projections, Specification<DOMAIN> specification) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<DOMAIN> root = query.from((Class<DOMAIN>) domainClass);
query.multiselect(projections.project(root));
query.where(specification.toPredicate(root, query, cb));
return entityManager.createQuery(query);
}
where Projections is a functional interface for root projection.
#FunctionalInterface
public interface Projections<D> {
List<Selection<?>> project(Root<D> root);
}
SingleTupleMapper and TupleMapper are used to map the TupleQuery result to the Object you want to return.
#FunctionalInterface
public interface SingleTupleMapper<D> {
D map(Tuple tuple);
}
#FunctionalInterface
public interface TupleMapper<D> {
List<D> map(List<Tuple> tuples);
}
Example of use :
Projections<User> userProjections = (root) -> Arrays.asList(
root.get(User_.uid).alias(User_.uid.getName()),
root.get(User_.active).alias(User_.active.getName()),
root.get(User_.userProvider).alias(User_.userProvider.getName()),
root.join(User_.profile).get(Profile_.firstName).alias(Profile_.firstName.getName()),
root.join(User_.profile).get(Profile_.lastName).alias(Profile_.lastName.getName()),
root.join(User_.profile).get(Profile_.picture).alias(Profile_.picture.getName()),
root.join(User_.profile).get(Profile_.gender).alias(Profile_.gender.getName())
);
Specification<User> userSpecification = UserSpecifications.withUid(userUid);
SingleTupleMapper<BasicUserDto> singleMapper = tuple -> {
BasicUserDto basicUserDto = new BasicUserDto();
basicUserDto.setUid(tuple.get(User_.uid.getName(), String.class));
basicUserDto.setActive(tuple.get(User_.active.getName(), Boolean.class));
basicUserDto.setUserProvider(tuple.get(User_.userProvider.getName(), UserProvider.class));
basicUserDto.setFirstName(tuple.get(Profile_.firstName.getName(), String.class));
basicUserDto.setLastName(tuple.get(Profile_.lastName.getName(), String.class));
basicUserDto.setPicture(tuple.get(Profile_.picture.getName(), String.class));
basicUserDto.setGender(tuple.get(Profile_.gender.getName(), Gender.class));
return basicUserDto;
};
BasicUserDto basicUser = findOne(userProjections, userSpecification, singleMapper);
I hope it helps.

Resources