По умолчанию при выборе способа доступа к полю Hibernate ориентируется на положение обязательной аннотации @Id. Если @Id стоит над полем, то доступ (установка и чтение значений) ко всем полям будет осуществляться через механизмы рефлексии непосредственно на поле. Если аннотация над геттером, то значения полей будут устанавливаться и считываться Hibernate’ом через геттеры и сеттеры (при этом аннотация над сеттером никогда не ставится).
Изменить способ доступа к отдельному полю можно с помощью аннотации @Access.
Создадим минимальное Spring Boot приложение с поддержкой JPA/Hibernate
Создадим класс предметной области следующего содержания:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
@Entity public class Person { @Id @GeneratedValue private Long id; @Access(AccessType.PROPERTY) private String name; public int age; public Person() {} public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name.toUpperCase(); } public void setName(String name) { this.name = name + "!"; } public int getAge() { return age + 1; } public void setAge(int age) { this.age = age + 1; } } |
Аннотация @Id стоит над полем, а значит по умолчанию Hibernate будет читать и записывать данные полей непосредственно через сами поля.
Над полем name мы ставим аннотацию @Access с параметром AccessType.PROPERTY. Эта аннотация переопределит поведение Hibernate’а по умолчанию для этого поля и сделает так, что Hibernate перед сохранением в БД будет читать данные этого поля через геттер и в БД сохранится то, что вернёт этот геттер. А при обратной записи данных из БД в объект будет использоваться сеттер.
Соответственно, если мы посмотрим на геттер и сеттер поля name, то мы ожидаем, что в БД данные поля будут записаны преобразованными к верхнему регистру. А при отображении данных из БД в объект, к данным поля будет присоединяться восклицательный знак (хотя в БД его нет).
Над полем age мы не ставим никаких аннотаций и поэтому ожидаем, что хотя геттер и сеттер этого поля как-то манипулируют его значением, Hibernate этого никогда не увидит, так как будет работать со значением поля напрямую.
Если бы аннотация @Id стояла над геттером поля id (здесь мы его для краткости опустили), то Hibernate по умолчанию работал бы с геттерами и сеттерами всех полей. Тогда для переопределения поведения с конкретным полем, нужно было использовать аннотацию @Access с парамтером AccessType.FIELD. Таким образом параметры означают:
- AccessType.PROPERTY — работать с геттерами/сеттерами;
- AccessType.FIELD — работать с полем напрямую.
Проверим работу аннотации @Access. Создадим репозиторий:
1 2 3 |
@Repository public interface PersonRepository extends JpaRepository<Person, Long> { } |
Создадим тест со следующим содержанием:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@SpringBootTest class SpringHibernatePostgresqlApplicationTests { @Autowired PersonRepository personRepository; @Test void accessTest() { Person irina = new Person("Irina", 30); personRepository.save(irina); List<Person> tableData = personRepository.findAll(); assertEquals(tableData.get(0).age, 30); assertEquals(tableData.get(0).getName(), "IRINA!"); } } |
В тесте мы создаём объект irina, где в поле name устанавливаем значение «Irina», а в age — 30.
При сохранении в базу для чтения поля name Hibernate использует геттер, который в нашем случае приводит сроку к верхнему регистру. При чтении поля age Hibernate будет смотреть в поле напрямую. И хотя геттер поля age тоже что-то модифицирует, Hibernate этого не увидит.
И действительно, если запустить тест, а затем посмотреть содержимое БД,то мы увидим, что всё отработало, как ожидалось:
Затем мы извлекаем данные из таблицы и проверяем их. Здесь сработают те же механизмы: при заполнении объекта данными из БД Hibernate будет использовать поле age напрямую, а в name установит значение через сеттер. Таким образом получится, что в поле age попадёт значение 30, хотя сеттер этого поля что-то модифицирует. А в name попадёт «IRINA» из БД плюс «!», добавленный сеттером, то есть будет «IRINA!».
Ассерты теста подтвердят, что всё работает именно так, как и ожидалось.