4

我正在重构我的代码。我想在我的 DTO 中使用 java 记录而不是 java 类。要将 DTO 转换为实体,我使用的是 ModelMapper(版本 2.3.5)。当我尝试获取有关用户的信息(调用方法将实体转换为 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没有帮助!

4

2 回答 2

12

记录的字段是最终的,因此必须通过构造函数进行设置。无论如何,许多框架会作弊并使用各种技巧来修改最终字段,但这些对记录不起作用。如果要实例化记录,则必须在构建时提供所有字段值。

框架可能需要一些时间来了解记录。“调用无参数构造函数,然后设置字段”的旧模型不适用于记录。一些框架已经能够处理这个问题(例如,“构造函数注入”),而其他框架还没有。但是,我们预计框架将很快到达那里。

正如评论者所说,您应该鼓励您的框架提供者支持他们。这并不难。

于 2020-06-20T14:14:27.443 回答
2

record是 Java 14 中的预览功能,因此我建议您不要在生产中使用它。其次,它不模仿java bean。

record如果有字段,则没有默认的无参数构造函数。如果您编写了无参数构造函数,则必须将调用委托给所有 args 构造函数,并且由于所有字段都是final您只能设置一次。所以你有点卡在那里。见JEP 359

向样板宣战不是目标;特别是,使用 JavaBean 命名约定来解决可变类的问题并不是目标。

今天可行的替代方法是使用Lombok. UserDto使用龙目岛的例子:

@NoArgsConstructor
@AllArgsConstructor
@Data
public class UserDto {
    private String firstName;
    private String lastName;
    private String email;
    private String imageUrl;
}
于 2020-06-18T17:21:29.773 回答