Reputation: 2721
I have an issue for circular reference calling. Even if I set true to this option, I cannot fix my issue. How can I fix it? Here are my code snippets which are shown below step by step.
Here is my application.properties file shown below.
...
spring.main.allow-circular-references= true
...
Here is my error message shown below.
Description:
The dependencies of some of the beans in the application context form a cycle:
userController (field com.photoapp.users.service.UserService com.photoapp.users.controller.UserController.userService)
┌─────┐
| userServiceImpl defined in file [C:\Users\de\Desktop\sts-4.9.0.RELEASE\workspace\PhotoAppApiUsers\target\classes\com\photoapp\users\service\impl\UserServiceImpl.class]
↑ ↓
| webSecurity defined in file [C:\Users\de\Desktop\sts-4.9.0.RELEASE\workspace\PhotoAppApiUsers\target\classes\com\photoapp\users\security\WebSecurity.class]
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
Here is my userServiceImpl class
@Service
@Transactional
public class UserServiceImpl implements UserService{
UserMapper userMapper;
UserRepository userRepository;
PasswordEncoder passwordEncoder;
@Autowired
public UserServiceImpl(UserMapper userMapper,UserRepository userRepository,PasswordEncoder passwordEncoder) {
super();
this.userMapper = userMapper;
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
public UserDto createUser(UserDto userDetails) {
// TODO Auto-generated method stub
userDetails.setUserId(UUID.randomUUID().toString());
User user = userMapper.userDtotoUser(userDetails);
String encodedPassword = passwordEncoder.encode(userDetails.getPassword());
user.setEncryptedPassword(encodedPassword);
userRepository.save(user);
UserDto returnValue = userMapper.userToUserDto(user);
return returnValue;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
User user = userRepository.findByEmail(username);
if(user == null)
throw new UsernameNotFoundException(username);
return new org.springframework.security.core.userdetails.User(user.getEmail(),
user.getEncryptedPassword(),
true, true, true, true, new ArrayList<>());
}
@Override
public UserDto getUserDetailsByEmail(String email) {
User user = userRepository.findByEmail(email);
if(user == null)
throw new UsernameNotFoundException(email);
UserDto returnValue = userMapper.userToUserDto(user);
return returnValue;
}
@Override
public UserDto getUserByUserId(String userId) {
// TODO Auto-generated method stub
return null;
}
}
Here is my WebSecurity class
@Configuration
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private Environment environment;
private UserService userService;
@Autowired
public WebSecurity(Environment environment, UserService userService) {
super();
this.environment = environment;
this.userService = userService;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.csrf().disable();
http.authorizeRequests().antMatchers("/users").hasIpAddress(environment.getProperty("gateway.ip"))
.and()
.addFilter(getAuthenticationFilter());
http.headers().frameOptions().disable();
}
private AuthenticationFilter getAuthenticationFilter() throws Exception{
AuthenticationFilter authenticationFilter = new AuthenticationFilter(userService, environment, authenticationManager());
//authenticationFilter.setAuthenticationManager(authenticationManager());
authenticationFilter.setFilterProcessesUrl(environment.getProperty("login.url.path"));
return authenticationFilter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
}
Upvotes: 0
Views: 8379
Reputation: 3889
If you declare the bean factory method for the password encoder static
, i.e.
@Bean
public static PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
you make it clear that the bean does not actually depend on anything that is injected into WebSecurity
. Then, you don't need to work with @Lazy
and the proxying it creates.
You may even be able to remove the property that allows circular references. But that depends on the whole rest of your application.
Upvotes: 1
Reputation: 2721
Here is my solution
public UserServiceImpl(UserMapper userMapper,UserRepository userRepository,@Lazy PasswordEncoder passwordEncoder) {
super();
this.userMapper = userMapper;
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
Upvotes: 1
Reputation: 9100
The error message is pretty clear. UserServiceImpl
depends on WebSecurity
which depends on UserServiceImpl
.
The dependency from WebSecurity
to UserServiceImpl
is necessary. That means you need to break the dependency from UserServiceImpl
to WebSecurity
. This is caused by the password encoder. You need to move that out of WebSecurity
. Maybe you can integrate it in UserServiceImpl
?
Upvotes: 0
Reputation: 4652
Try using @Lazy
public class WebSecurity extends WebSecurityConfigurerAdapter {
private Environment environment;
@Lazy
private UserService userService;
Reference: https://www.baeldung.com/spring-lazy-annotation
Upvotes: 0