How to mock ModelMapper for list in SpringBootTest using Junit and Mockito? - spring-boot

I have one API in which I am returning a list of DTO by mapping it with main entity object using model mapper
employeeList = employeeRepository.findAll();
employeeListPojos = employeeList.stream().map((emp) -> modelMapper.map(emp, EmployeeInfoPojo.class))
.collect(Collectors.toList());
I am trying to mock the model mapper in my test class but the same output is overriding in the test case
#ExtendWith(MockitoExtension.class)
public class EmployeeServiceTest {
#Mock
private EmployeeRepository employeeRepository;
#Mock
private ModelMapper modelMapper;
#InjectMocks
private EmployeesApiServiceImpl employeesApiService;
EmployeeEntity employee;
#BeforeEach
public void setup()
{
employee = EmployeeEntity.builder()
.id("1L")
.employeeName("Test employee")
.description("Dummy employee")
.build();
}
#DisplayName("Test Case For Getting The employee Object")
#Test
public void givenemployeeObject_whenGetemployeeHeader_thenReturnemployeeObject()
{
//given - precondition or setup
EmployeeEntity employee2 = employeeEntity.builder()
.id("2L")
.employeeName("Test employee 1")
.description("Dummy employee")
.build();
List<EmployeeEntity> employees = new ArrayList<EmployeeEntity>();
employees.add(employee);
employees.add(employee2);
BDDMockito.given(employeeRepository.findAll()).willReturn(employees);
employeeInfoPojo convertedPojo1 = employeeInfoPojo.builder()
.id("1L")
.employeeName("Test employee 2")
.description("Dummy employee")
.build();
EmployeeInfoPojo convertedPojo2 = employeeInfoPojo.builder()
.id("2L")
.employeeName("Test employee")
.description("Dummy employee")
.build();
List<EmployeeInfoPojo> employeesResult = new ArrayList<EmployeeInfoPojo>();
employeesResult.add(convertedPojo1);
employeesResult.add(convertedPojo2);
for(EmployeeInfoPojo co : employeesResult){
BDDMockito.when(modelMapper.map(any(),any()))
.thenReturn(co);
}
//when - action or behaviour need to be tested
List<EmployeeInfoPojo> result = employeesApiService.getemployeeList(null);
System.out.println(result);
//then - verify the output
Assertions.assertThat(result).isNotNull();
Assertions.assertThat(result.size()).isEqualTo(2);
}
}
Test case is passing but output of result is not correct the convertedPojo2 is overridden in both the entries of list.
Any suggestion how to mock ModelMapper that is used with list in Junit and Mockito.
Issue mostly in these lines of EmployeeServiceTest
for(EmployeeInfoPojo co : employeesResult){
BDDMockito.when(modelMapper.map(any(),any()))
.thenReturn(co);
}

The mock for modelMapper.map(...) will always return convertedPojo2 since you don't have any specific matcher in the for-loop. Each iteration of the for-loop will override the last mock method and hence the last mock will be used.
Instead of setting up the mock in a for-loop, add the specific mock mapping, e.g something like this:
when(modelMapper.map(eq(employee), eq(EmployeeInfoPojo.class)))
.thenReturn(convertedPojo1);
when(modelMapper.map(eq(employee2), eq(EmployeeInfoPojo.class)))
.thenReturn(convertedPojo2);
This will set up a mock for the mapper when employee is used as parameter, convertedPojo1 will be returned for employee2, convertedPojo2 will be returned

Related

#Before not setting up data during integration test

I am creating an integraiton test for a JpaRepository and the testcase fails with "Record not found with random value rand", as null is returned in the find results.
My test case:
#SpringBootTest
class JpatestsApplicationTests {
#Autowired
private JpaRepo jpaRepo;
#Before
void setup() {
FirstTable firstTable1 = new FirstTable();
firstTable1.setUid("x");
firstTable1.setRandom("rand");
jpaRepo.save(firstTable1);
}
#Test
void testFindByRandom() {
FirstTable f = jpaRepo.findByRandom("rand");//find by random value 'rand'
Assert.notNull(f, "Record not found with random value rand ");
}
The entity associated:
#Entity
#Table(name = "table1")
public class FirstTable {
#Id
#GeneratedValue
private String uid;
#Column
private String random;
And my Repository:
#Repository
public interface JpaRepo extends JpaRepository<FirstTable, Long> {
FirstTable findByRandom(String rand);
}
I am using h2 database.
Why is the result coming as null for findByRandom? Also please note that if I move the record saving part jpaRepo.save(firstTable1) to be within the test case (before the findByRandom("rand") is called, it gets passed.
Why wouldn't it work if I save the record in setup() method annotated with #Before ?
You have to add #Transactional on the top of your class.
#Transactional will cause your tests to execute within a test-managed transaction that will be rolled back after the test completes; code executed within the #Before method will be executed inside the test-managed transaction.
The latest version of spring-boot-test makes use of junit 5 and #Before is deprecated. It started working after changing to #BeforeAll with annotation of #TestInstance(TestInstance.Lifecycle.PER_CLASS) at the class level
My updated test class:
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class JpatestsApplicationTests {
#Autowired
private JpaRepo jpaRepo;
#BeforeAll
void setup() {
FirstTable firstTable1 = new FirstTable();
firstTable1.setUid("x");
firstTable1.setRandom("rand");
jpaRepo.save(firstTable1);
}
#Test
void testFindByRandom() {
FirstTable f = jpaRepo.findByRandom("rand");//find by random value 'rand'
Assert.notNull(f, "Record not found with random value rand ");
}
Chose BeforeAll over BeforeEach as I need to run it only once during execution of this class.
Reference: https://junit.org/junit5/docs/current/user-guide/

How to make DataJpaTest flush save automatically?

I have an Employee entity with the following column:
#Entity
class Employee {
#Column(name = "first_name", length = 14)
private String firstName;
and I have a Spring JPA Repository for it:
#Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
In test/resources/application.properties I have the following so that I use an in-memory h2 database with tables auto-generated:
spring.jpa.hibernate.ddl-auto=create
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
I was expecting this test to fail, since the firstName is longer than what is allowed:
#DataJpaTest
public class EmployeeRepositoryTest {
#Autowired
private EmployeeRepository employeeRepository;
#Test
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setFirstName("koraykoraykoray"); // 15 characters!
employeeRepository.save(employee);
}
}
And I was surprised to see this test was not failing, however the following does fail:
#DataJpaTest
public class EmployeeRepositoryTest {
#Autowired
private EmployeeRepository employeeRepository;
#Test
public void testMustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setFirstName("koraykoraykoray"); // 15 characters!
employeeRepository.save(employee);
employeeRepository.findAll();
}
}
with the stacktrace:
Caused by: org.h2.jdbc.JdbcSQLDataException: Value too long for column "FIRST_NAME VARCHAR(14)": "'koraykoraykoray' (15)"; SQL statement:
The only difference is the second test has the additional employeeRepository.findAll(); statement, which forces Hibernate to flush as far as I understand.
This does not feel right to me, I would much rather want the test to fail immediately for save.
I can also have
#Autowired
private TestEntityManager testEntityManager;
and call
testEntityManager.flush();
but again, this does not feel correct either.. How do I make this test fail without any workaround or additional statements?
The easiest option in your case is configure #Transactional annotation, forcing to send database all changes in your tests (it can be used only in specific ones):
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.jupiter.api.Assertions.assertThrows;
#Transactional(propagation = Propagation.NOT_SUPPORTED)
#DataJpaTest
public class EmployeeRepositoryTest {
#Autowired
private EmployeeRepository employeeRepository;
#Test
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("koraykoraykoray"); // 15 characters!
assertThrows(DataIntegrityViolationException.class, () -> {
employeeRepository.save(employee);
});
}
#Test
public void mustSaveFirstNameShorterThan14() {
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("koraykor"); // 8 characters!
employeeRepository.save(employee);
}
}
PD: I have added a simple Integer property as PK of Employee entity due to your repository definition.
You can see the results in the following picture:
You could use JpaRepository<T,ID> instead of CrudRepository<T,ID>. Something like:
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Integer>
Then you can use its saveAndFlush() method anywhere you need to send data immediately:
#Test
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setFirstName("koraykoraykoray"); // 15 characters!
employeeRepository.saveAndFlush(employee);
}
And in code where you would like to have optimization you still can use save() method.
Thanks doctore for your answer, I had the similar problem as OP and your solution has helped. I decided to dig a little and figure out why it works, should someone else have this problem.
With #DataJpaTest annotated test class, your class implicitly becomes #Transactional with default propagation type Propagation.REQUIRED. That means every test method is also #Transactional with same default configuration. Now, all CRUD methods in CrudRepository are also #Transactional, but it has nothing to do with #DataJpaTest - they are transactional due to implementation. Whoa, that's a lot of transactions!
As soon as you annotate your whole class (or just a test method) with #Transactional(propagation = Propagation.NOT_SUPPORTED), your test method(s) are no longer #Transactional. However, inner methods of your test method(s), that is, CRUD operations from CrudRepository, remain transactional, meaning that they will have their own transaction scopes. Because of that, they will be committed to database immediately after execution, because by default (in Spring Boot, which users HikariCP connection pool), auto commits are turned on. Auto commits happen after every SQL query. And thus tests pass as you'd expect.
I like to visualize things, so here is the visualization of the whole process:
I hope this was helpful. URLs from the diagram:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html#disable_auto_commit
https://github.com/brettwooldridge/HikariCP/blob/dev/src/main/java/com/zaxxer/hikari/HikariConfig.java#L126
https://dzone.com/articles/spring-boot-transactions-tutorial-understanding-tr (not from diagram, but explains transaction very well!)
The #Commit can do the job ( it was added since 4.2)
#Test
#Commit
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("koraykoraykoray"); // 15 characters!
assertThrows(DataIntegrityViolationException.class, () -> {
employeeRepository.save(employee);
});
}

Unit test POST API in spring-boot + kotlin + Junit

I'm pretty new to spring boot and kotlin. I've started with one basic app from net and writing unit test, but I'm getting following error:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: articleRepository.save(article) must not be null
Let me show you the code: Entity Class
#Entity
data class Article (
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
#get: NotBlank
val title: String = "",
#get: NotBlank
val content: String = ""
)
controller:
#PostMapping("/articles")
fun createNewArticle(#Valid #RequestBody article: Article) : Article {
return articleRepository.save(article)
}
Repository:
#Repository
interface ArticleRepository : JpaRepository<Article, Long>
Test File:
RunWith(SpringRunner::class)
#SpringBootTest
class KotlinDemoApplicationTests {
lateinit var mvc: MockMvc
#InjectMocks
lateinit var controller: ArticleController
#Mock
lateinit var respository: ArticleRepository
#Before
fun setup() {
MockitoAnnotations.initMocks(this)
mvc = MockMvcBuilders.standaloneSetup(controller).setMessageConverters(MappingJackson2HttpMessageConverter()).build()
}
#Test
fun createBlog() {
var article = Article(1, "Test", "Test Content")
var jsonData = jacksonObjectMapper().writeValueAsString(article)
mvc.perform(MockMvcRequestBuilders.post("/api/articles/").contentType(MediaType.APPLICATION_JSON).content(jsonData))
.andExpect(MockMvcResultMatchers.status().isOk)
.andDo(MockMvcResultHandlers.print())
.andReturn()
}
}
When I'm running this test file, getting error mentioned above.
Please help me with this.
The problem is your ArticleRepository mock.
While you correctly inject it into your Controller, you're not specifiying what a call to save should return. It therefore returns null, which is not allowed in Kotin because you specified it as non-optional.
Either you allow your controller's createNewArticle to return null, by adding a ?, that is changing its signature to
fun createNewArticle(#Valid #RequestBody article: Article) : Article? {...}
Or you set-up the mock so that it does not return null, but an article.
#Before
fun setup() {
MockitoAnnotations.initMocks(this)
...
`when`(respository.save(any())
.thenReturn(Article()) // creates a new article
}
(Alternatively, there's also Mockito's returnsFirstArg() in case you don't want to invoke the construtor.)
Note that using any() in this case will only work if you're using mockito-kotlin
If you don't want to use it, check this answer

How to write a RestController to update a JPA entity from an XML request, the Spring Data JPA way?

I have a database with one table named person:
id | first_name | last_name | date_of_birth
----|------------|-----------|---------------
1 | Tin | Tin | 2000-10-10
There's a JPA entity named Person that maps to this table:
#Entity
#XmlRootElement(name = "person")
#XmlAccessorType(NONE)
public class Person {
#Id
#GeneratedValue
private Long id;
#XmlAttribute(name = "id")
private Long externalId;
#XmlAttribute(name = "first-name")
private String firstName;
#XmlAttribute(name = "last-name")
private String lastName;
#XmlAttribute(name = "dob")
private String dateOfBirth;
// setters and getters
}
The entity is also annotated with JAXB annotations to allow XML payload in
HTTP requests to be mapped to instances of the entity.
I want to implement an endpoint for retrieving and updating an entity with a given id.
According to this answer to a similar question,
all I need to do is to implement the handler method as follows:
#RestController
#RequestMapping(
path = "/persons",
consumes = APPLICATION_XML_VALUE,
produces = APPLICATION_XML_VALUE
)
public class PersonController {
private final PersonRepository personRepository;
#Autowired
public PersonController(final PersonRepository personRepository) {
this.personRepository = personRepository;
}
#PutMapping(value = "/{person}")
public Person savePerson(#ModelAttribute Person person) {
return personRepository.save(person);
}
}
However this is not working as expected as can be verified by the following failing test case:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = RANDOM_PORT)
public class PersonControllerTest {
#Autowired
private TestRestTemplate restTemplate;
private HttpHeaders headers;
#Before
public void before() {
headers = new HttpHeaders();
headers.setContentType(APPLICATION_XML);
}
// Test fails
#Test
#DirtiesContext
public void testSavePerson() {
final HttpEntity<Object> request = new HttpEntity<>("<person first-name=\"Tin Tin\" last-name=\"Herge\" dob=\"1907-05-22\"></person>", headers);
final ResponseEntity<Person> response = restTemplate.exchange("/persons/1", PUT, request, Person.class, "1");
assertThat(response.getStatusCode(), equalTo(OK));
final Person body = response.getBody();
assertThat(body.getFirstName(), equalTo("Tin Tin")); // Fails
assertThat(body.getLastName(), equalTo("Herge"));
assertThat(body.getDateOfBirth(), equalTo("1907-05-22"));
}
}
The first assertion fails with:
java.lang.AssertionError:
Expected: "Tin Tin"
but: was "Tin"
Expected :Tin Tin
Actual :Tin
In other words:
No server-side exceptions occur (status code is 200)
Spring successfully loads the Person instance with id=1
But its properties do not get updated
Any ideas what am I missing here?
Note 1
The solution provided here is not working.
Note 2
Full working code that demonstrates the problem is provided
here.
More Details
Expected behavior:
Load the Person instance with id=1
Populate the properties of the loaded person entity with the XML payload using Jaxb2RootElementHttpMessageConverter or MappingJackson2XmlHttpMessageConverter
Hand it to the controller's action handler as its person argument
Actual behavior:
The Person instance with id=1 is loaded
The instance's properties are not updated to match the XML in the request payload
Properties of the person instance handed to the controller's action handler method are not updated
this '#PutMapping(value = "/{person}")' brings some magic, because {person} in your case is just '1', but it happens to load it from database and put to ModelAttribute in controller. Whatever you change in test ( it can be even empty) spring will load person from database ( effectively ignoring your input ), you can stop with debugger at the very first line of controller to verify it.
You can work with it this way:
#PutMapping(value = "/{id}")
public Person savePerson(#RequestBody Person person, #PathVariable("id") Long id ) {
Person found = personRepository.findOne(id);
//merge 'found' from database with send person, or just send it with id
//Person merged..
return personRepository.save(merged);
}
wrong mapping in controller
to update entity you need to get it in persisted (managed) state first, then copy desired state on it.
consider introducing DTO for your bussiness objects, as, later, responding with persisted state entities could cause troubles (e.g. undesired lazy collections fetching or entities relations serialization to XML, JSON could cause stackoverflow due to infinite method calls)
Below is simple case of fixing your test:
#PutMapping(value = "/{id}")
public Person savePerson(#PathVariable Long id, #RequestBody Person person) {
Person persisted = personRepository.findOne(id);
if (persisted != null) {
persisted.setFirstName(person.getFirstName());
persisted.setLastName(person.getLastName());
persisted.setDateOfBirth(person.getDateOfBirth());
return persisted;
} else {
return personRepository.save(person);
}
}
Update
#PutMapping(value = "/{person}")
public Person savePerson(#ModelAttribute Person person, #RequestBody Person req) {
person.setFirstName(req.getFirstName());
person.setLastName(req.getLastName());
person.setDateOfBirth(req.getDateOfBirth());
return person;
}
The issue is that when you call personRepository.save(person) your person entity does not have the primary key field(id) and so the database ends up having two records with the new records primary key being generated by the db. The fix will be to create a setter for your id field and use it to set the entity's id before saving it:
#PutMapping(value = "/{id}")
public Person savePerson(#RequestBody Person person, #PathVariable("id") Long id) {
person.setId(id);
return personRepository.save(person);
}
Also, like has been suggested by #freakman you should use #RequestBody to capture the raw json/xml and transform it to a domain model. Also, if you don't want to create a setter for your primary key field, another option may be to support an update operation based on any other unique field (like externalId) and call that instead.
For updating any entity the load and save must be in same Transaction,else it will create new one on save() call,or will throw duplicate primary key constraint violation Exception.
To update any we need to put entity ,load()/find() and save() in same transaction, or write JPQL UPDATE query in #Repository class,and annotate that method with #Modifying .
#Modifying annotation will not fire additional select query to load entity object to update it,rather presumes that there must be a record in DB with input pk,which needs to update.

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