This is my Controller class and I wrote exceptions to check pin and username(because I want to make them unique) But When I enter data in Postman It gives only one of them( I want to create scenario that both pin and username are not unique and used for once) How can I write Both of them same time. I actually want to add some elements additionally like that so I'm stuck there)
I want output be like:
Ex: This pin Already in use!
This username Already in use!
#RestController
#RequestMapping("/api")
public class EmployeeController {
//private EmployeeService employeeService;
private final EmployeeRepository employeeRepository;
// ControllerException controllerException;
#Autowired
public EmployeeController(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
#PostMapping("/employee")
public ResponseEntity<Employee> saveEmployee(#RequestBody Employee employee, BindingResult bindingResult) throws EmployeeAlreadyExistsException {
if (employeeRepository.existsById(employee.getId())) {
throw new EmployeeAlreadyExistsException();
}
String temUsername = employee.getUsername();
if(temUsername !=null && !"".equals(temUsername)) {
Employee userObject = employeeRepository.findByUsername(temUsername);
if(userObject!=null) {
throw new EmployeeUsernameAlreadyExistsException();
}
}
String pin = employee.getPin();
if(pin !=null && !"".equals(pin)) {
Employee userObject = employeeRepository.findByPin(pin);
if(userObject!=null) {
throw new EmployeePinAlreadyExistsException();
}
}
Employee employee1 = employeeRepository.save(employee);
return new ResponseEntity<>(employee1, HttpStatus.CREATED);
}
#GetMapping("/employees")
public ResponseEntity<List<Employee>> getAllEmployee() throws EmployeeNotFoundException {
return new ResponseEntity<>((List<Employee>) employeeRepository.findAll(), HttpStatus.OK);
}
#PostMapping("/update")
public ResponseEntity<?> updateEmployee(#RequestBody Employee employee) throws EmployeeNotFoundException, EmployeePinAlreadyExistsException {
if (!employeeRepository.existsById(employee.getId())) {
throw new EmployeeNotFoundException();
} else {
Employee employee1 = employeeRepository.save(employee);
return new ResponseEntity<>(employee1, HttpStatus.CREATED);
}
}
#GetMapping("employee/{id}")
public ResponseEntity<?> getEmployeeById(#PathVariable("id") int id, Employee employee) throws EmployeeNotFoundException {
if (!employeeRepository.existsById(employee.getId())) {
throw new EmployeeNotFoundException();
}
return new ResponseEntity<>(employeeRepository.findById(id), HttpStatus.OK);
}
#ExceptionHandler(value = EmployeeAlreadyExistsException.class)
public ResponseEntity<?> EmployeeAlreadyExistsException(EmployeeAlreadyExistsException employeeAlreadyExistsException) {
ErrorResponse erResp = ErrorResponse.builder()
.message("This Employee already exist!")
.code("101")
.traceId(UUID.randomUUID().toString())
.build();
return new ResponseEntity<>(erResp, HttpStatus.CONFLICT);
}
#ExceptionHandler(value = EmployeeNotFoundException.class)
public ResponseEntity<?> EmployeeNotFoundException(EmployeeNotFoundException employeeNotFoundException) {
ErrorResponse erResp = ErrorResponse.builder()
.message("This id is not valid!")
.code("404")
.traceId(UUID.randomUUID().toString())
.build();
return new ResponseEntity<>(erResp, HttpStatus.CONFLICT);
}
#ExceptionHandler(value = EmployeePinAlreadyExistsException.class)
public ResponseEntity<?> EmployeePinAlreadyExistsException(EmployeePinAlreadyExistsException employeePinAlreadyExistsException) {
ErrorResponse erResp = ErrorResponse.builder()
.message("This pin Already in use!")
.code("101")
.traceId(UUID.randomUUID().toString())
.build();
return new ResponseEntity<>(erResp, HttpStatus.CONFLICT);
}
#ExceptionHandler(value = EmployeeUsernameAlreadyExistsException.class)
public ResponseEntity<?> EmployeeUsernameAlreadyExistsException(EmployeeUsernameAlreadyExistsException employeeUsernameAlreadyExistsException) {
ErrorResponse erResp = ErrorResponse.builder()
.message("This Username Already in use!")
.code("109")
.traceId(UUID.randomUUID().toString())
.build();
return new ResponseEntity<>(erResp, HttpStatus.CONFLICT);
}
}
You should define a class with attribute like private List<String> errMsg to handle response
Then, check pin and username and save check result to boolean variable. If result are false, add an element to errMsg like "pin already in use", "username already in use".
Finally, dependent to check results, if all of them are false, you can throw PinAndUsernameAlreadyExistsException with errMsg have 2 messages were added
If you need all the fields in the exception message don't throw the exception until all validations have been made, however for a public accessed application is not a good idea from a security perspective, It's better a generic error message like: "Some of your employee data is already used", anyway, if you need it for some kind of customer requirement or simple formation exercise, this code should do what you ask for:
private void assertEmployeeDataisUnique(Employee employee) throws Exception {
List<String> existingFields = new ArrayList<>();
if (employeeRepository.existsById(employee.getId())) {
existingFields.add("id");
}
String temUsername = employee.getUsername();
if(temUsername !=null && !"".equals(temUsername)) {
Employee userObject = employeeRepository.findByUsername(temUsername);
if(userObject!=null) {
existingFields.add("username");
}
}
String pin = employee.getPin();
if(pin !=null && !"".equals(pin)) {
Employee userObject = employeeRepository.findByPin(pin);
if(userObject!=null) {
existingFields.add("pin");
}
}
if(!existingFields.isEmpty()) {
throw new Exception("Employee data is not unique. Fields: " + existingFields);
}
}
#PostMapping("/employee")
public ResponseEntity<Employee> saveEmployee(#RequestBody Employee employee, BindingResult bindingResult) throws EmployeeAlreadyExistsException {
this.assertEmployeeDataisUnique(employee);
Employee employee1 = employeeRepository.save(employee);
return new ResponseEntity<>(employee1, HttpStatus.CREATED);
}
Related
I'm making an ajax call to a method that returns a list of object, if something happens while getting the data in a try-catch block I have a response.setStatus(400) to then show the error in the front-end, also there I'm returning null, there is where I'm getting the SonarLint notification. Now if I change that to an empty collection then I get below error:
getWriter() has already been called for this response
I think the above is because I'm returning the empty collection and the http response status 400. If I leave it null then all works fine, just that SonarLint notification.
#GetMapping("/runquery")
#ResponseBody
public List<Map<String, Object>> runQuery(#RequestParam(name = "queryId") String queryId, #RequestParam(name = "formData") String formData, HttpServletResponse response) throws IOException {
(...)
try {
queryResult = namedParameterJdbcTemplateHive.queryForList(query, paramSource);
for (Map<String, Object> map : queryResult) {
Map<String, Object> newMap = new HashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (key.contains(".")) {
key = key.replace(".", "_");
newMap.put(key, value);
} else {
newMap.put(key, value);
}
}
queryResultFinal.add(newMap);
}
} catch (Exception e) {
response.setStatus(400);
response.getWriter().write(e.getMessage());
return null; <-- SonarLint notification
}
return queryResultFinal;
}
Any idea on how to fix this notification?
I would recommend not catching the exception in this method, but instead throw it, and use an exception handler method in your controller to handle it. In that case you will never return null from the method, and Sonar will have nothing to complain about. It will also mean that you are using Spring the way it is designed to be used.
For example, something like the following:
#ExceptionHandler
#ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleException(Exception e) {
log.error("Exception during request", e);
}
or the direct equivalent of your current handling:
#ExceptionHandler
public ResponseEntity<?> handleException(Exception e) {
return ResponseEntity.badRequest().body(e.getMessage()).build();
}
You can remove the HttpServletResponse response parameter from your normal method after switching to an exception handler.
I would recommend you to create a GenericReponse that wraps all of your responses, it's pretty good for front-end also because you're facing with a fixed template.
So via this solution, you can wrap up any object you want and send it to the response.
I coded the scenario like this:
1- Create a GenericResponse Class
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class GenericResponse {
private Boolean error;
private List<ErrorPayload> errorPayload;
private Object payload;
public GenericResponse(Boolean error) {
this.error = error;
}
public static GenericResponse ok() {
return new GenericResponse(false);
}
public GenericResponse payload(Serializable o) {
this.payload = o;
return this;
}
//Getters and Setters and other Constructors
2-Create ErrorPayload Class
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorPayload {
private String errorMessage;
private String errorType;
//Getters and Setters and Constructors
}
3-Create ExceptionConverter Service (Used when we have exception)
#Service
public class ExceptionConverterService {
public GenericResponse convert(Exception x) {
GenericResponse genericResponse = new GenericResponse();
genericResponse.setError(true);
String exceptionType = x.getClass().getSimpleName();
String exceptionMessage = x.getClass().getSimpleName();
genericResponse.setErrorPayload(Collections.singletonList(new ErrorPayload(exceptionType, exceptionMessage)));
return genericResponse;
}
}
4-Change Your scenario with GenericResponse
All you need to do is:
Create aforementioned classes (Copy the code that I wrote in 1, 2 and 3)
Change your response form List<Map<String, Object>> to GenericResponse
Wrap your return types into GenericResponse
I changed your code as follows (Just change 3 lines)
#RestController
public class TestController {
#Autowired
private ExceptionConverterService exceptionConverter;
#GetMapping("/runquery")
#ResponseBody
//Changed (Change Return type to GenericResponse )
public GenericResponse runQuery(#RequestParam(name = "queryId") String queryId, #RequestParam(name = "formData") String formData, HttpServletResponse response) throws IOException {
try {
//Your code
}
} catch (Exception e) {
//Changed (Create GenericResponse for Exception)
GenericResponse genericResponse = exceptionConverter.convert(e);
return genericResponse;
}
//Changed (Create GenericResponse for main result)
return GenericResponse.ok().payload(queryResultFinal);
}
}
Examples for two scenarios (first, without exception and the second with exception)
Sample 1
Controller with GenericResponse (We have no exception in this sample)
#RestController
public class TestController {
#GetMapping(value = "/getNameAndFamily")
public GenericResponse getNameAndFamily() {
Map<String, String> person = new HashMap<>();
person.put("name", "foo");
person.put("family", "bar");
return GenericResponse.ok().payload((Serializable) person);
}
}
The result is like as follows:
{
"error": false,
"payload": {
"name": "foo",
"family": "bar"
}
}
Sample 2
controller with GenericResponse when we have Exception in business
#RestController
public class TestController {
#Autowired
private ExceptionConverterService exceptionConverter;
#GetMapping(value = "/getNameAndFamily")
public GenericResponse getNameAndFamily() {
try {
//Create Fake Exception
int i = 1 / 0;
return GenericResponse.ok();
} catch (Exception e) {
//Handle Exception
GenericResponse genericResponse = exceptionConverter.convert(e);
return GenericResponse.ok().payload((Serializable) genericResponse);
}
}
}
The result is as follows:
{
"error": true,
"errorPayload": [
{
"errorType": "ArithmeticException"
}
]
}
I'm new in spring boot and trying to figure out when we create a bean using #Bean and tries to access that bean where ever it requires using #Autowired. But i know #Bean is by default singleton and it will save its state but i want to clear its state so that it will give new newly append data or null if no data was append. Kindly help me on this. And i also want to know that is i'm following correct coding standard by using Bean with autowired because i want my every api give similar type of response that's why i create a pojo and make it a bean so that i don't have to create object again and again. Sorry if my problem is silly.. thanks in advance
This is my main class
#SpringBootApplication
public class GyftiV2Application {
public static void main(String[] args) {
SpringApplication.run(GyftiV2Application.class, args);
}
#Bean
public ResponseData getResponse() {
return new ResponseData();
}
}
Below is the pojo
public class ResponseData {
private boolean responce;
private String error;
private List<?> data = new ArrayList<>();
public ResponseData() {
}
public boolean isResponce() {
return responce;
}
public void setResponce(boolean responce) {
this.responce = responce;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public List<?> getData() {
return data;
}
public void setData(List<?> data) {
this.data = data;
}
}
Below is the service where is used my bean
#Service
public class UserServiceImpl implements UserService {
#Autowired
private ResponseData resData;
#Autowired
private UserRepository userRepository;
public ResponseData changePassword(PasswordChange pass) {
User user = userRepository.getOne(pass.getUserId());
if (null != user) {
if (pass.getOldPassword().equals(user.getUser_password())) {
if ((pass.getNewPassword().trim()).equals(pass.getConfirmPassword().trim())) {
user.setUser_password(pass.getNewPassword());
userRepository.save(user);
resData.setResponce(true);
resData.setData(Collections.singletonList("Password change successfully"));
return resData;
} else {
resData.setResponce(false);
resData.setError("Please write the same new password in the confirm section");
return resData;
}
} else {
resData.setResponce(false);
resData.setError("Please write the correct old password");
return resData;
}
} else {
resData.setResponce(false);
resData.setError("Something went wrong userId is not correct");
return resData;
}
}
}
With Controller
#RestController
#RequestMapping("/user")
public class UserController {
#Autowired
private UserService userService;
#PostMapping(value = "/changePassword")
public ResponseEntity<ResponseData> changePassword(#RequestBody PasswordChange pass) {
ResponseData response = userService.changePassword(pass);
if (response.isResponce()) {
return new ResponseEntity<>(response, HttpStatus.OK);
}
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
}
But when i didn't pass same newPassoword and confirmPassword then i got the response
{
"responce": false,
"error": "Please write the same new password in the confirm section",
"data": []
}
And when i pass everything correct then i got the response
{
"responce": true,
"error": "Please write the same new password in the confirm section",
"data": [
"Password change successfully"
]
}
You will clearly see resData save its state that's why error key is still exist. I know if i pass "" in error field it will fix this issue but is there is any why to clear #Bean state ? Thanks for the help.
As said in the comment, you should not be using this as a Bean... It is just a regular object.
Here is how should be your service code:
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
public ResponseData changePassword(PasswordChange pass) {
User user = userRepository.getOne(pass.getUserId());
if (null != user) {
if (pass.getOldPassword().equals(user.getUser_password())) {
if ((pass.getNewPassword().trim()).equals(pass.getConfirmPassword().trim())) {
user.setUser_password(pass.getNewPassword());
userRepository.save(user);
ResponseData resData = new ResponseData();
resData.setResponce(true);
resData.setData(Collections.singletonList("Password change successfully"));
return resData;
} else {
ResponseData resData = new ResponseData();
resData.setResponce(false);
resData.setData("Please write the same new password in the confirm section");
return resData;
}
} else {
...
}
} else {
...
}
}
}
Things to consider:
You shouldn't be using your service to return a ResponseDate object sent directly over to the client. Maybe use exception in your service, like PasswordAndConfirmationAreDifferentException. This way, it is easier to deal the way you want in your controller.
#RestController
#RequestMapping("/user")
public class UserController {
#Autowired
private UserService userService;
#PostMapping(value = "/changePassword")
public ResponseEntity<ResponseData> changePassword(#RequestBody PasswordChange pass) {
try {
userService.changePassword(pass);
ResponseData resData = new ResponseData();
resData.setResponce(true);
resData.setData(Collections.singletonList("Password change successfully"));
return new ResponseEntity<>(resData, HttpStatus.OK);
} catch (PasswordAndConfirmationAreDifferentException e) {
ResponseData resData = new ResponseData();
resData.setResponce(false);
resData.setData("Password incorrect");
return new ResponseEntity<>(resData, HttpStatus.BAD_REQUEST);
}
}
}
Use a builder to easily build a responseDate of type Error ResponseData.Error("my error") and of type Data ResponseData.Data("my message 1", "my message2", ...)
I've a problem with the ExceptionHandler of Java Spring. I have a my Exception called EntityNotFoundException, and I want call ExceptionHandler method from REST Controller when exception is thrown.
This is my REST Controller method code:
#ExceptionHandler(Exception.class)
public ResponseEntity insertTicket(#Valid #RequestBody Ticket ticket, #AuthenticationPrincipal Principal principal) throws EntityNotFoundException {
ticket.setCreationTimestamp(Instant.now());
ticket.setSource(TicketSource.CLIENT);
ticket.setCurrentTicketStatus(TicketStatus.VALIDATION);
User customer = userController.findUserByUsername(principal.getName());
ticket.setCustomer(customer);
try {
ticket.setAttachments(savedFiles(
ticket.getAttachments(),
ticket.getCustomer().getUsername()
));
} catch (FileUploadException e) {
return CommonResponseEntity.NotFoundResponseEntity("ENTITY_NOT_FOUND");
}
ticketController.insertTicket(ticket);
mailSenderController.sendMail(customer.getEmail(), "TICKET_OPENED");
return CommonResponseEntity.CreatedResponseEntity("CREATED");
}
This is my Exception Handler code:
#EnableWebMvc
#ControllerAdvice
#RestControllerAdvice
public class InterceptedResponseEntityExceptionHandler extends
ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
BindingResult bindingResult = ex.getBindingResult();
List<MethodArgumentFieldError> methodArgumentFieldErrors = bindingResult
.getFieldErrors()
.stream()
.map(fieldError -> new MethodArgumentFieldError(fieldError.getField(), fieldError.getCode(), fieldError.getRejectedValue()))
.collect(Collectors.toList());
List<MethodArgumentGlobalError> methodArgumentGlobalErrors = bindingResult
.getGlobalErrors()
.stream()
.map(globalError -> new MethodArgumentGlobalError(globalError.getCode()))
.collect(Collectors.toList());
MethodArgumentError methodArgumentError = new MethodArgumentError(methodArgumentFieldErrors, methodArgumentGlobalErrors);
return new ResponseEntity<>(methodArgumentError, HttpStatus.UNPROCESSABLE_ENTITY);
}
#Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
MissingParameterError missingParameterError = new MissingParameterError(ex.getParameterName(), ex.getMessage());
return new ResponseEntity<>(missingParameterError, HttpStatus.UNPROCESSABLE_ENTITY);
}
#ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleNotFound(Exception ex, WebRequest request) {
System.out.println("inside!");
if( ex instanceof DataIntegrityViolationException){
System.out.println("Data integrity violation");
String constraintViolationErrors = ex.getMessage();
String msgErr = (constraintViolationErrors.substring(constraintViolationErrors.indexOf("=") + 1));
return new ResponseEntity<>(msgErr, HttpStatus.BAD_REQUEST);
}
if(ex instanceof UsernameNotFoundException) {
String msgErr = ex.getMessage();
return new ResponseEntity<>(msgErr, HttpStatus.BAD_REQUEST);
}
if (ex instanceof NotFoundEntityException || ex instanceof EntityNotFoundException || ex instanceof NoSuchElementException){
//return CommonResponseEntity.NotFoundResponseEntity(ex.getMessage());
System.out.println("inside the handler!");
return new ResponseEntity<>(ex.getMessage(),HttpStatus.NOT_FOUND);
}
if(ex instanceof UpdateException){
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
return null;
}
#Data
#AllArgsConstructor
public class MethodArgumentError {
private List<MethodArgumentFieldError> fieldErrors;
private List<MethodArgumentGlobalError> globalErrors;
}
#Data
#AllArgsConstructor
public class MethodArgumentFieldError {
private String field;
private String code;
private Object rejectedValue;
}
#Data
#AllArgsConstructor
public class MethodArgumentGlobalError {
private String code;
}
#Data
#AllArgsConstructor
public class MissingParameterError {
private String parameterName;
private String message;
}
#Data
#AllArgsConstructor
public class ConstraintViolationError {
private String invalidValue;
private String message;
}
}
I don't know why, when I get a DataIntegrityViolationException the ExceptionHandler is called, instead when I get an EntitynotFoundException I get this message:
java.lang.IllegalStateException: Could not resolve method parameter at index 0 in public org.springframework.http.ResponseEntity com.isssr.ticketing_system.rest.TicketRest.insertTicket(com.isssr.ticketing_system.entity.Ticket,java.security.Principal) throws com.isssr.ticketing_system.exception.EntityNotFoundException: No suitable resolver for argument 0 of type 'com.isssr.ticketing_system.entity.Ticket'
What's the problem??
I saw other strage things; I get this message:
Failed to invoke #ExceptionHandler method: public org.springframework.http.ResponseEntity com.isssr.ticketing_system.rest.TicketRest.insertTicket(com.isssr.ticketing_system.entity.Ticket,java.security.Principal) throws com.isssr.ticketing_system.exception.EntityNotFoundException
So it seems that Spring is trying to invoke another method instead of method of my ExceptionHandler.
How is possibile this?
I have already created an e mail confirmation in spring boot it is working nicely, and also I created a link when a user click it should say "confirmed"but I did not figure it out how to do that?
E mail sender java class:
#Component
public class EmailSender {
#Autowired
JavaMailSender javaEmailSender;
public void sendEmail(String to, String subject, String text) throws MessagingException {
MimeMessage message = javaEmailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,
MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name());
helper.setTo(to);
helper.setSubject(subject);
helper.setText(text, true);
helper.addInline("logo.jpg", new ClassPathResource("./images/logo.jpg"));
javaEmailSender.send(message);
}
}
E mail template Loader:
#Component
public class EmailTemplateLoader {
#Autowired
private Configuration freemakerConfiguration;
public String getEmailBody(String name, String confirmationLink) throws TemplateException {
try {
Template template = freemakerConfiguration.getTemplate("EmailConfirmation.ftl");
Map<String, Object> data = new HashMap<String, Object>();
data.put("name", name);
data.put("confirmationLink", confirmationLink);
return FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
return "";
}
}
My signup Resource :
#Autowired
private SignupService signupService;
#Autowired
private HttpServletRequest httpServletRequest;
#RequestMapping(value = "user/signup", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#Transactional(rollbackFor = Exception.class)
public ResponseEntity<?> signup(#RequestBody UserType user) throws SignUpException {
URL requestUrl = null;
try {
requestUrl = new URL(httpServletRequest.getRequestURL().toString());
} catch (MalformedURLException e) {
logger.debug("Malformed Request Url");
}
logger.debug(requestUrl.toString());
signupService.signUp(user, requestUrl.getHost());
return new ResponseEntity<>(HttpStatus.OK);
}
#RequestMapping(value = "user/confirmation", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#Transactional(rollbackFor = Exception.class)
public ResponseEntity<?> confirmSignUp(#RequestParam("u") String loginName, #RequestParam("p") String token) {
try {
signupService.emailConfirmation(loginName, token);
return new ResponseEntity<>(HttpStatus.OK);
} catch (SignUpException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
}
So, As I told I can send an email successfully, but I could not sort how I can write confirmation successfully
do you want to send confirmation mail or just want to know confirmation status that mail has been sent? Please specify it.
You Can add some code in your SignUpService where you have implemented
emailConfiguration() method
#Autowired
private Configuration freemarkerConfiguration;
and add like this in method to get verification
Template t = freemarkerConfiguration.getTemplate("verification.ftl");
String text = FreeMarkerTemplateUtils.processTemplateIntoString(t,object);
or you can do something with ResponseEntity while returning confirmSignup() method You can add some DTO also to get confirmation status.
In spring boot Junit testing when it call when(mockRestTemplate.postForObject(Mockito.any(), Mockito.any(),Mockito.any())).thenReturn(searchDTO) return null instead of searchDTO.
#RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest {
#InjectMocks
private UserServiceImpl userService;
#Mock
private RestTemplate mockRestTemplate;
#Mock
private BeanMapperUtil mockBeanMapperUtil;
#Mock
private UserDomain mockUserDomain;
/**
* This method will test find by SSN method running as per code or not
*
* #throws Exception
*/
#Test
public void findBySSNTest() throws Exception {
UserDTO userDTO = getUserDTO("93ff6e85-fcf4-40c3-9ae8-566791daafa6");
SearchDTO searchDTO = new SearchDTO();
searchDTO.setUid("93ff6e85-fcf4-40c3-9ae8-566791daafa6");
when(mockUserDomain.findByUID("93ff6e85-fcf4-40c3-9ae8-566791daafa6"))
.thenReturn(getUser("93ff6e85-fcf4-40c3-9ae8-566791daafa6"));
when(mockRestTemplate.postForObject(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(searchDTO);
when(mockBeanMapperUtil.createDtoFromEntity(Mockito.any(), Mockito.any())).thenReturn(userDTO);
UserDTO mockUserDTO = userService.findBySSN("123-45-6022");
Assert.assertEquals(mockUserDTO, userDTO);
}
/**
*
* This method is used to get User in methods for testing
*
* #return User
*
*/
private User getUser(String id) {
User mockUser = new User();
mockUser.setUid(id);
mockUser.setFirstName("test");
mockUser.setLastName("test");
mockUser.setEmail("Test#test.com");
mockUser.setAddressLine1("Temp Address");
mockUser.setCity("Temp");
return mockUser;
}
private UserDTO getUserDTO(String id) throws ParseException {
UserDTO mockUserDTO = new UserDTO();
mockUserDTO.setUid(id);
mockUserDTO.setFirstName("test");
mockUserDTO.setLastName("test");
mockUserDTO.setEmail("Test#test.com");
mockUserDTO.setAddressLine1("Temp Address");
mockUserDTO.setCity("Temp");
return mockUserDTO;
}
}
This test is link with UserServiceImpl class and here is implementation of UserServiceImpl class where I found null instead of searchDTO at
SearchDTO searchDTO = restTemplate.postForObject( REST_END_POINT_STAFF_MASTER_FIND_SSN , requestBody,SearchDTO.class);
UserServiceImpl method where it is call and All other variables are define in class already Found error of NullpointerException at getting searchDTO by restTemplate.
public UserDTO findBySSN(String id) throws UserServiceException {
try {
logger.logMethodStart(MessageConstant.METHOD_FIND_BY_USER_WORK_DAY_ID);
Map<String, String> ssnMap = new HashMap<String, String>();
ssnMap.put("ssn", id);
HttpEntity<Map<String, String>> requestBody = new HttpEntity<>(ssnMap);
SearchDTO searchDTO = restTemplate.postForObject(REST_END_POINT_STAFF_MASTER_FIND_SSN, requestBody,
SearchDTO.class);
System.out.println(searchDTO);
UserDTO userDTO = null;
if (searchDTO != null && searchDTO.getUid() != null) {
logger.logMethodFlow(MessageConstant.METHOD_FIND_BY_USER_SSN, "SearchDTO :", searchDTO);
userDTO = findByUID(searchDTO.getUid());
logger.logMethodFlow(MessageConstant.METHOD_FIND_BY_USER_SSN, "Find user by UID", userDTO);
// If the DTO is null, it means request for new external user, so
// it'll create a new external user with returned UID and return it.
if (userDTO != null) {
userDTO.setNewExternalUser(false);
logger.logMethodEnd(MessageConstant.METHOD_FIND_BY_USER_SSN, userDTO);
return userDTO;
}
// If the userDTO is not null, it means found userDTO is not new external user,
// So, set corresponding field to false
userDTO = new UserDTO();
userDTO.setUid(searchDTO.getUid());
userDTO.setNewExternalUser(true);
logger.logMethodEnd(MessageConstant.METHOD_FIND_BY_USER_SSN, userDTO);
return userDTO;
} else {
String msg = messageSource.getMessage(ErrorMessageEnum.USER_STAFF_MASTER_ERROR.toString(), null,
Locale.getDefault());
logger.logMethodFlow(MessageConstant.METHOD_FIND_BY_USER_SSN, msg);
throw new UserServiceException(msg, UserServiceExceptionEnum.GET_USER_BY_SSN.toString(),
searchDTO.toString(), null);
}
} catch (UserServiceException e) {
throw e;
} catch (Exception e) {
String msg = messageSource.getMessage(ErrorMessageEnum.USER_FIND_BY_SSN_ERROR.toString(), null,
Locale.getDefault());
logger.logException(MessageConstant.METHOD_FIND_BY_USER_SSN, e, msg);
throw new UserServiceException(msg, UserServiceExceptionEnum.GET_USER_BY_SSN.toString(), e.getMessage(),
null);
}
}
Try this:
when(mockRestTemplate.postForObject(Mockito.any(String.class),
Mockito.any(HttpEntity.class),
Mockito.eq(SearchDTO.class)))
.thenReturn(searchDTO);