Optional and Java Spring Testing - java

I have a problem with my ControllerTest. I'm not sure how to test for the Optional - does someone know how? The other test gives me a NullPointerException for the stubbing : when(couponService.getCouponById(id)).thenReturn(expectedCoupon);
Would be awesome if someone could help me.
public class CouponControllerTest {
#MockBean
private CouponService couponService;
#MockBean
private UserService userService;
#Autowired
MockMvc mockMvc;
#Test
public void checkAndUpdateCoupon() throws Exception {
int id = 1;
int userId = 1;
Coupon expectedCoupon = new Coupon(1, 1);
when(couponService.getCouponById(id)).thenReturn(expectedCoupon);
List<User> userList = new ArrayList<User>();
when(userService.getAllUser()).thenReturn(userList);
List<Coupon> couponList = new ArrayList<Coupon>();
when(couponService.getAllCoupons()).thenReturn(couponList);
mockMvc.perform(get("/checkCoupon")
.param("id", "1")
.param("userId", "1"))
.andExpect(status().isOk())
.andExpect(view().name("couponPage"))
.andExpect(model().attribute("error", "Not correct user id or coupon id."))
.andExpect(model().attribute("users", userList))
.andExpect(model().attribute("coupons", couponList));
verify(couponService).updateCoupons(id, userId);
}
}
#Controller
public class CouponController {
#Autowired
CouponService couponService;
#Autowired
UserService userService;
#GetMapping("/checkCoupon")
public String checkCoupon(ModelMap model, #RequestParam Integer id, #RequestParam Integer userId, Coupon coupon) {
Optional<Coupon> couponFromDatabase = couponService.byUserIdAndId(coupon.getUserId(), coupon.getId());
if(couponFromDatabase.isEmpty()) {
String error = "Not correct user id or coupon id.";
model.addAttribute("error", error);
} else {
String message = couponService.updateCoupons(id, userId);
model.addAttribute("message", message);
}
List<User> userList = userService.getAllUser();
model.addAttribute("users", userList);
List<Coupon> couponList = couponService.getAllCoupons();
model.addAttribute("coupons", couponList);
return "couponPage";
}
}

I think you need to do some changes in mocking the first service.
when( couponService.byUserIdAndId(anyLong(), anyLong()) ).thenReturn( Optional.of(expectedCoupon) );
Here the anyLong() refer to any Incoming long data type number.
Override your existing code with this above line.

Related

How to properly wrap server response to client

Task:
Make a single wrapper for server responses to the client.
My decision:
Create an ApiResponse object and use it in the controller and services
Am I doing the right thing? Sorry I don't know much about this...
ApiResponce
#Data
public class ApiResponse {
private Date timestamp;
private int status;
private String message;
private Object data;
public ApiResponse(int status, String message, Object data) {
this.timestamp = new Date();
this.status = status;
this.message = message;
this.data = data;
}
Controller
#RestController
#RequestMapping("/api/v1/admin")
#RequiredArgsConstructor
#PreAuthorize("hasAuthority('ADMIN')")
public class Admin {
private final UserService userService;
#PostMapping(value = "/users/add", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<ApiResponse> addUser(#RequestBody User user) {
return ResponseEntity.ok(userService.addUser(user));
}
}
Service
public interface UserService {
ApiResponse addUser(User user);
ApiResponse updateUser(User user);
ApiResponse getUserByEmail(String email);
ApiResponse getUserById(Long id);
}
Implementation method example
#Override
public ApiResponse addUser(User user) {
log.info("Saving new user to the database. Email: {}", user.getEmail());
// Check if the user is already in the database
User useDB = userRepo.findByEmail(user.getEmail());
if (useDB != null) {
return new ApiResponse(200, "A user with this e-mail already exists in the system!", user);
}
try {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRepo.save(user);
return new ApiResponse(200, "User added successfully", null);
} catch (Exception ex) {
log.error("New user added error! " + ex.getMessage());
return new ApiResponse(403, "New user registration error! " + ex.getMessage(), null);
}
}
Am I moving in the right direction? Or is it a sign of bad code?
Actually what I tried above)
As per my knowledge, you're doing good. Make sure to use BCryptPasswordEncoder in Configuration file in order to make password encrypted.

how to convert MessageResponse type to ResponseEntity<?> return type

I have a Service Class which has following method
NewCartService.java:
#Service
public class NewCartService {
#Autowired
private LoginRepository loginRepository;
#Autowired
private ProductRepository productRepository;
#Autowired
private CartRepository cartRepository;
#Autowired
private CartDao cartDao;
#Autowired
private Mailer mailService;
public MessageResponse order(List<Cart> cart) throws MessagingException {
for (Cart cart1 : cart) {
String userName = cart1.getUserName();
String password = cart1.getPassword();
String productName = cart1.getProductName();
String price = cart1.getPrice();
String discription = cart1.getDiscription();
if (!cartRepository.existsAllByUserNameAndPasswordAndProductNameAndPriceAndDiscription(userName, password, productName, price, discription)) {
throw new ResourceNotFoundException("not found");
}
MustacheFactory mf = new DefaultMustacheFactory();
Mustache m = mf.compile("cart.mustache");
StringWriter writer = new StringWriter();
String messageText = "";
List<Cart> carts = cartDao.getCart(cart);
Map<String, Object> params = new HashMap<>();
params.put("carts", carts);
Writer m1 = m.execute(writer, params);
System.out.println(m1);
messageText = m1.toString();
mailService.sendMail("/*email address*/", "/*email address*/", messageText, "demo", true);
cartRepository.deleteByUserNameAndPasswordAndProductNameAndPriceAndDiscription(userName, password, productName, price, discription);
return new MessageResponse("product Successfully ordered from cart");
}
throw new BadArgumentsException("bad arguments");
}
}
I have controller
CartController.java:
#RestController
public class CartController {
#Autowired
public CartService cartService;
#GetMapping("/orders")
public ResponseEntity<?> orders(#Valid #RequestBody List<Cart> carts) throws MessagingException {
return newCartService.order(carts);// it gives error because i need to convert MessageResponse into the ResponseEntity<?>
}
}
Now my Question is that how can i convert these MessageResponse into the ResponseEntity<?> ?
please suggest me code so that i can solve these issue and Thanks in Advance.
Have you tried:
return new ResponseEntity<>(newCartService.order(carts), HttpStatus.OK);
or as suggested in the comments:
return ResponseEntity.ok(newCartService.order(carts));
In addition if you want set header with response entity you can try:
HttpHeaders headers = new HttpHeaders();
headers.add("Custom-Header", "<header>");
return new ResponseEntity<>(newCartService.order(carts), headers, HttpStatus.OK);
alternative you can use:
return ResponseEntity.ok()
.header("Custom-Header", "<header>")
.body(newCartService.order(carts));

#SessionAttribute in java/spring losing data?

hi i have a problem with my project (small blog site) that i can't handle for a while
that's my LoginController
'''
#Controller
#SessionAttributes("currentUser")
public class LoginController {
#Autowired
UserService userService;
#ModelAttribute("currentUser")
public User setUpUserForm() {
return new User();
}
#RequestMapping(value="/login",method = RequestMethod.GET)
public String showLoginPage() {
return "loginsite";
}
#RequestMapping(value="/login",method=RequestMethod.POST)
public String userLogin(#ModelAttribute("currentUser") User user,ModelMap model,#RequestParam String login,#RequestParam String password) {
if(userService.checkUserLoginData(login, password)==true) {
user=userService.getUserByLogin(login);
System.out.println("Logged in user");
System.out.println("ID:"+user.getUserId());
System.out.println("Login:"+user.getLogin());
System.out.println("Password:"+user.getPassword());
System.out.println("Email:"+user.getEmail());
return "welcomesite";
}else {
model.put("message", "Check your login and password ! ");
return "loginsite";
}
}
}
'''
that's my UserController
'''
#Controller
public class UserController {
#Autowired
UserService userService;
#RequestMapping(value="/",method = RequestMethod.GET)
public String posts() {
return "redirect:/posts";
}
#RequestMapping(value="/createaccount",method = RequestMethod.GET)
public String showRegisterPage() {
return "registrationpage";
}
#RequestMapping(value="/createaccount",method = RequestMethod.POST)
public String createAccount(ModelMap model,#RequestParam String login,#RequestParam String password,#RequestParam String email) {
userService.addUser(new User(login,password,email));
return "redirect:/login";
}
#RequestMapping(value="/login/accountsettings",method = RequestMethod.GET)
public String showAccountSettings(#SessionAttribute("currentUser") User user) {
System.out.println("amil"+user.getEmail());
return "userSettings";
}
#RequestMapping(params="update",value="/login/accountsettings",method = RequestMethod.POST)
public String updateAccountSettings(#SessionAttribute("currentUser") User user,#RequestParam String login,#RequestParam String password,#RequestParam String email) {
user=userService.updateUser(new User(login,password,email));
return "redirect:/login";
}
#RequestMapping(params="delete",value="/login/accountsettings",method = RequestMethod.POST)
public String deleteAccount(#RequestParam String login) {
userService.deleteUser(login);
return "redirect:/posts";
}
'''
i would like to pass user data after logging in to next pages for ex /login/accountsettings or even to have user id to add post with his id as a creator of this post. After logging in everythink is okay i have complete user data but when im tring to get them in /login/accountsettings User is empty(full of null values).what am I doing wrong?
output:
enter image description here
or I have a question, is there another better way to transfer user data until logging out?
Thanks for help!

Architecture pattern for "microservice" with hard logic (Spring boot)

i've got a microservice which implements some optimization function by calling many times another microservice (the second one calculates so called target function value and the first micriservice changes paramters of this tagrget function)
It leads to necessity of writing some logic in Rest Controller layer. To be clear some simplified code will be represented below
#RestController
public class OptimizerController {
private OptimizationService service;
private RestTemplate restTemplate;
#GetMapping("/run_opt")
public DailyOptResponse doOpt(){
Data iniData = service.prepareData(null);
Result r = restTemplate.postForObject(http://calc-service/plain_calc", iniData, Result.class);
double dt = service.assessResult(r);
while(dt > 0.1){
Data newData = service.preapreData(r);
r = restTemplate.postForObject(http://calc-service/plain_calc", newData , Result.class);
dt = service.assessResult(r);
}
return service.prepareResponce(r);
}
As i saw in examples all people are striving to keep rest controller as simple as possible and move all logic to service layer. But what if i have to call some other microservices from service layer? Should i keep logic of data formin in service layer and return it to controller layer, use RestTemplate object in service layer or something else?
Thank you for your help
It is straightforward.
The whole logic is in the service layer (including other services).
Simple example:
Controller:
#RestController
#RequestMapping("/api/users")
public class UserController {
private final UserManager userManager;
#Autowired
public UserController(UserManager userManager) {
super();
this.userManager = userManager;
}
#GetMapping()
public List<UserResource> getUsers() {
return userManager.getUsers();
}
#GetMapping("/{userId}")
public UserResource getUser(#PathVariable Integer userId) {
return userManager.getUser(userId);
}
#PutMapping
public void updateUser(#RequestBody UserResource resource) {
userManager.updateUser(resource);
}
}
Service:
#Service
public class UserManager {
private static final Logger log = LoggerFactory.getLogger(UserManager.class);
private final UserRepository userRepository;
private final UserResourceAssembler userResourceAssembler;
private final PictureManager pictureManager;
#Autowired
public UserManager(
UserRepository userRepository,
UserResourceAssembler userResourceAssembler,
PictureManager pictureManager
) {
super();
this.userRepository = userRepository;
this.userResourceAssembler = userResourceAssembler;
this.pictureManager= pictureManager;
}
public UserResource getUser(Integer userId) {
User user = userRepository.findById(userId).orElseThrow(() -> new NotFoundException("User with ID " + userId + " not found!"));
return userResourceAssembler.toResource(user);
}
public List<UserResource> getUsers() {
return userResourceAssembler.toResources(userRepository.findAll());
}
public void updateUser(UserResource resource) {
User user = userRepository.findById(resource.getId()).orElseThrow(() -> new NotFoundException("User with ID " + resource.getId() + " not found!"));
PictureResource pictureResource = pictureManager.savePicture(user);
user = userResourceAssembler.fromResource(user, resource);
user = userRepository.save(user);
log.debug("User {} updated.", user);
}
}
Service 2:
#Service
public class PictureManager {
private static final Logger log = LoggerFactory.getLogger(PictureManager.class);
private final RestTemplate restTemplate;
#Autowired
public PictureManager(RestTemplate restTemplate) {
super();
this.restTemplate = restTemplate;
}
public PictureResource savePicture(User user) {
//do some logic with user
ResponseEntity<PictureResource> response = restTemplate.exchange(
"url",
HttpMethod.POST,
requestEntity,
PictureResource.class);
return response.getBody();
}
}
Repository:
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsername(String username);
}

How to pass userid from one table to another table in spring mvc using hibernate

I'm using Spring security for the login. I have the User.java which contains user-details.
#Entity(name = "user_table")
//#Table(name = "user_table")
public class User {
#Id
#Column(name = "id")
private String userId;
#Column(name = "email" ,unique = true)
private String userEmail;
#Column(name = "password")
private String userPassword;
//getter and setters
}
I'm getting the whole data of the current user from the table by using spring security. This is the code:
public User findUserByEmail(String email) {
List<User> users = new ArrayList<User>();
try{
users = sessionFactory.getCurrentSession().createQuery("from user_table where email= ?").setParameter(0, email).list();
System.out.println("user is " +users);
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
if (users.size() > 0) {
return users.get(0);
} else {
return null;
}
}
#Override
public User getCurrentUser() {
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
User currentUser = new User();
if (!(auth instanceof AnonymousAuthenticationToken)) {
UserDetails userDetails = (UserDetails) auth.getPrincipal();
System.out.println("User has authorities: "
+ userDetails.getAuthorities());
System.out.println("USERNAME:: "+userDetails.getUsername());
currentUser = findUserByEmail(userDetails
.getUsername());
System.out.println("currentUser "+currentUser);
System.out.println("currentUser "+currentUser.getUserId());
return currentUser;
}
return null;
}
What I want is to send the user id which I'm getting from currentUser.getUserId() to some other method. In that method I'm mapping to some other table like user_detail table where id is primary key. By sending id, I will get the other user_details which are not present in the user_table.
This is my UserDetail:
#Entity(name = "user_detail")
#Table(name = "user_detail")
public class UserDetail {
#Id
#GeneratedValue
#Column(name = "id")
private String userId;
//some other details like Address .
//getter and setter.
}
From controller I'm calling the above method like this:
UserService userService = new UserService();
User user=userDao.getCurrentUser();
String userId = user.getUserId();
System.out.println(userId);
UserDetail u=userDao.findUserById(userId);
and this is the method where I pass the current user id :
public UserDetail findUserById(String id) {
// TODO Auto-generated method stub
List<String> users = new ArrayList<String>();
try{
users = sessionFactory.getCurrentSession().createQuery("from user_detail where id= ?").setParameter(0, id).list();
System.out.println("user is " +users);
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
if (users.size() > 0) {
return null;
} else {
return null;
}
}
Now the result I'm getting here is null . Like user is null. What I'm doing wrong here?
There are several problems in your code. Just to point out some of them:
UserService userService = new UserService(); - you're manually creating the service object and not letting Spring-MVC injecting it into your controller, i.e. :
#Autowired
private UserService userService ;
UserDAO should be injected in your service, and not called from your controller :
class UserServiceImpl implements UserService{
#Autowired
private UserDAO userDAO;
}
All operations from your controller should call services methods and not DAO's methods. The service should use the DAO for database access. i.e.
UserDetail u=userDao.findUserById(userId);
should become
UserDetail u = userService.findUserById(userId);
and in your service :
class UserServiceImpl implements UserService{
#Autowire
private UserDAO userDAO;
#Override
public UserDetail findUserById(Long userId){
return userDAO.findUserById(userId);
}
}
if (users.size() > 0) {
return null;
} else {
return null;
}
is always returning null. Should be :
if (`users.isEmpty()){
return users.get(0);
}else { return null;}
users = sessionFactory.getCurrentSession().createQuery("from user_detail where id= ?").setParameter(0, id).list();
Your query is wrong. You should use your current bean class name and not the table name in your query, i.e. createQuery("FROM UserDetail WHERE id = ?")

Categories