how can't I update my user profile with new information? - java

I want to update my user profile if the String loginExist = null or loginExist.equals(principal.getName())
the problem is that I get NullPointerException.
this is my code:
// update profile
#RequestMapping(value = "/updateRH", method = RequestMethod.POST)
public ModelAndView updateRH(Principal principal, #ModelAttribute("user") user user) {
ModelAndView mv = new ModelAndView();
String loginExist = "";
user rh = RhRepo.findByUsername(principal.getName());
try {
loginExist = userRepo.findCountUsername(user.getUsername());
} catch (Exception e) {
}
System.out.println(loginExist);
if (loginExist.equals(null) || loginExist.equals(principal.getName())) {
user.setId(RhRepo.findByUsername(principal.getName()).getId());
user.setPwd(encoder.encode(user.getPwd()));
RhRepo.save(user);
} else {
String msg = "Username Deja exist !!!";
mv.addObject("msg", msg);
}
mv.addObject("rh", rh);
mv.setViewName("rhprofile");
return mv;
}

loginExist.equals(null) will throw NPE if loginExist is null as you are trying to call a method from a null object.
Use :-
loginExist == null
instead.

So the problem is user.getUsername(). the user is null and trying to get its username causes a NullPointerWxception.
add a check before that call, try this:
if (user != null) {
loginExist = userRepo.findCountUsername(user.getUsername());
}
otherwise (if it is null), you need to create the user before trying to find it from repository.

Related

How to write test for this put method

I have a put method, which takes an "Accept" header with value "application/json", and a requestBody class, and returns a ResponseEntity class. Can anyone tell me how to write tests for this method
This is my put api
public ResponseEntity<String> registerUserUsingPUT(#Parameter(in = ParameterIn.DEFAULT, description = "", schema=#Schema()) #Valid #RequestBody UserInput body) {
String accept = request.getHeader("Accept");
if (accept != null && accept.contains("application/json")) {
UserInfo user = userInfoService.getByEmail(body.getEmail());
if(user==null) {
user = new UserInfo();
String email = body.getEmail();
if(email.matches("^[a-z0-9._%+-]+#[a-z0-9.-]+.[a-z]{2,4}$")) user.setEmail(email);
user.setFirstName(body.getFirstName());
user.setLastName(body.getLastName());
user.setPassword(body.getUserPassword());
user.setRole(roleService.findRoleByType("Customer"));
if(body.getPhoneNo().length()==10) user.setPhoneNumber(body.getPhoneNo());
else return new ResponseEntity<String>("Incorrect Phone number",HttpStatus.BAD_REQUEST);
user.setPoints(0);
user.setStatus("Active");
user.setWalletBalance(0);
AddressDetails address = new AddressDetails();
address.setAddress(body.getAddress());
String pincode = body.getPinCode();
if(pincode.matches("^[0-9]{1,6}$")) address.setPincode(pincode);
address.setUser(user);
userInfoService.register(user);
addressDetailsDao.save(address);
return new ResponseEntity<String>("Registered",HttpStatus.OK);
}
else {
return new ResponseEntity<String>("User Already Exists",HttpStatus.BAD_REQUEST);
}
}
return new ResponseEntity<String>(HttpStatus.NOT_IMPLEMENTED);

How to send Status Codes Along with my Custom Class Using Spring?

I am trying to make a log in system using spring. Problem is if username is not in the database I want to send a different status code and if username is in the database but password is wrong I want to send different status code. Because in my front end i am going to inform user using different alerts according to status code.
I cannot use HttpStatus.NOT_ACCEPTABLE or something like that because my controller is returning a User(my custom class). It will either return User or null.
#GetMapping("/users")
public User userLogin(#RequestParam String username,#RequestParam String password) {
User user = userService.findByUsername(username);
if(user==null) {
return null;
}
if(user.getPassword().equals(password)) {
return user;
} else {
return null;
}
}
Here I am trying to change status while returning nulls.
you can return ResponseEntity to meet your requirement
#GetMapping("/users")
public ResponseEntity<User> userLogin(#RequestParam String username,#RequestParam String password) {
User user = userService.findByUsername(username);
if(user==null) {
return new ResponseEntity<>(null,HttpStatus.NOT_FOUND);
}
if(user.getPassword().equals(password)) {
return new ResponseEntity<>(user,HttpStatus.OK);
} else {
return new ResponseEntity<>(null,HttpStatus.FORBIDDEN);
}
}
Spring 5 introduced the ResponseStatusException class. We can create an instance of it providing an HttpStatus and optionally a reason and a cause:
#GetMapping(value = "/{id}") public Foo findById(#PathVariable("id") Long id, HttpServletResponse response) {
try {
Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response));
return resourceById;
}
catch (MyResourceNotFoundException exc) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Foo Not Found", exc);
} }
Maybe this is which you looking for?
Detail in https://www.baeldung.com/exception-handling-for-rest-with-spring#controlleradvice

Issues testing my Spring MVC Controllers

I have the following controller method. A user submits a search form with 4 input fields and has to fill in at least one of the field. If all the fields are empty (using the validator) then an error will be displayed on top of the form (in the same page).
Otherwise it will use the service method to look for users and display the results at the bottom of the form (in the same page). That is why in the if statement I return the same page as well as the end of the method because whatever happens the user is directed to the same page
#RequestMapping(value="/search", method={RequestMethod.POST})
public ModelAndView searchUser(#ModelAttribute("searchUserDTO")SearchUserDTO searchUserDTO, BindingResult bindingResult, ModelMap modelMap){
validate(searchUserDTO, bindingResult);
List<BlueUser> users = new ArrayList<>();
if (bindingResult.hasErrors()) {
modelMap.put("searchUserDTO", searchUserDTO);
return new ModelAndView(VIEW_USERS, modelMap);
} else {
users = BlueUserService.findUsers(searchUserDTO.getMyName, searchUserDTO.getSSID(), searchUserDTO.getPostcode(), new Email(searchUserDTO.getMail()));
}
modelMap.put("searchUserDTO", users);
return new ModelAndView(VIEW_USERS, modelMap);
}
validator method
#Override
public void validate(Object target, Errors errors) {
SearchUserDTO dto = (SearchUserDTO)target;
if(dto.getMyName()==null && dto.getSSID() == null && dto.getPostcode() == null && dto.getMail()==null){
errors.reject(EMPTY, "Please fill in the form");
}
}
I use reject to return error in the global scope and not on specific field and the following test method:
public static final String BINDING_RESULT = BindingResult.class.getName() + '.' + "searchUserDTO";
#Test
public void searchUserPOST() throws Exception{
MultiValueMap<String, String> paramMap = mockMVCTestUtil.createParamMap("myName", null,
"ssid", null,
"postcode", null,
"mail", null);
MvcResult mvcResult = this.mockMvc.perform(
post("/search")
.params(paramMap))
.andExpect(model().attributeExists("searchUserDTO"))
.andExpect(model().attributeHasErrors("searchUserDTO"))
.andExpect(status().isOk())
.andExpect(redirectedUrl(VIEW_USERS))
.andExpect(forwardedUrl(VIEW_USERS))
.andReturn();
BindingResult bindingResult = (BindingResult) mvcResult.getModelAndView().getModel().get(BINDING_RESULT);
assertNotNull(bindingResult);
assertGlobalErrorMessage(bindingResult, "Please fill in the form");
}
When I run the test method it fails and i get the following error messages:
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: No errors for attribute 'searchUserDTO'
What am I doing wrong?

REST to return content after POST on Java service

New users are created with the POST method, and after this the database will attach it an unique ID, which is necessary to create a token.
The only way to create a token, is after the process of user creation. I query it from the database and now it should have ID on it, but I can't figure how to do that.
Is there any way to retrieve the entity from database right after creating it?
If looked at this similar question, but couldn't find an answer: Is it ok by REST to return content after POST?
#POST
#Consumes({MediaType.APPLICATION_JSON})
public Response create(#QueryParam("email") String email, #QueryParam("username") String userName, #QueryParam("password") String password) {
if (TextUtil.isEmpty(userName) || TextUtil.isEmpty(password) || TextUtil.isEmpty(email)) {
return Response.status(Response.Status.BAD_REQUEST).build();
} else {
User newUser = new User();
newUser.setEmail(email);
newUser.setUsername(userName);
newUser.setPass(password);
super.create(newUser); //ths line create user in database
String id = newUser.getUid() + ""; //the newUser has no id yet so it is null but I want this id from database
return Response.status(Response.Status.OK).entity("id: " + id).build();
}
}
Create super.method
public void create(T entity) {
getEntityManager().persist(entity);
}
I generate REST api using this tutorial
https://netbeans.org/kb/docs/websvc/rest.html
getEntityManager().persist(entity);
Set the id of the entity by calling entity.setId(...).
I my comments I show how to sync EntityManager. Maybe you should write a better create method:
public <T> T create(T t) throws Exception {
try {
entityManager.persist(t);
entityManager.flush();
} catch (Exception e) {
throw e;
} finally {
entityManager.clear();
}
return t;
}
And then
newUser = super.create(newUser);

Mock BindingResult in unit test case when user does not exist

I'm very new to Mockito and Junit. I'm working on creating test case for forgot password workflow. Below is the code for controller and test. Could anyone tell me how should I test on bindingresult?
#RequestMapping(value = "/user/public/forgotPassword", method = RequestMethod.POST)
public ModelAndView sendforgetPasswordLink(#ModelAttribute ForgetPasswordBean forgetPasswordBean,BindingResult result, HttpSession session) {
BreadCrumbBuilder.addLinktoBreadCrumb(session, new Link(Constants.FORGET_PASSWORD_TITLE, "/user/public/forgotPassword", Constants.GROUP_USER, 0));
Map<String, String> breadCrumbs = HomePageController.setupInitialBreadCrumbs(session);
breadCrumbs.put(Constants.FORGET_PASSWORD_TITLE, "/user/public/forgotPassword");
session.setAttribute(SessionAttributes.BREAD_CRUMBS,breadCrumbs);
ModelAndView mav = new ModelAndView();
mav.addObject("displayTitle", Constants.FORGET_PASSWORD_TITLE);
PublicUser user = publicUserService.findPublicUserByEmail(forgetPasswordBean.getEmail().toLowerCase());
if(user == null) {
result.reject("email", "An account does not exist for this email.");
mav.setViewName("publicuser/forgetPassword.jsp");
return mav;
}
String randomId = java.util.UUID.randomUUID().toString();
user.setTempId(randomId);
mailService.sendForgetPasswordLink(user);
publicUserService.savePublicUser(user);
String msg = "Password reset instructions have been sent to your email.";
mav.addObject("msg", msg);
mav.setViewName("message.jsp");
return mav;
}
This is test I created so far
#Test
public void TestForgetPasswordForNoUserFound() throws Exception {
final String input_email = "abc#test.com";
ForgetPasswordBean forgetPasswordBean = new ForgetPasswordBean();
forgetPasswordBean.setEmail(input_email);
PublicUser daoUser = new PublicUser();
daoUser.setEmail(input_email);
when(mockPublicUserService.findPublicUserByEmail(input_email)).thenReturn(null);
when(mockBindingResult.hasErrors()).thenReturn(true);
final ModelAndView modelAndView = controller.sendforgetPasswordLink(forgetPasswordBean, mockBindingResult, mockHttpSession);
ModelMap modelMap = modelAndView.getModelMap();
assertEquals("An account does not exist for this email.", modelMap.get(mockBindingResult));
assertEquals("publicuser/forgetPassword.jsp", modelAndView.getViewName());
assertModelAttributeValue(modelAndView, "displayTitle", Constants.FORGET_PASSWORD_TITLE);
}
What you can do is verify behavior of your BindingResult by checking that the reject method was called.
Basically instead of
assertEquals("An account does not exist for this email.", modelMap.get(mockBindingResult));
You can do the following
Mockito.verify(mockBindingResult).reject("email", "An account does not exist for this email.");
And that way you can verify that the method was called.

Categories