Problem in calculating the age of majority of a student in Spring Boot
I have a Student class with the following attributes:
package com.example.estudantes.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDate;
import java.time.Period;
@Entity
@Table(name = "students")
@Getter
@Setter
@NoArgsConstructor
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
private String name;
private LocalDate dateOfBirth;
private boolean ageMajority;
private LocalDate dateOfCreation;
public Student(String name, LocalDate dateOfBirth) {
this.name = name;
this.dateOfBirth = dateOfBirth;
this.ageMajority = this.isOfLegalAge(dateOfBirth);
this.dateOfCreation = LocalDate.now();
}
private boolean isOfLegalAge(LocalDate dateOfBirth) {
Period period = Period.between( dateOfBirth,LocalDate.now());
return period.getYears() >= 18 ;
}
}
here is the Repository ,Service , Controller and Pom :
Repository:
package com.example.estudantes.repository;
import com.example.estudantes.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentRepository extends JpaRepository<Student,Long> {
}
Service:
import com.example.estudantes.model.Student;
import com.example.estudantes.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepository;
public List<Student> getAllStudents(){
return studentRepository.findAll();
}
public Object getStudentById(Long id){
Optional<Student> optionalStudent = studentRepository.findById(id);
return optionalStudent.isPresent() ? optionalStudent.get() :"Student not found";
}
public Student insertStudent(Student student){
studentRepository.save(student);
return student;
}
public Object updateStudent(Long id ,Student student){
Optional<Student> optionalStudent = studentRepository.findById(id);
if (optionalStudent.isPresent()){
Student student1 = new Student(student.getName(),student.getDateOfBirth());
student1.setId(id);
studentRepository.save(student1);
return student1;
}
return "Student not found";
}
public String deleteStudent(Long id){
Optional<Student> optionalStudent = studentRepository.findById(id);
if (optionalStudent.isPresent()){
studentRepository.deleteById(id);
return "Student deleted successfully";
}
return "Student not found";
}
}
Controller:
package com.example.estudantes.controller;
import com.example.estudantes.model.Student;
import com.example.estudantes.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("student")
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping
public List<Student> getAllStudents(){
return studentService.getAllStudents();
}
@GetMapping("{id}")
public Object getStudentById(@PathVariable Long id){
return studentService.getStudentById(id);
}
@PostMapping
public Student inserirEstudante(@RequestBody Student student){
return studentService.insertStudent(student);
}
@PutMapping("{id}")
public Object updateStudent(@PathVariable Long id , @RequestBody Student student){
return studentService.updateStudent(id,student);
}
@DeleteMapping("{id}")
public String deleteStudent(@PathVariable Long id){
return studentService.deleteStudent(id);
}
}
POM.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>estudantes</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>estudantes</name>
<description>Uma aplicação sobre estudantes</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
I am using the PostgreSQL database. I tried to use several other alternatives that the artificial intelligence showed me, but they did not work.
The problem is that, when passing parameters for the date of birth (1900-11-25) and storing in the database using the POST method in Spring Boot, the isOfLegalAge() function always returns false and dateOfCreation return null, except when I use the PUT method to change.
For example: when I use postman and using POST method pass the following parameters
{
"name":"F",
"dateOfBirth":"1900-11-25"
}
it return to me(and is saved in the data base) :
{
"id": 2,
"name": "F",
"dateOfBirth": "1900-11-25",
"ageMajority": false,
"dateOfCreation": null
}
But when I use PUT method ( in the url http://localhost:8080/student/2 on postman) passing the same parameters
{
"name":"F",
"dateOfBirth":"1900-11-25"
}
It return to me (and is saved in the data base) :
{
"id": 2,
"name": "F",
"dateOfBirth": "1900-11-25",
"ageMajority": true,
"dateOfCreation": "2024-11-25"
}
I would like the ageMajority attribute to be saved as true and dateOfCreation be saved when using the POST method. How can I solve this problem?
2
Answers
Move
from constructor to callback methods:
Some additional background information:
The problem is that the Spring Framework doesn’t use the
Student(String name, LocalDate dateOfBirth)
constructor.When it receives a request (POST or PUT), it uses the NoArgs
Student()
constructor and calls the property setters. (BTW the same applies to the database backend – when hydrating an entity from the data read from the database it calls the NoArgs constructor and then calls the property setters.)Only your code in
StudentService.updateStudent()
calls theStudent(String name, LocalDate dateOfBirth)
and only then willageMajority
anddateOfCreation
be initialized.To resolve the issue you can create (and call) an initializing function that will initialize the computed fields for you or you can the annotations from the talex’ answer do let the framework do it for you.