Home > Software design >  Parsing request body data into object in Java Spring boot
Parsing request body data into object in Java Spring boot

Time:11-23

I am trying to parse a request body into an object (I am using Java Spring boot).

This is how my controller looks like:

public class UserController {
    @PutMapping("/lock/{id}")
    public Optional<User> lockUser(@PathVariable Long id, @Validated @RequestBody UserLockRequest user) {
        return userService.lockUser(id, user);
    }
}

My UserService looks like this:

public Optional<User> lockUser(Long userId, UserLockRequest userLockRequest) {
    Optional<User> user = userRepository.findById(userId);

    user.get().setLocker(userLockRequest.getLocker());
    userRepository.save(user.get());
    return user;
}

And my request class UserLockRequest looks like this:

public class UserLockRequest {
    @NotBlank
    @NotNull
    private Locker locker;

    public Locker getLocker() {
        return locker;
    }

    public void setLocker(Locker locker) {
        this.locker = locker;
    }
}

And my request looks like this:

curl --location --request PUT 'http://localhost:8081/user/lock/8' \
--header 'Content-Type: application/json' \
--data-raw '{
    "locker_id": "1"
}'

My User entity contains locker field:

@OneToOne
@JoinColumn(name = "locker_id")
private Locker locker;

I can see that userLockRequest.getLocker() in the UserService is always null.

I am trying to assign a Locker to a User object and save it in the database.

I am not sure how to map locker_id from the PUT request to UserLockRequest which I use for accepting the request.

Any help is much appreciated :)

CodePudding user response:

You will need to get Locker from the database and assign it to the User. In order to achieve this you need a couple of changes:

public class UserLockRequest {
    private long locker_id;  // so that it matches your JSON, but it should really be "lockerId" and you should update your JSON

    // getter / setter
}

Then you need to adjust your UserService code as well to get the Locker from the database:

public Optional<User> lockUser(Long userId, UserLockRequest userLockRequest) {
    Optional<User> user = userRepository.findById(userId);
    Locker locker = lockerService.getById(userLockRequest.getLockerId());

    user.get().setLocker(locker);
    userRepository.save(user.get());
    return user;
}

I assumed you have a LockerService with a method returning a Locker given its ID.

Finally, avoid using Optional.get() without checking that the Optional is not empty, otherwise, you might get a NoSuchElementException. You could do something along the following lines instead:

public User lockUser(Long userId, UserLockRequest userLockRequest) {
    Optional<User> optionalUser = userRepository.findById(userId);
    Locker locker = lockerService.getById(userLockRequest.getLockerId());

    if (optionalUser.isPresent()) {
        User user = optionalUser.get();
        user.setLocker(locker);
        userRepository.save(user.);
        return user;
    } else {
        // throw some custom exception or just return null, it is your decision
    }
}

CodePudding user response:

Alright, I assume

  1. you have a User entity and a Lock entity and you need to tag a Lock entity against an user entity
  2. You have JpaRepository interfaces for both User and Lock entity.
  3. You have lombok dependency in your project

If that's correct, below is a solution I would implement. This helps in better API design and separating the responsibilities between Controller and service classes.

  1. Define UserLockRequest request body class
@Getter
@Setter
public class UserLockRequest{
   
   @NotNull
   @NotBlank
   private int userId;

   @NotNull 
   @NotBlank
   private long lockerId;
}
  1. UserService class. I use constructor based injection as recommended by spring.
@Service
public class UserService {
    
    private final UserRepository userRepository;
    private final LockerRepository lockerRepository;
    
    public UserService(UserRepository userRepository, LockerRepository lockerRepository) {
        this.userRepository = userRepository;
        this.lockerRepository = lockerRepository;
    }

    public User lockUser(UserLockRequest userLockRequest) {
        Optional<User> optionalUser =
                userRepository.findById(userLockRequest.getUserId());
        Optional<Locker> locker = lockerRepository.findById(userLockRequest.getLockerId());

        if (optionalUser.isPresent() && locker.isPresent()) {
            User user = optionalUser.get();
            user.setLocker(locker.get());
            userRepository.save(user);
            return user;
        } else {
            // Error handling is upto you based on what requirement you have
        }
    }
}
  1. UserController class
public class UserController {
    @PutMapping("/lock")
    public Optional<User> lockUser(@Validated @RequestBody UserLockRequest userLockRequest) {
        return userService.lockUser(userLockRequest);
    }
}
  1. Now below is how your http call looks like
curl --location --request PUT 'http://localhost:8081/user/lock/ \
--header 'Content-Type: application/json' \
--data-raw '{
    "user_id": 8,
    "locker_id":"1"
}'
  • Related