如何将 Java 记录用作 ModelMapper 的 DTO?
How can I use Java records as DTO with ModelMapper?
我正在重构我的代码。我想在我的 DTO 中使用 java 记录而不是 java class。要将 DTO 转换为实体,我使用的是 ModelMapper(版本 2.3.5)。当我尝试获取有关用户的信息时(调用方法 co convert Entity to DTO)我收到此错误。
Failed to instantiate instance of destination xxx.UserDto. Ensure that xxx.UserDto has a non-private no-argument constructor.
这是我的代码。
public record UserDto(String firstName,
String lastName,
String email,
String imageUrl) {}
@RestController
public class UserController {
@Autowired
private UserRepository userRepository;
@Autowired
private ModelMapper modelMapper;
@GetMapping("/user/me")
@PreAuthorize("hasRole('USER')")
public UserDto getCurrentUser(@CurrentUser UserPrincipal userPrincipal) {
return convertToDto(userRepository.findById(userPrincipal.getId())
.orElseThrow(() -> new ResourceNotFoundException("User", "id", userPrincipal.getId())));
}
private UserDto convertToDto(User user) {
UserDto userDto = modelMapper.map(user, UserDto.class);
return userDto;
}
private User convertToEntity(UserDto userDto) throws Exception {
User post = modelMapper.map(userDto, User.class);
return post;
}
}
编辑:更新到版本2.3.8
没有帮助!
record
是 Java 14 中的预览功能,因此我建议您不要在生产中使用它。其次,它不模仿 java bean。
如果有字段,record
没有默认的无参数构造函数。如果您编写了一个无参数构造函数,则必须将调用委托给所有参数构造函数,并且由于所有字段都是 final
您只能设置一次。所以你有点被困在那里。见 JEP 359:
It is not a goal to declare "war on boilerplate"; in particular, it is not a goal to address the problems of mutable classes using the JavaBean naming conventions.
今天可行的替代方法是使用 Lombok
。 UserDto
使用 Lombok 的示例:
@NoArgsConstructor
@AllArgsConstructor
@Data
public class UserDto {
private String firstName;
private String lastName;
private String email;
private String imageUrl;
}
记录的字段是最终的,因此必须通过构造函数设置。许多框架会在事后欺骗并使用各种技巧来修改最终字段,但这些对记录不起作用。如果要实例化记录,则必须在构造时提供所有字段值。
框架可能需要一点时间来了解记录。 “调用无参数构造函数,然后设置字段”的旧模型不适用于记录。一些框架已经能够处理这个问题(例如,“构造函数注入”),而其他框架还没有。但是,我们希望框架能够尽快实现。
正如评论者所说,您应该鼓励您的框架提供商支持他们。不难。
我正在重构我的代码。我想在我的 DTO 中使用 java 记录而不是 java class。要将 DTO 转换为实体,我使用的是 ModelMapper(版本 2.3.5)。当我尝试获取有关用户的信息时(调用方法 co convert Entity to DTO)我收到此错误。
Failed to instantiate instance of destination xxx.UserDto. Ensure that xxx.UserDto has a non-private no-argument constructor.
这是我的代码。
public record UserDto(String firstName,
String lastName,
String email,
String imageUrl) {}
@RestController
public class UserController {
@Autowired
private UserRepository userRepository;
@Autowired
private ModelMapper modelMapper;
@GetMapping("/user/me")
@PreAuthorize("hasRole('USER')")
public UserDto getCurrentUser(@CurrentUser UserPrincipal userPrincipal) {
return convertToDto(userRepository.findById(userPrincipal.getId())
.orElseThrow(() -> new ResourceNotFoundException("User", "id", userPrincipal.getId())));
}
private UserDto convertToDto(User user) {
UserDto userDto = modelMapper.map(user, UserDto.class);
return userDto;
}
private User convertToEntity(UserDto userDto) throws Exception {
User post = modelMapper.map(userDto, User.class);
return post;
}
}
编辑:更新到版本2.3.8
没有帮助!
record
是 Java 14 中的预览功能,因此我建议您不要在生产中使用它。其次,它不模仿 java bean。
record
没有默认的无参数构造函数。如果您编写了一个无参数构造函数,则必须将调用委托给所有参数构造函数,并且由于所有字段都是 final
您只能设置一次。所以你有点被困在那里。见 JEP 359:
It is not a goal to declare "war on boilerplate"; in particular, it is not a goal to address the problems of mutable classes using the JavaBean naming conventions.
今天可行的替代方法是使用 Lombok
。 UserDto
使用 Lombok 的示例:
@NoArgsConstructor
@AllArgsConstructor
@Data
public class UserDto {
private String firstName;
private String lastName;
private String email;
private String imageUrl;
}
记录的字段是最终的,因此必须通过构造函数设置。许多框架会在事后欺骗并使用各种技巧来修改最终字段,但这些对记录不起作用。如果要实例化记录,则必须在构造时提供所有字段值。
框架可能需要一点时间来了解记录。 “调用无参数构造函数,然后设置字段”的旧模型不适用于记录。一些框架已经能够处理这个问题(例如,“构造函数注入”),而其他框架还没有。但是,我们希望框架能够尽快实现。
正如评论者所说,您应该鼓励您的框架提供商支持他们。不难。