Hibernate: Czy klasa @Entity do poprawnego działania musi posiadać konstruktor oraz settery dla pól?
Jeśli chodzi o konstruktor, to sprawa jest dość prosta. Standard JPA 2.0 wymaga bezparametrowego konstruktora. Jeśli mamy w klasie zdefiniowany konstruktor parametrowy, to musimy również wprost zdefiniować ten bezparametrowy. Jeżeli natomiast nie mamy żadnego konstruktora parametrowego, to nie musimy się o nic martwić – kompilator stworzy za nas konstruktor domyślny.
Jeśli chodzi o settery, to sprawa jest nieco bardziej skomplikowana. Wszystko zależy od tego, jakiej strategii dostępu do pól będzie używał Hibernate, a decydujemy o tym my – programiści, choć praca z ludźmi pokazuje, że często nieświadomie.
Zazwyczaj adnotację @Id umieszczamy nad polem klasy związanym z kluczem głównym:
@Entity public class Person { @Id @GeneratedValue private long id; private String lastName; public String getLastName() { return lastName; } }
W takim wypadku, Hibernate do odczytywania i zapisywania wartości atrybutów naszej klasy, będzie używał refleksji. Nie potrzebujemy więc definiować getterów oraz setterów dla pól (choć oczywiście jeśli ich potrzebujemy, to możemy to zrobić). Tę strategię możemy kojarzyć z pojęciem field-based access.
Jeśli jednak adnotację @Id umieścilibyśmy nad metodą getId(), a nie nad samym polem id, to settery będą wymagane dla wszystkich pól, które posiadają gettery. Jeśli bowiem chcemy mieć możliwość odczytywać wartość jakiegoś pola, to Hibernate musi mieć możliwość zapisania w nim jakiejś wartości. Tę strategię możemy kojarzyć z pojęciem property-based access.
@Entity public class Person { private long id; private String lastName; @Id @GeneratedValue public long getId() { return id; } public void setId(long id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
Jeśli w powyższym przykładzie nie zapewnilibyśmy settera dla pola lastName, to podczas startu aplikacji napotkalibyśmy następujący wyjątek:
- org.hibernate.PropertyNotFoundException: Could not locate setter method for property [pl.rekrutacjajava.rj.person.Person#lastName].
Przy użyciu odpowiednich adnotacji, możemy teoretycznie mieszać obie powyższe strategie, aby dla jednych pól stosować pierwszą, a dla innych drugą. Wprowadzanie takiego braku spójności rzadko będzie jednak dobrym pomysłem.
PS. Odpowiedź na to pytanie dotyczy ściśle Hibernate i jego wymagań. Jeśli pytanie miałoby bardziej ogólny wydźwięk, to warto pamiętać, że brak getterów i setterów może mieć swoje konsekwencje również w innych miejscach, np. przy serializacji/deserializacji JSONa w Springowym controllerze.