In my Spring Boot project, I use the following map:
public void create(List<EmployeeRequest> request) {
final List<Employee> employees = request.stream()
.map(r -> new Employee(r.getName(),
r.getEmail(),
r.getCountry(),
r.getAge()))
.collect(Collectors.toList());
employeeRepository.saveAll(employees);
}
Here is the related classes:
public class EmployeeRequest {
String name;
String email;
String country;
int age;
}
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String country;
private int age;
public Employee(String name, String email, String country, int age) {
this.name = name;
this.email = email;
this.country = country;
this.age = age;
}
As the field names are the same, I tried to make a mapping directly using class instead of each field as shown below, but I make a mistake I think related to Functional method:
public void create(List<EmployeeRequest> request) {
final List<Employee> employees = request.stream()
.map(Employee::new) // Cannot resolve constructor 'Employee'
.collect(Collectors.toList());
employeeRepository.saveAll(employees);
}
But I am getting "Cannot resolve constructor 'Employee'" error on the following line:
.map(Employee::new)
So, is it possible to make this kind of mapping via Java stream?
Update: I moved toEntity()
method to a separate class a shown below, but get error if I don't make it static:
public class EmployeeRequestMapper {
public Employee mapToEntity(EmployeeRequest request) {
return new Employee(request.getName(), request.getEmail(), request.getCountry(), request.getAge());
}
}
And I use it as shown below:
public void create(List<EmployeeRequest> request) {
final List<Employee> employees = request.stream()
.map(EmployeeRequestMapper::mapToEntity)
.collect(Collectors.toList());
employeeRepository.saveAll(employees);
}
So, do I have to make mapToEntity
static or is there a proper way using that method in my service?
CodePudding user response:
I assume that it's a rest API and your Request class functions as a DTO. So what I like to do is just create a method toEntity
in the Request/DTO class and then I have a pretty easy mapping and the responsibility is on the Request/DTO side. In your case it would look something like this:
public class EmployeeRequest {
String name;
String email;
String country;
int age;
public Employee toEntity() {
return new Employee(this.name, this.email, this.country, this.age);
}
}
Now you can use it like this:
public void create(List<EmployeeRequest> request) {
final List<Employee> employees = request.stream()
.map(EmployeeRequest::toEntity)
.collect(Collectors.toList());
employeeRepository.saveAll(employees);
}
But if you want to make your way work you could create a constructor in Employee
that just takes EmployeeRequest
. But I don't like this solution because I think the Entity should not need to know about the other class.
But in case you don't care about this, just add a constructor in your Employee:
public Employee(EmployeeRequest request) {
this.name = request.getName();
this.email = request.getEmail();
this.country = request.getCountry();
this.age = request.getAge();
}
CodePudding user response:
map
accepts a function that is supposed to receive the EmployeeRequest
and returns back the instance of Employee
Something like this:
Employee createEmployeeFromRequest(EmployeeRequest request) {...}
So if you want to use a constructor, you should create one that maps the request to the Employee:
public class Employee {
public Employee(EmployeeReqeuest request) {
...
}
}
Then you can map with Employee::new
which is a method reference here - it "refers" this constructor - without that it won't work