How can I create a personalized method using JPA? - java

I've been trying to create a personalized get request to find an user by email using Jpa Repository and a Controller class but it doesn't seem to work. Everytime I make a request using an email that exists (!!!!) on the database my method can't find it!
this is my interface:
#Repository
#Transactional
public interface TheUserRepository extends JpaRepository<User, Integer> {
User findByEmail(#Param("email") String email);
}
this is the controllers method:
#GetMapping(value="emails/{email}")
public ResponseEntity<User> findByEmail(String email){
User entity=repo.findByEmail(email);
if(entity!=null) {
return ResponseEntity.ok().body(entity);
}
else {
return ResponseEntity.noContent().build();
}
}
I have tried many other combinations but none of them are working, if anyone has any idea of how to do this request I would appreciate it so much!

Related

I want to transmit a status code if the query is successful with Spring boot, how can I do it?

Although this situation is easy for ready overrided methods, I couldn't find a way for my own query.
This is my repository :
public interface CommentRepository extends JpaRepository<User , Long >{
#Modifying
#Transactional
#Query( value="delete from users where first_name=:name" , nativeQuery=true )
public void delete( String name );
}
This is my controller :
#RestController
#RequestMapping(path="/api/v1/users")
public class CommentController {
#Autowired
CommentRepository repository ;
// Delete user
#DeleteMapping(path="/delete")
public void delete(#RequestParam String name) {
repository.delete(name) ;
}
}
For example, if I delete a user, I want to pass a status code of 200 to the developer if the query is successful.
However I want to pass different codes if the query fails.
ResponseEntity represents the whole HTTP response: status code, headers, and body. As a result, we can use it to fully configure the HTTP response.
Have a look at Response entity using which you will be able to configure everything including status codes .
https://www.baeldung.com/spring-response-entity
In the rest controller you can do something like:
#RestController
#RequestMapping(path="/api/v1/users")
public class CommentController {
#Autowired
CommentRepository repository ;
// Delete user
#DeleteMapping(path="/delete")
public ResponseEntity<Void> delete(#RequestParam String name) {
repository.delete(name);
return ResponseEntity.ok().build();
}
}
Since I don't know your database structure, let's say a SQLIntegrityConstraintViolationException can be thrown, you can create a service layer that will handle the exception. You will end up with something like:
#RequiredArgsConstructor
public class CommentServiceImpl implements CommentService {
private final CommentRepository commentRepository;
#Override
public void deleteUsersByName(String name) {
try {
commentRepository.delete(name); //consider changing the repo method name 'delete' to be more contextual like 'deleteAllByName(String name)'
} catch (Exception | SQLIntegrityConstraintViolationException e) //or other type, depending on your database structure
throw new MyCustomException("my message: " + e); //create new RuntimeException with the name you prefer
}
}
Then you have lots of ways to handle your new exception. Please read more here: https://www.baeldung.com/exception-handling-for-rest-with-spring
One of the ways is to have this inside your #RestController class
#ExceptionHandler({MyCustomException.class})
public ResponseEntity<Void> handleConstrainViolationException() {
return ResponseEntity.internalServerError(); //just an example
}
for the last part you can play around with the exceptions thrown on the service layer and return appropriate status code from the corresponding exception handler. Consider having a global exception handler as stated into the article on Baeldung above. Hope it helps a little bit.

spring boot return Not Found

I need to create a rest method to get a client by id in postman, I even created the method, but it doesn't return any information by id with spring boot.
ClientControle.java:
#GetMapping(value = "/clientes/{id}")
public Cliente listCliente(#PathVariable("id") long id){
return clienteService.getById(id);
ClienteService:
public interface ClienteService {
Cliente getById(long id);
List<Cliente> getAll();
Cliente save(Cliente cliente);
}
but i have the following error:
You have #RequestMapping("clientes") at the controller(class) level,
so your actual URL should be http://localhost:8080/clientes/clientes/1
As per your code in image, you shared you are having clientes on class level also either you can remove from here then localhost:8080/clientes/1 will work or you need to use localhost:8080/clientes/clientes/1

Type Mismatch cannot convert from type Optional<User> to User

I am trying to create a website that allows the user to update, edit, delete, etc., and I have got to the part of Updating or Editing user’s information. I have tried multiple times using different ways, but I cannot seem to get past the error. I am completely oblivious to Optional<> I just don’t get it. I have read https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html, but i dont understand how it should be coded, its just not clicking. If someone could please inform on how it should be coded in my code and please explain it I would be so grateful. Maybe its because im overworked and have not slept, but i cannot seem to correct this error. This is the error i get on the page when i attempt to edit the information for a user:
There was an unexpected error (type=Internal Server Error, status=500).
For input string: "id"
java.lang.NumberFormatException: For input string: id
//Repository
public interface UserRepository extends CrudRepository<User, Integer> {
}
here is the UserService
//UserService
#Service
#Transactional
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository=userRepository;
}
public void saveMyUser(User user) {
userRepository.save(user);
}
public List<User> showAllUsers(){
List<User> users = new ArrayList<User>();
for(User user: userRepository.findAll()) {
users.add(user);
}
return users;
}
public void deleteMyUser(int id) {
userRepository.deleteById(id);
}
public User editUser (int id) {
return userRepository.findById(id);//I also get an error here as well
}
}
here is the controller
//Application Controller
#Controller
public class ApplicationController {
#Autowired
private UserService userService;
// THIS IS WHERE I GET THE ERROR
#RequestMapping("/edit-user")
public String editUser(#RequestParam int id,HttpServletRequest request) {
/* OPTIONAL<?> is this where i would implement the
optional what do i have to put here exactly?
I tried some ways I read about but its not working for me */
request.setAttribute("user", userService.editUser(id));
request.setAttribute("mode", "MODE_UPDATE");
return "welcome";
}
}
Thank you for the help in advance Im a little frustrated with this because I have been trying to correct this error all night.
There are several ways to convert from an option to an entity. You can use the following:
Use get() method:
public User editUser (int id) {
return userRepository.findById(id).get();
}
Use orElse method:
public User editUser (int id) {
/* new User() is stab if user was not found */
return userRepository.findById(id).orElse(new User());
}
Use orElseThrowMethod:
public User editUser (int id) {
/* Throw exception if user was not found*/
return userRepository.findById(id).orElseThrow(IllegalArgumentException::new));
}
As for controller it will be like this:
#RequestMapping("/edit-user")
public String editUser(#RequestParam int id,HttpServletRequest request) {
User user = userService.editUser(id);
request.setAttribute("user", user);
request.setAttribute("mode", "MODE_UPDATE");
return "welcome";
}
Also there similar question for your topic:
Spring Boot. how to Pass Optional<> to an Entity Class

Different return types for function Java

I'm using Spring Boot with Data JPA.
I have the following code.
A User Class with name and an informative message.
class UserResponse{
private String name;
private String message;
}
User JPA Repository which finds userBy id;
interface UserRepository{
Optional<User> findUserById(String id);
}
User Service which invokes repo and set message if user not found
class UserService(){
UserResponse user = new UserResponse();
public UserResponse getUserById(String userId){
Optional<User> useroptional = userRepository.findById(userId);
if(userOptional.isPresent()){
user.setName(userOptional.get().getName());
}else{
user.setMessage("User Not Found");
}
}
UserController has to set proper HTTP status code as per the message.
class UserController(){
public ResponseEntity<UserResponse> getUserById(String id){
UserResponse user = userService.getUserById(id);
HttpStatus status = OK;
if(!StringUtils.isEmpty(user.getMessage())){
status = NOT_FOUND;
}
return new ResponseEntity<>(user,status);
}
}
The problems I have faced is inorder to set proper status code in controller layer I have to inspect user message,which i didn't like.
Is there anyway we can create a control flow for Success and Failure cases.
Say One Return type and flow for Success scenario and vice-versa.
I know Scala has this feature with Either keyword.
Is there any alternate in Java ?
Or any other approach I can use to handle this better...
One approach would be returning RepsonseEntity in service layer itself with proper status code but setting status code is controller's Responsibility is what I felt.
In case of failure you can throw custom Exception with proper message. Then you can catch it in #ControllerAdvice. I'll add an example in a moment.
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(MyCustomException.class)
public ResponseEntity<String> exception(MyCustomException e) {
return new ResponseEntity(e.getMessage(), HttpStatus.NotFound);
}
}
In one #ControllerAdvice one could have more methods listening for different Exceptions. Custom Exception can hold whatever you want - it's a normal class - so you can return ResponseEntity of whatever you want.
For example:
#Transactional(readOnly = true)
#GetMapping("/{id}")
public ResponseEntity<?> getUserById(#PathVariable("id") String userId) {
return userRepository.findById(userId)
.map(user -> ResponseEntity.ok().body(user))
.orElse(new ResponseEntity<>(/* new ErrorMessage */, HttpStatus.NOT_FOUND))
}
For 'not found' response you have to create an error message object and return it to client.

Spring service class contains too many finder methods

I am using Spring framework and Spring Data JPA to develop an application. Below are one of the repository interface and service class.
public interface UserRepository extends JpaRepository<User, Long>
User findByName(String name);
User findByEmail(String email);
}
public class DefaultUserService implements UserService {
#Inject protected UserRepository userRepo;
#Override
public User getUserById(Long id) {
return userRepo.findOne(id);
}
#Override
public User getUserByName(String name) {
return userRepo.findByName(name);
}
#Override
public User getUserByEmail(String email) {
return userRepo.findByEmail(email);
}
}
As stated by many experts, service layer design should be coarse grained and focused on application operations. Looking at the service class above, I believe that is not a good design as it directly expose all finder methods from the repository. Since all 3 service methods above are returning the same object type (User), I would want to expose only one finder method instead of three that able to encapsulate all finder logic.
public class DefaultUserService implements UserService {
#Inject protected UserRepository userRepo;
// what would be the arguments and logic for this method.
#Override
public User getUser() {
}
}
I appreciate if anyone can point me the solution on how to solve this design issue?
I think the design is not so bad, I mean I was seeing that kind of approach several times, in fact you have several finder methods but each one use different property to obtain the User, if you want to make a service method which encapsulate the logic to retrieve the user I would suggest something like this.
public class DefaultUserService implements UserService {
#Inject protected UserRepository userRepo;
enum UserFindEnum{
ID, EMAIL, NAME;
}
public User getUser(UserFindEnum e, Object obj){
switch(e.ordinal()){
case 0:
return userRepo.findOne(obj);
case 1:
return userRepo.findByName(obj);
case 2:
return userRepo.findByEmail(obj);
default:
break;
}
}
}
I mean you need to know which property you will use to find the User so at least one parameter need to be sent to the service layer so getUser() it is not enough. Probably using some kind of logic as above you will have only one service method and needed logic within it.

Categories