In a Spring application, I have a class called Utility.java and the class is annotated with the #Service annotation. In that class I am trying to fetch a user in a function to be used globally in the project.
Upon calling the user in a controller using the utility method created it throws nullpointer exception from the repository. Below is the code
//Utility.java file
#Service
public class Utility{
#Autowired static UserDao userDao;
public static User findActiveUser(String auth){
System.out.println("here is the username: " + auth);
User user = null;
try {
user = Utility.userDao.findBy...("user1", "ACTIVE"); //throws null here
}catch (Exception ex){
ex.printStackTrace();
}
return user;
}
//Controller annotated class
#Autowired Utility utility;
#GetMapping(value = "/success")
public String success(Authentication auth,HttpServletRequest request){
if (auth == null) {
return "index";
}
System.out.println("#dashboard success");
User user = utility.findActiveUser(auth.getName());
Everything look fine and good to go but still not working
You can't #Autowired a static field.
You have to remove static word from this line #Autowired static UserDao userDao; or implement additional logic to autowire value to the static field.
Related
I am trying to understand Mockito and Junit 4. I hava an interface named UserService which has a method named getUserInfo. I have written an implementation class UserServiceImpl to this interface.
I am using this getUserInfo method inside another class named UserInfoImpl. Now I am trying to Junit UserInfoImpl by Mocking UserServiceImpl. But instead of going to to the mock method, the call is going to the actual method. I have verified it by adding sysout to the actual method. I am not sure why it is not getting mocked. Can someone please throw some light.
Junit Class
public class Junit4WithMockito {
private UserInfoImpl userInfo;
#Mock
private UserService userService;
#Before
public void setUp() {
System.out.println("Inside Setup");
MockitoAnnotations.initMocks(this);
}
#Test
public void testUserInfoImpl() throws InterruptedException {
String cid="yu444";
userInfo = new UserInfoImpl();
userInfo.setUserService(userService);
when(userService.getUserInfo(cid)).thenReturn(new User("John Doe",33));
Assert.assertEquals("Peter",userInfo.getUserInfo(cid).getUsername());
}
}
UserInfoImpl Class
public class UserInfoImpl implements UserInfo {
private UserService userService;
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
#Override
public User getUserInfo(String username) {
try {
userService = new UserServiceImpl();
return userService.getUserInfo(username);
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
}
****** UserServiceImpl Class which I am trying to mock *********
public class UserServiceImpl implements UserService {
#Override
public User getUserInfo(String username) throws InterruptedException {
System.out.println("Inside the actual Service");
Thread.sleep(5000);
return new User("John Doe",33);
}
}
Error Message Below
You don't usually want to mock an implementation class, especially when there is an interface for it. The point of mocking is that you don't need (or want) the real implementation to be used.
So in your case, your #Mock should be
#Mock
private UserService userService;
Furthermore, you have this line in UserInfoImpl:
userService = new UserServiceImpl();
Obviously this replaces whatever instance of UserService you inject (including the mock). I'm guessing that's a mistake (maybe left around from an earlier attempt) since I can't think of any reason you'd really want to instantiate something that you're injecting.
I'm developing REST App for the IT courses. One of the requirements was to use Spring-JDBC with all queries to be stored in separate properties file. Here is a part of my UserDaoImpl:
#Repository
#RequiredArgsConstructor
#PropertySource(value = "classpath:/user_queries.properties")
#Log
public class UserDaoImpl implements UserDao {
private final NamedParameterJdbcTemplate template;
private final RowMapper<User> rowMapper;
#Value("${find.by_id}")
private String findById;
#Override
public Optional<User> findById(int id) {
SqlParameterSource param = new MapSqlParameterSource("id", id);
User user = null;
try {
user = template.queryForObject(findById, param, BeanPropertyRowMapper.newInstance(User.class));
} catch (DataAccessException ex) {
String.format("User with id - %d, not found.", id);
}
return Optional.ofNullable(user);
}
}
All method work fine, but troubles started when I wrote my Test to this class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {TestDBConfiguration.class})
public class UserDaoTest {
#Autowired
DataSource dataSource;
#Test
public void findByIdTest() {
NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(dataSource);
UserRowMapper userMapper = new UserRowMapper();
UserDao userDao = new UserDaoImpl(template, userMapper);
User user = new User(1, "John", "Doe",
"$2a$04$MzVXtd4o0y4DOlyHMMLMDeE4/eezrsT5Xad.2lmGr/NkCpwBgvn3e",
"jdoe#gmail.com", true);
assertEquals(Optional.of(user), userDao.findById(1));
}
}
When I run this Test my findById is always null. Is there any way to run this test and keep all queries inside the separate file?
Since your UserDaoImpl uses Spring annotations (#Value, #PropertySource, etc), you have to initialize it via Spring to enable their injection. Or else you'd have to supply all these values yourself manually.
So in your test you should inject the DAO itself:
#Autowired
private UserDao userDao;
Or if you want to go manual way (not recommended), allow setting field findById via constructor (recommended) same way you're passing template, userMapper.
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.
So here is what the current description of the error gives me.
Description:
Field profileDoa in com.N2O2.Nitrouz_Studioz.controller.MainController required a bean of type 'com.N2O2.Nitrouz_Studioz.model.profile.ProfileDoa' that could not be found. The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.N2O2.Nitrouz_Studioz.model.profile.ProfileDoa' in your configuration.
I'm sort of lost to why this error is happening as I've only been working with Java Spring Boot recently and still getting used to working with Beans. I've Autowired the Bean in the Test class but it's still throwing the same error.
Here's what I have in my test class and the Controller and ProfileDoa class.
#WebMvcTest(MainController.class)
#ContextConfiguration(classes = NitrouzStudiozApplication.class)
public class MainControllerTest {
#Autowired
private MockMvc mockMvc;
ProfileEntity profileEntity;
#Autowired
private ProfileDoa profileDoa;
private MainController mainController;
#Mock
private Model model;
private boolean loggedOut = true;
private boolean loggedIn = false;
#BeforeEach
public void intializeController(){
mainController = new MainController();
}
#Test
#DisplayName("Navigating to Website Correctly Displays Index page")
public void loadsIndexPage() throws Exception {
RequestBuilder request = MockMvcRequestBuilders.get("/");
MvcResult result = mockMvc.perform(request)
.andExpect(model().attribute("loggedOut", loggedOut))
.andExpect(model().attribute("loggedIn", loggedIn))
.andExpect(model().attribute("profileEntity", "Not logged In"))
.andReturn();
Assertions.assertEquals("index", result);
}
}
#Controller
public class MainController {
private boolean loggedOut = true;
private boolean loggedIn = false;
private ProfileEntity profileEntity;
#Autowired
private ProfileDoa profileDoa;
#RequestMapping("/")
public String home_page(Model model) {
model.addAttribute("loggedOut", loggedOut);
model.addAttribute("loggedIn", loggedIn);
model.addAttribute("profileEntity", "Not logged In");
return "index";
}
#RequestMapping("/about")
public String about_page(Model model){
model.addAttribute("loggedOut", loggedOut);
model.addAttribute("loggedIn", loggedIn);
model.addAttribute("profileEntity", "Not logged In");
return "about";
}
#RequestMapping("/signup")
public String sign_up(){
return "signup";
}
#GetMapping("/signUpForm")
public String signUpForm(Model model, ProfileEntity profileEntity){
boolean checked = false;
model.addAttribute("profileEntity", profileEntity);
model.addAttribute("join", checked);
return "signUpForm";
}
#RequestMapping("/signUpFormError")
public String signUpFormError(Model model,
#ModelAttribute("error") boolean error,
#ModelAttribute("message") String message,
ProfileEntity profileEntity){
boolean checked = false;
model.addAttribute("join", checked);
model.addAttribute("error", error);
model.addAttribute("message", message);
model.addAttribute("profileEntity", profileEntity);
return "signUpForm";
}
#RequestMapping("/ForgotPasswordPage")
public String forgotPasswordPage(){
return "forgotPassword";
}
#GetMapping("/Forgot_Password")
public String ForgotPasswordResponse(){
return "forgotPassword";
}
}
#Transactional
public interface ProfileDoa extends JpaRepository<ProfileEntity, Long> {
public ProfileEntity findByEmail(String email);
}
Any help on this would be helpful. Thanks.
With #WebMvcTest you can write tests for your web layer. Spring Test will create a context for you with all beans that are required to test this slice of your application: e.g. classes annotated with #Controller, #RestController, #ControllerAdvice, filter, etc.
All other beans are not created for you as they are not in the scope of the web layer. In your case, that's any other bean your MainController injects.
You have basically now two options:
Mock the ProfileDoa
Use a real bean of ProfileDoa. This would require a database and more setup on your side.
For option one you can adjust your test like the following:
#WebMvcTest(MainController.class)
public class MainControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private ProfileDoa profileDoa;
private boolean loggedOut = true;
private boolean loggedIn = false;
#Test
#DisplayName("Navigating to Website Correctly Displays Index page")
public void loadsIndexPage() throws Exception {
RequestBuilder request = MockMvcRequestBuilders.get("/");
MvcResult result = mockMvc.perform(request)
.andExpect(model().attribute("loggedOut", loggedOut))
.andExpect(model().attribute("loggedIn", loggedIn))
.andExpect(model().attribute("profileEntity", "Not logged In"))
.andReturn();
Assertions.assertEquals("index", result);
}
}
As I don't see any interaction with profileDoa in your MainController there is also no need to prepare any mocked method response. If you do however call e.g. profileDao.findByEmail("mail#duke.io") somewhere, you can use Mockito to prepare the result:
ProfileEntity databaseResult = new ProfileEntitiy();
when(profileDao.findByEmail("THIS_HAS_TO_MATCH_YOUR_MAIL")).thenReturn(databaseResult);
For option two, you can use a combination of #SpringBootTest and #AutoconfigureMockMvc to load the whole Spring context (all beans) and make use of MockMvc:
#SpringBootTest
#AutoconfigureMockMvc
public class MainControllerTest {
// no mocking required as _real_ beans are used
}
Here you might want to use e.g. Testcontainers to start a database for your test.
Dao
#Repository
public interface LoginDao extends JpaRepository<Login, Integer> {
Login findByLogin(String login);
}
Validator
#Component
public class PasswordChangeValidator implements Validator {
private LoginDao loginDao;
#Override
public boolean supports(Class<?> aClass) {
return PasswordChange.class.equals(aClass);
}
#Override
public void validate(Object o, Errors errors) {
PasswordChange passwordChange = (PasswordChange) o;
**// There is a null pointer here because loginDao is null**
Login login = loginDao.findByLogin(passwordChange.getLoginKey());
}
public LoginDao getLoginDao() {
return loginDao;
}
#Autowired
public void setLoginDao(LoginDao loginDao) {
**// There is a debug point on the next line and it's hit on server startup and I can
// see the parameter us non-null**
this.loginDao = loginDao;
}
}
Controller
#Controller
#RequestMapping("api")
public class PasswordController {
#Autowired
PasswordService passwordService;
#InitBinder("passwordChange")
public void initBinder(WebDataBinder webDataBinder, WebRequest webRequest) {
webDataBinder.setValidator(new PasswordChangeValidator());
}
#RequestMapping(value = "/passwordChange", method = RequestMethod.POST)
public #ResponseBody PasswordInfo passwordInfo(#RequestBody #Valid PasswordChange passwordChange)
throws PasswordChangeException {
return passwordService.changePassword(passwordChange.getLoginKey(), passwordChange.getOldPassword(), passwordChange.getNewPassword());
}
}
I have the Dao listed above. This same dao bean gets injected in an #Service annotated class but not in #Component annotated Validator class. Well, not exactly the upon server startup I can see that the setter method gets called, but when I try to use this variable in a method the variable shows as null.
Does anybody see a problem with my configuration ? Please note that the loginDao bean gets injected into a service class, so the Context configuration is good.
Well there's your problem
webDataBinder.setValidator(new PasswordChangeValidator());
Spring can only manage beans it created. Here, you're creating the instance. Instead inject your bean into the #Controller and use it.
#Inject
private PasswordChangeValidator passwordChangeValidator;
...
webDataBinder.setValidator(passwordChangeValidator);