I have a Student class that has some fields, including "age" and "dateOfBirth". The age value is calculated and attributed inside the constructor, based on the dateOfBirth, as following:
//Student.java
private Integer id;
private String name;
private String email;
private LocalDate dateOfBirth;
@Transient
private Integer age;
public Student(String name, String email, LocalDate dateOfBirth) {
this.name = name; // ex: "John Doe"
this.email = email; // ex: "johndoe@gmail.com"
this.dateOfBirth = dateOfBirth; // ex: LocalDate.of(2002, Month.MAY, 1));
this.age = Period.between(dateOfBirth, LocalDate.now()).getYears(); // result: 21
}
The getAge()
method inside the Student class returns the age field value
//Student.java
public Integer getAge() {
return age; // Returns the expected value (21)
}
(getters for every other field have the same structure as the getAge()
: they return the field's value)
I also have a simple Repository, to query data from DB. It extends from the JpaRepository
and has nothing inside it:
//StudentRepository.java
@Repository
public interface StudentRepository extends JpaRepository<Student, Integer> { }
Inside the StudentController class, I have a route to "/"
, which simply gets all the students from DB and return them:
//StudentController.java
@GetMapping("/")
public List<Student> getStudents() {
return studentService.getStudents();
}
The result I was expecting is the following, with the age field's value being 21:
[{"id":1,"name":"John Doe","email":"johndoe@gmail.com","dateOfBirth":"2002-05-01","age":21}]
Instead, I got a null
value for the age field:
[{"id":1,"name":"John Doe","email":"johndoe@gmail.com","dateOfBirth":"2002-05-01","age":null}]
But if I change the getAge()
method implementation of the Student class to:
// Student.java
public Integer getAge() {
return Period.between(dateOfBirth, LocalDate.now()).getYears();
}
I get the 21
as expected, not null
.
[{"id":1,"name":"John Doe","email":"johndoe@gmail.com","dateOfBirth":"2002-05-01","age":21}]
JPA does not use your constructor. JPA specification requires no-arg constructor. You JPA implementation can create one for you if you don't provide one no-arg constructor (For example openjpa does it, see https://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/jpa_overview_pc.html#jpa_overview_pc_no_arg).
That's why your code works when you change the getter to compute the age value.
If you don't want to recompute the age every time the getter is called you can :
public Integer getAge() {
if (age == null && dateOfBirth != null) {
age = Period.between(dateOfBirth, LocalDate.now()).getYears();
}
return age;
}