Concurrency issues on #Autowire HttpServletRequest request in Spring #Controller,#Service and #Component - java

As i consume a lot of data in httpservletrequest header and set a lot of values in request attribute in service class, I'm not sure if this would cause thread safety issues, I looked over the web if autowiring httpservlet request would cause threadsafety issues and i got mixed opinion
Following are the places where i autowire httpservletrequest
#RestController
Public class UserController {
#Autowire
HttpServletRequest httpServletRequest;
#Autowire
IAMService iamservice;
#PostMapping("/addUser")
public String addUser(#RequestBody UserDto userdto){
return iamservice.addUser(userdto);
}
}
#Service
Public Class IAMService {
#Autowire
HttpServletRequest httpServletRequest;
#Autowire
UserDao userDao;
public String addUser(UserDto userdto){
Long primaryKey = userDao.save(userdto,httpServletRequest.getHeader("loggedInUserId"));
httpServletRequest.setAttribute("userPrimaryKey",primaryKey);
return "User is added successfully";
}
}

We should not #Autowire HttpServletRequest. Consider modifying your code as below to have valid usage of request object and avoid thread-safety issues-
#RestController
Public class UserController {
#Autowire
IAMService iamservice;
#PostMapping("/addUser")
public String addUser(#RequestBody UserDto userdto, HttpServletRequest httpServletRequest){
return iamservice.addUser(userdto, httpServletRequest);
}
}
#Service
Public Class IAMService {
#Autowire
UserDao userDao;
public String addUser(UserDto userdto, HttpServletRequest httpServletRequest){
Long primaryKey = userDao.save(userdto,httpServletRequest.getHeader("loggedInUserId"));
httpServletRequest.setAttribute("userPrimaryKey",primaryKey);
return "User is added successfully";
}
}

Related

#Autowired service bean in Controller Class won't recognize the methods

I have this classes:
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Autowired
private EntityManager entityManager;
#Override
public UserDetails loadUserByUsername( String username) throws UsernameNotFoundException {
Optional<User> userOptional = userRepository.findUserByUsername(username);
User user = userOptional.orElseThrow(
()->new UsernameNotFoundException("Username not found in the database")
);
return new MyUserDetails(user);
}
public void saveUser(User user){
User newUser=new User();
newUser.setUsername(user.getUsername());
newUser.setPassword(passwordEncoder.encode(user.getPassword()));
newUser.setEnabled(true);
newUser.setRoles(List.of(entityManager.find(Role.class,1)
));
userRepository.save(newUser);
}
public void deleteUser(User user){
userRepository.delete(user);
}
public UserDetails getCurrentlyLoggedUser(Authentication authentication){
Object principal = authentication.getPrincipal();
if(principal instanceof UserDetails){
String username=((User) principal).getUsername();
UserDetails loggedUser = loadUserByUsername(username);
return loggedUser;
}
return null;
}}
#Controller
#RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
#Autowired
private final UserDetailsService userDetailsService;
#GetMapping("/orderlist")
public String showOrdeList(Model model, #AuthenticationPrincipal Authentication authentication){
userDetailsService.getCurrentlyLoggedUser
}
}
I want to know why the methods from UserDetailsServiceImpl class won't show up in the controller...
I can acces only the methods from the interface, but not the ones implemented besides them.
I tried to use qualifiers, and even made a config class to instantiate the impl class when injecting the bean by interface.
#Configuration
public class OrderConfig {
#Bean("userDetailsService")
public UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
Can anyone tell me what I'm doing wrong?
Methods defined in UserDetailsServiceImpl but not in UserDetailsService aren't accessible because you're injecting your service by interface UserDetailsService and compiler doesn't know which implementation will be injected in runtime.
So, you need to define your own interface with all methods that you want to expose or inject your service by class.
#Autowired
private final UserDetailsServiceImpl userDetailsService;
I would recommend a custom interface that extends UserDetailsService and injecting your service using your custom interface.

DAO method is not being mocked

I have a UserDAO that has methods like add,delete,update,getUser and getUsers (to manipulate my database). I also have a Requestmapping that I want to test via Mockito. Here is everything relevant in terms of what I have:
The test:
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(value = UserController.class)
public class UserControllerTest
{
#Autowired
private MockMvc mockMvc;
#Mock
private UserDAO userDao;
#InjectMocks
private UserController userController;
#Before
public void setUp()
{
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(userController)
.build();
}
#Test
public void testGetAllUsersSuccess() throws Exception{
User s = new User();
List<User> users = Arrays.asList(
new User(1,"somebody", "pass", "somebody#yahoo.com"),
new User(2, "sam", "mypass", "tom#hotmail.com"));
doReturn(users).when(userDao).getUsers();
mockMvc.perform(get("/userList"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].userID", is(1)))
.andExpect(jsonPath("$[0].name", is("somebody")))
.andExpect(jsonPath("$[0].password", is("pass")))
.andExpect(jsonPath("$[0].email", is("somebody#yahoo.com")))
.andExpect(jsonPath("$[1].userID", is(2)))
.andExpect(jsonPath("$[1].name", is("sam")))
.andExpect(jsonPath("$[1].password", is("mypass")))
.andExpect(jsonPath("$[1].email", is("tom#hotmail.com")));
verify(userDao, times(1)).getUsers();
verifyNoMoreInteractions(userDao);
}
}
UserController where I have my requestmapping:
#RestController
public class UserController {
/**
*
*
* #return list of all users
*/
#RequestMapping(value = "/userList", method = RequestMethod.GET)
public List<User> user() throws Exception {
UserDAO gettingUsers = new UserDAO();
return gettingUsers.getUsers();
}
}
the getUsers() method:
public List<User> getUsers(){
try(Session session = HibernateUtil.getSessionFactory().openSession()){
return session.createQuery("from User", User.class).getResultList();
}
}
PROBLEM: When I execute my test, a connection is made with the database (which is not what I want) instead of a fake instance of UserDAO that only returns the users list that I have made in mockito.
QUESTION: What should my code look like to be able to mock the userDAO method getUsers() such that it doesn't return the users from the database but instead returns the faked users list when I call it by requesting the get method of "/userList"?
UPDATE=
SOLUTION:
My new Controller:
#RestController
public class UserController {
private UserDAO userDAO;
public UserController (UserDAO userDAO)
{
this.userDAO = userDAO;
}
/**
*
*
* #return list of all users
*/
#GetMapping(value = "/Users", method = RequestMethod.GET)
public List<User> users() throws Exception {
return userDAO.getUsers();
}
}
Changes done in test:
//...
#MockBean
private UserDAO userDao;
....
when(userDao.getUsers()).thenReturn(users);
...//
Spring didn't find my userDAO Bean so I added the package name where I stored the bean in the ApplicationConfiguration class of mine. Doing this, Spring was able to inject the bean in the constructor.
The userDao mock is never set to the controller under test.
1) You don't want to use new to instantiate the UserDAO in your Controller :
UserDAO gettingUsers = new UserDAO();
You want to inject it as a Spring Bean.
Besides you also have to make the dependency visible because actually it is not settable from the unit test POV.
You could inject it in the constructor :
private UserDAO userDAO;
public UserController (UserDAO userDAO){
this.userDAO = userDAO;
}
2) You mock Spring bean in a running container with #MockBean from Spring Boot test not with #Mock from Mockito.

How can I inject #RequestBody object(value object) to Spring Service layer?

How can I inject #RequestBody object(value object) to Spring Service layer?
I want to Inject(Autowired)objects what come from request body values.
HelloController
#Autowired
UserService userService;
(….)
#GetMapping("/hello")
public String hello(
#RequestBody UserRequestBodyDto userDto,
HttpServletResponse response){
return null;
}
UserRequestBodyDto
#Data
public class UserRequestBodyDto{
private String name;
private String address;
}
UserServiceImpl
#Service
public class UserServiceImpl implements UserService{
#AutoWired
public UserServiceImpl(UserRequestBodyDto userDto){
(….)
}
}
In that case, how can I inject UserRequestBodyDto objects into service layer?
Add 'setUserDto' method to UserService is the best way?
or If
convert dto to entity is the best way to inject objets,
how can I manage many of same classes between dto class and entity class?
+a) In my opinion, make a RequestScopedBean is bad way.
ref: Spring: injecting #RequestBody into #Bean
Why you need to #AutoWired a request object? I seems completely unnecessary while doing operation with a request object cause, it will change on every new request.
So you can do operation with request object in the service layer method.
public UserServiceImpl(UserRequestBodyDto userDto){
(….)//do operation with userDto here.
}
Or, I you really need to #AutoWire the request object then declare UserRequestBodyDto userDto in service layer with #AutoWired annotation. And when the service layer method executes just set the values to this.userDto.
#Service
public class UserServiceImpl implements UserService{
#AutoWired
private UserRequestBodyDto userDto;
#AutoWired
public UserServiceImpl(UserRequestBodyDto userDto){
this.userDto = userDto;//Here, setting value of userDto to this.userDto
}
}

Spring #RestController with #RequestBody #Valid by default

Usually we write
#RestController
public class TestController {
#RequestMapping(value = "/test")
public String test2(#RequestBody #Valid TestClass req) {
return "test2";
}
}
But since it is a REST controller is it possible to configure Spring to use #RequestBody #Valid by default, so these annotations could be omitted?

How can I use a DAO inside a Controller in Spring MVC?

In a Spring MVC project I've a DAO class myproj.models.UserDAO:
#Repository
#Transactional
public class UserDAO {
// UserDAO methods ...
}
and I should use it inside a controller, say myproj.controllers.UserController:
#Controller
public class UserController {
// UserController methods ...
#RequestMapping(value="/{user}")
public String create(String user) {
// Here I want to use the UserDAO
// ...
}
}
How can I create an instance of the UserDAO object and use it inside a controller method?
You could try following
#Repository
#Transactional
public class UserDAO {
// UserDAO methods ...
}
Controller:
#Controller
public class UserController {
#Autowired //this will give you the reference to UserDAO
UserDAO userDao;
// UserController methods ...
#RequestMapping(value="/{user}")
public String create(String user) {
// Here I want to use the UserDAO
userDao.userDaoMethod();
// ...
}
}
For more information on #Autowired explore this
User Autowired annotation to inject a bean instance of your DAO:
#Controller
public class UserController {
#Autowired
UserDAO userDao;
#RequestMapping(value="/{user}")
public String create(String user) {
userDao.method();
}
}

Categories