How to update a single field using jpa repository using @patch

Viewed 1927

I am developing a simple application by spring boot. I need to restrict the user to be able to only update the name, not all the filed that related to user data but unfortunately, my code has a problem that if someone sends a data in Json format and changes the age or any other field it will be updated but as I told I need the user to be able to change the only name not any other field. I have to mention I am using JPA repository and spring data

my controller

@RestController
@RequestMapping("/student")
public class StudentController {
    @Autowired
    StudentRepository repository;
    // method i user to only update the name field
    @PatchMapping("/pattt/{id}")

    public ResponseEntity partialUpdateName(
        @RequestBody Student partialUpdate, 
        @PathVariable("id") String id 
    ){
        Student.save(partialUpdate, id);
        return ResponseEntity.ok(repository.save(partialUpdate));
    };
}

JPA repository

@Repository
public interface StudentRepository extends JpaRepository<Student, Integer> {}

Student class

@Entity
@Table(name = "student")
public class Student {

    @Id
    @GeneratedValue
    private int id;
    private String name;
    private int age;
    private String emailAddress;

    public Student() {  }
    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
    public Student(int id, String name, int age, String emailAddress) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.emailAddress = emailAddress;
    }
    public static void save(Student partialUpdate, String id) {
        partialUpdate.setName(id);
    }
    public void setId(int id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public String getEmailAddress() {
        return emailAddress;
    }
}
1 Answers

The best solution for the future is to add a DTO layer to your application and use it to map to your object. See example below.

public class StudentDto {
    private String name;

    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

Then you can map this to your model by Mapstruct:

@Mapper
public abstract class StudentMapper {
    public static final StudentMapper INSTANCE = 
    Mappers.getMapper(StudentMapper.class);
      
    @Mapping
    Student studentDtoToStudent(StudentDto studentDto); 
}

Mapstruct dependencies:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-jdk8</artifactId>
    <version>1.3.0.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.3.0.Final</version>
</dependency>

You will be able to hide your internal structure from outside world.
In your conroller:

public ResponseEntity partialUpdateName(
    @RequestBody StudentDto partialUpdate, 
    @PathVariable("id") String id)
{
    Student student = 
    StudentMapper.INSTANCE.studentDtoToStudent(partialUpdate);
}

The last line will give you a safe student model which you can then save

  1. Quick solution In your controller:
public ResponseEntity partialUpdateName(
    @RequestBody Student partialUpdate, 
    @PathVariable("id") String id) 
{
    Optional<Student> optionalStudent = repository.findById(id);

    if(optionalStudent.isPresent() && partialUpdate!=null) {
        Student current=optional.get();
        current.setName(partialUpdate.getName());
        return ResponseEntity.ok(repository.save(current));     
     }  
              
     /* return an error */
}
Related