Парень попросил меня помочь ему устранить странную ошибку в службе безопасности его весеннего загрузочного приложения, после нескольких часов пути мне удалось исправить ошибку, но я действительно понятия не имею, что произойдет.Обратите внимание на следующие классы:
Класс User
: информация о пользователе в базе данных
@Getter
@Setter
@Entity
@Table(name = "user", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_name"})})
public class User extends DateAudit implements Serializable {
// Id, username, password and constructor... not really important
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> role = new HashSet<>();
}
Класс UserDto
: реализация интерфейса Spring для управления учетными данными пользователя
@Getter
@Setter
@AllArgsConstructor
public class UserDto implements org.springframework.security.core.userdetails.UserDetails {
private long id;
private String Username;
@JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
public static UserDto create(User user) {
List<GrantedAuthority> authorities = user.getRole().stream()
.map(role -> new SimpleGrantedAuthority(role.getName().name())).collect(Collectors.toList());
return new UserDto(user.getId(), user.getUserName(), user.getPassword(), authorities);
}
// implement interface's methods, only getters, not important
}
Class CustomUserService
: служба аутентификации
@Service
public class CustomUserService implements org.springframework.security.core.userdetails.UserDetailsService {
private final UserRepository userRepository;
@Autowired
public CustomUserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
@Transactional
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
User user = userRepository.findUserByUserName(userName).orElseThrow(() -> {
return null;
});
return UserDto.create(user);
}
}
Полный исходный код можно найти здесь (это всего лишь простое приложение с весенней загрузкой с некоторыми классами): https://github.com/raizo000/admin_project (его репозиторий использует встроенный tomcatЯ пытался изменить его на причал, но это не причина)
Когда я запускаю код первый раз с этими 3 классами.Строка
return UserDto.create(user);
Дайте мне NoClassDefFoundError
:
WARN 7252 --- [qtp223566397-22] org.eclipse.jetty.server.HttpChannel : /login
java.lang.NoClassDefFoundError: com/example/admin/dto/UserDto
at com.example.admin.services.CustomUserService.loadUserByUsername(CustomUserService.java:28) ~[classes/:na]
at com.example.admin.services.CustomUserService$$FastClassBySpringCGLIB$$b9234a59.invoke(<generated>) ~[classes/:na]
....
Я проверил файл JAR, в правом каталоге есть файл UserDto.class.
Удалите @Transactional
, помогите исправить ошибку, но вызвайте еще одну ленивую ошибку инициализации, и я в итоге быстро заменю fetch = FetchType.LAZY
в User
классе на fetch = FetchType.EAGER
.
Почему добавление Transactional может вызватьa NoClassDefFoundError?Является ли удаление Transactional правильным решением или есть лучшее решение?