Autowired Service is null in specific methods - java

I have a spring boot application where, suddenly, the autowired services returning null at specific methods.
Here is a code snippet for the controller:
#RestController
#RequestMapping("/user")
#CrossOrigin
public class UserManagementController {
#Autowired
private UserService userService;
...
#PostMapping("/register")
private GameInfo register(#RequestBody UserInfo userInfo) {
User user = new User();
...
user.setUsername("user-" + userService.count());
...
return gameController.getGameInfo(user);
}
...
#PostMapping("/statistics")
public StatisticsInfo statistics(
#RequestParam(name = "username", required = true) String username,
Authentication authentication) {
User user = userService.findByUsername(username);
...
}
}
The userService is null in the first method, and works fine in the second one.
UPDATE:
Here is the code snippet for the UserService which is null in "register" method.
#Service
public class UserService implements UserDetailsService {
#Autowired
private UserRepository repository;
public long count() {
return repository.count();
}
...
}
The userService has normal CRUD methods.
Kindly note that the userService is null, so a NullPointerException is thrown when I invoke any of its methods.
UPDATE 2:
I have created a clone of the faulty method register and named it dontRegister, this magically solved the issue of register but introduced the same issue in the new method.
I don't understand the logic behind this, as it seems that I always need to add one extra unused method.
I'll keep the question open until maybe someone comes up with an explanation.

Your register method is private, make it public. Logically it should be public anyway as it is called from outside the package.

Related

How to resolve the concurrency problem in a REST service in Spring Boot project?

I'm working at a simple Spring Boot project, and I want to create a resource in the database. So the client will send a POST request with a body that contains these information: name, age, email, password. The app has a RestController a Service and a DAO that communicate with the database using Spring Data JPA. I want to know how to resolve the concurrency problem for this POST request.
Controller:
#RestController
#RequestMapping(value = "/api/v1")
public class UserApi {
#Autowired
private UserService userService;
#PostMapping("/users")
public User createUser(#RequestBody User user) {
return userService.createUser(user);
}
}
Service interface:
public interface UserService {
User createUser(User user);
}
Service class:
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Override
public User createUser(User user) {
return userRepository.save(user);
}
}
DAO:
public interface UserRepository extends JpaRepository<User, Integer> {
}
So it is a simple POST request to create a user in the database. And I want to know how to resolve the concurrency problem. For example if 2 users call the createUser method in the same time and they have the same email address.
And the second question is why it is recommended to have an interface for service layer and then a class that implement this interface and to inject the interface into the constructor? I see this design on many projects. Why it isn't recommend to have just a class, without an interface and inject the class in the constructor?
Thank you in advance!

NullPointerException when testing service containing mocked JPA repository [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 2 years ago.
I am working on my first spring boot project and I am having trouble with testing my class as a Mockito newbie.
I need to check that the findAndUpdateUser method below update User entity fields correctly :
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepo;
public User findUser(String id) {
return userRepo.findById(id);
}
public User findAndUpdateUser(String id) {
User foundUser = findUser(id);
//some update on foundUser fields
return foundUser;
}
}
To test, I need to mock entity bean because I don't have DB locally. Here is my test class :
#RunWith(MockitoJUnitRunner.class)
public class UpdateFieldsTest {
#Mock
private UserRepository userRepo;
#Test
public void test1() {
User user = new User();
user.setId("testId");
//setting some other user fields
Mockito.when(userRepo.findById("testId")).thenReturn(user);
UserServiceImpl userService = new userServiceImpl();
User returnedUser = userService.findAndUpdateUser("testId");
//Checking if user field values are updated after findAndUpdate call
Assert.xxx
//other asserts
}
}
But this code throw me some NullPointerException on method call. I even tried to mock findUser method but I still have error...
Am I having a bad approach ? How should I test my method ?
Any help is welcomed
Thanks all
using this instantiation UserServiceImpl userService = new userServiceImpl(); make the UserRepo null;
you are using mockito, so you can use
#InjectMocks
private UserServiceImpl; and delete the instastiation line.
Mocks won't magicly appear inside of your object. You need to inject them manually. In you test, inside of the userService, the userRepo will be null. You inject dependancies either by constructor or by setter. It would look like this in your test:
UserServiceImpl userService = new userServiceImpl(userRepo);
Or
UserServiceImpl userService = new userServiceImpl();
userService.setUserRepo(userRepo);

Can't consume rest service

I want to create two spring-boot projects which communicate via rest calls. The first one contains the UI part with loginForm. The second project should communicate with the DB and should fetch the information about the user and then send it back to the UI.
The service project contains two modules: data module and impl module. The data project should contain the common data shared between the UI and the service project. It should be only a jar which I will add as a dependency in the UI project and the impl module in the service project.
The impl module should contain entities, repositories, restcontrollers and a service layer containing the real back-end logic of the application. I have already created the UI project but I have problems with the service. In the data module I have created the classes with the user information in a package org.tu.userdata. In the service impl I have an userController like this:
package org.tu.userserviceimpl.controller;
#RestController
#RequestMapping("/user")
public class UserController {
private final UserAuthenticationService userService;
#Autowired
public UserController(UserAuthenticationService userService) {
this.userService = userService;
}
#PostMapping(value = { "/logUser" })
public UserDto logUser(#RequestBody AuthenticateUserDto authenticateUserDto) throws Exception {
return userService.logUser(authenticateUserDto);
}
#PostMapping(value = { "/register" })
public UserDto register(#RequestBody RegisterUserDto registerUserDto) throws Exception {
return userService.registerUser(registerUserDto);
}
}
It injects the UserAuthenticationService which is an interface implemented like this:
package org.tu.userserviceimpl.service.impl;
#Service
public class UserAuthenticationServiceImpl implements UserAuthenticationService {
private final UserRepository userRepository;
#Autowired
public UserAuthenticationServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public UserDto registerUser(RegisterUserDto registerUserDto) throws AuthenticationException {
return new UserDto();
}
#Override
public UserDto logUser(AuthenticateUserDto authenticateUserDto)
throws UserPrincipalNotFoundException, AuthenticationException {
return new UserDto();
}
}
the UserRepository:
package org.tu.userserviceimpl.repository;
#Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
UserEntity findByUsername(String username);
boolean existsByUsername(String username);
boolean existsByEmail(String email);
}
and an application class:
package org.tu.userserviceimpl;
#SpringBootApplication
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
When I run it I get:
*************************** APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in
org.tu.userserviceimpl.service.impl.UserAuthenticationServiceImpl
required a bean of type
'org.tu.userserviceimpl.repository.UserRepository' that could not be
found.
I thought that's strange because the UserRepository should be visible there since its a directory below the application class. To solve this I added a ComponentScan annotation on the application class:
#ComponentScan("org.tu.userserviceimpl.repository")
After that the project builds and deploys fine but I cannot access it. I got an 404 error. I even added an method like this one in the UserController just to troubleshoot it:
#GetMapping("/hello")
public String hello() {
return "hello";
}
But still cannot access it. The application is deployed on port 8082 but when I try to access "http://localhost:8082/user/hello" I cannot. After that I tried to remove the code in the UserAuthenticationServiceImpl which injects the UserRepository and I removed the componentScan annotation as well. After this code removal I was able to reach "http://localhost:8082/user/hello" and I got the message "hello" there. This means that the problem is somewhere in the Repository. Then I tried to add:
#EnableJpaRepositories("org.tu.userserviceimpl.repository")
#EntityScan("org.tu.userserviceimpl.entity")
on top of the application class and I added the code which injects the repository in the UserAuthenticationServiceImpl again. This time the outcome was a different error:
Parameter 0 of constructor in org.tu.userserviceimpl.service.impl.UserAuthenticationServiceImpl required a bean named 'entityManagerFactory' that could not be found.
I deleted the EntityScan annotation but the result was the same. Any ideas? What I am doing wrong?
I uploaded almost the same project in github: https://github.com/lei-gustavson/user-service.git
You have already created an argument based constructor in UserAuthenticationServiceImpl .
as below:
public UserAuthenticationServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
So NO argument constructor can't be created by JVM automatically.
and the below line has also not autowired
private final UserRepository userRepository;
Please add no argument constructor or remove the existing to resolve this issue.
Can you try putting below statement ?
#EntityScan("org")
I also have faced same issue but when i have used above statement for my directory structure it works.
Note :
You are confused between #ComponentScan and #EntityScan.
Just do one thing both above annotation annote like,
#ComponentScan("org"),
#EntityScan("org") and
#EnableJPARepository("org")
Mostly it will work for you
Thank you all for trying to help me! I find a solution. The problem was that i didnt have JPAConfig file. This solved the problem:
#Configuration
#EnableJpaRepositories("org.tu.userserviceimpl.repository")
public class JPAConfig {
}
After that i deleted the ComponentScan annotation from the SpringBootApplication class and everything was up and running

Transaction Rollback in Controller if exception occurred in any service

I am newbie to spring and I face problem in Transaction.
I have created two Model as below:
UserDto - Stored user information
RoleDto - Stored user's role information
Service respected to both models are as below (both are annotated with #Transactional):
UserService - void saveUser(UserDto userDto) throws Exception;
RoleService - void saveRole(RoleDto roleDto) throws Exception;
now when user create account in the application at that time I called "add" method of the controller, which has the code snippet as below:
userService.saveUser(userDto);
roleService.saveRole(roleDto);
now in this code if exception occurred in Roleservice than it still insert user data into database table. but I want to rollback that too if roleService throws any exception. I tried to find the solution but could not get any good tutorial. any help will be appreciated.
The way you're calling the method makes each of it has its own transaction. Your code can be understood like this:
Transaction t1 = Spring.createTransaction();
t1.begin();
try {
//your first service method marked as #Transactional
userService.saveUser(userDto);
t1.commit();
} catch (Throwable t) {
t1.rollback();
} finally {
t1.close();
}
Transaction t2 = Spring.createTransaction();
t2.begin();
try {
//your second service method marked as #Transactional
roleService.saveRole(roleDto);
t2.commit();
} catch (Throwable t) {
t2.rollback();
} finally {
t2.close();
}
An option to solve this would be to create another service class where its implementation has RoleService and UserService injected, is marked as #Transactional and calls these two methods. In this way, both methods will share the same transaction used in this class:
public interface UserRoleService {
void saveUser(UserDto userDto, RoleDto roleDto);
}
#Service
#Transactional
public class UserRoleServiceImpl implements UserRoleService {
#Autowired
UserService userService;
#Autowired
RoleService roleService;
#Override
public void saveUser(UserDto userDto, RoleDto roleDto) {
userService.saveUser(userDto);
roleService.saveRole(roleDto);
}
}
A better design would be to make RoleDto a field of USerDto and that implementation of USerService has a RoleService field injected and perform the necessary calls to save each. Note that service classes must provide methods that contains business logic, this also means business logic rules. Service classes are not just wrappers for Dao classes.
This could be an implementation of the above explanation:
#Service
public class UserServiceImpl implements UserService {
#Autowired
RoleService roleService;
public void saveUSer(UserDto userDto) {
//code to save your userDto...
roleService.saveRole(userDto.getRoleDto());
}
}

Cant put users ID as FK for added database entry (bind added entry to currently loggedin user) - Hibernate, Spring, Spring Security -

I am working on a small library management system where users log in and add books from their collection. I am using Spring Boot with Spring Security, MySql and Hibernate. Users are able to login and when they are logged in I can take their info via ContexHolder and I can add books to database and get them all and display them in front-end, but now I want to bind every added book with currently logged in user so I can display only books this user has added, not all books from db. I am trying to do it like this:
My BookController.java:
#RestController
#RequestMapping("/book")
public class BookController {
#Resource
BookDAO bookDao;
#RequestMapping(value = "/save", method = RequestMethod.POST)
public HashMap<String, String> addBook(#RequestBody Book book) {
book.setUser(new Security().getCurrentUser());
bookDao.save(book);
return Response.setSuccess("Book saved successfuly.");
}
My Security.java:
public class Security {
private UserDAO userDao;
#RequestMapping(value = "/getCurentUser", method = RequestMethod.GET)
public User getCurrentUser() {
return userDao.findByEmail(SecurityContextHolder.getContext().getAuthentication().getName());
}
}
But, for some reason, in this case, method getCurrentUser returns null and I get NullPointerException. But when I use the same method from UserController.java it returns exactly what I expect i to return. This is tested at the same run (first I called a method from Securty.java and it returned null, then I called method from UserControll.java and I got currently logged in user (me) ).
Here is my UserController.java (only getCurrentUser and loginUser methods):
#RestController
#RequestMapping("/user")
public class UserController {
#Resource
private UserDAO userDao;
#Autowired
AuthenticationManager authenticationManager;
#Autowired
BCryptPasswordEncoder encoder;
#RequestMapping(value = "/getCurentUser", method = RequestMethod.GET)
public User getCurrentUser() {
return userDao.findByEmail(SecurityContextHolder.getContext().getAuthentication().getName());
}
...
#RequestMapping(value = "/login", method = {RequestMethod.POST, RequestMethod.GET})
public HashMap<String, String> loginUser(#RequestBody final User user) {
final User foundUser = userDao.findByEmail(user.getEmail());
if (foundUser == null || !encoder.matches(user.getCurentPassword(), foundUser.getCurentPassword())) {
return Response.setError("Bad credentials");
} else {
final UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user.getEmail(), user.getCurentPassword(), AuthorityUtils.createAuthorityList(foundUser.getRole().name()));
final Authentication authentication = authenticationManager.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
return Response.setSuccess(foundUser.getRole().name());
}
}
Oh, and my Book.Java bean:
....
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
....
Finally after long time of trying i have managed to solve this problem. As it turned out - calling getCurrentUser method from separate Security class returned anonymous user even thou user with ROLE_USER was logged in. Adding #Autowired annots to UserDAO userDao or #Component or #Service annots to whole class also did not gave any results.
Calling:
userDao.findByEmail(SecurityContextHolder.getContext().getAuthentication().getName())
from BookController with UserDAO userDao eith #Resource annot in BookController also returned anonymous user. Only when I added #Autowired to UserDAO userDao i managed to get currently logged in user and bind book to him. Here is the code:
#RestController
#RequestMapping("/book")
public class BookController {
#Resource
BookDAO bookDao;
#Autowired
UserDAO userDao;
#PreAuthorize("hasRole('ROLE_USER')")
#RequestMapping(value = "/save", method = {RequestMethod.POST, RequestMethod.GET})
public HashMap<String, String> addBook(#RequestBody Book book) {
book.setUser(userDao.findByEmail(SecurityContextHolder.getContext().getAuthentication().getName()));
bookDao.save(book);
return Response.setSuccess("Book saved successfuly.");
}
1- The class Security has a #Component or #Service annotation?
2- userDao field is null - you need to inject it using #Autowired to avoid NullPointerException in getCurrentUser() method.

Categories

Resources