Почему Hibernate не требует конструктора аргументов?
Конструктор без аргументов является требованием (такие инструменты, как Hibernate, используют reflection этого конструктора для создания объектов).
Я получил этот волнистый ответ, но может ли кто-нибудь объяснить дальше? благодаря
- org.hibernate.MappingException: Не удалось определить тип для: java.util.List, at table: College, для столбцов:
- Классы classов Hibernate должны быть Serializable?
- Hibernate: MyInterceptor # onFlushDirty никогда не вызывается
- Как удалить объект с отношениями ManyToMany в JPA (и соответствующие строки таблицы соединений)?
- Указание индекса (не-уникальный ключ) с использованием JPA
- Автоматическое резервирование зарезервированного слова для таблиц и столбцов Hibernate
- @Basic (необязательно = false) vs @Column (nullable = false) в JPA
- Что такое ленивая загрузка в Hibernate?
- Почему вы должны использовать ORM?
- Каковы преимущества использования ORM?
- В чем разница между JPA и Hibernate?
- Нарушение спящего режима с помощью orphanRemoval
- Hibernate / JPA - аннотирование методов бобов и полей
Hibernate и код в целом, который создает объекты через reflection, использует Class
для создания нового экземпляра ваших classов. Этот метод требует, чтобы публичный конструктор no-arg мог создавать экземпляр объекта. Для большинства случаев использование конструктора no-arg не является проблемой.
Существуют хаки, основанные на сериализации, которые могут работать без использования конструктора no-arg, поскольку сериализация использует jvm magic для создания объектов без вызова конструктора. Но это не доступно для всех виртуальных машин. Например, XStream может создавать экземпляры объектов, у которых нет открытого конструктора no-arg, но только путем запуска в так называемом «расширенном» режиме, который доступен только на определенных виртуальных машинах. (Подробнее см. Ссылку). Дизайнеры Hibernate, безусловно, решили поддерживать совместимость со всеми виртуальными машинами и поэтому избегают таких трюков и используют официально поддерживаемый метод отражения Class
требующий конструктора no-arg.
Спящий режим запускает объекты. Таким образом, он должен иметь возможность создавать их. Если конструктор no-arg отсутствует, Hibernate не будет знать, как его создать, то есть, какой аргумент должен пройти.
В документации спящего режима говорится:
4.1.1. Внедрить конструктор без аргументов
Все постоянные classы должны иметь конструктор по умолчанию (который может быть непубличным), чтобы Hibernate мог создавать их с помощью Constructor.newInstance()
. Рекомендуется, чтобы у вас был конструктор по умолчанию, имеющий хотя бы видимость пакета для генерации прокси-сервера во время работы в Hibernate.
Спящий режим представляет собой структуру ORM, которая поддерживает страtagsю доступа к полям или свойствам. Однако он не поддерживает построение на основе конструктора – возможно, что бы вы хотели? – из-за некоторых
1º Что произойдет, если ваш class содержит много конструкторов
public class Person { private String name; private Integer age; public Person(String name, Integer age) { ... } public Person(String name) { ... } public Person(Integer age) { ... } }
Как вы можете видеть, вы имеете дело с проблемой несогласованности, потому что Hibernate не может предположить, какой конструктор должен быть вызван. Например, предположим, что вам нужно восстановить сохраненный объект Person
Person person = (Person) session.get(Person.class, );
Какой конструктор должен Hibernate вызвать для извлечения объекта Person? Видишь ?
2º И, наконец, с помощью отражения Hibernate может создать экземпляр classа через его конструктор no-arg. Поэтому, когда вы звоните
Person person = (Person) session.get(Person.class, );
Hibernate будет создавать экземпляр объекта Person следующим образом
Person.class.newInstance();
Что по документации API
Класс создается таким образом, как будто новым выражением с пустым списком аргументов
Мораль истории
Person.class.newInstance();
похож на
new Person();
Ничего больше
Erm, извините всех, но Hibernate не требует, чтобы ваши classы имели конструктор без параметров. Спецификация JPA 2.0 требует этого, и это очень слабое от имени JPA. Другие frameworks, такие как JAXB, также требуют этого, что также очень слабое от имени этих фреймворков.
(Фактически, JAXB, предположительно, позволяет предприятиям-основателям, но он настаивает на создании экземпляров этих фабрик сам по себе, требуя, чтобы у них был какой-то бескомпромиссный конструктор , который в моей книге точно так же хорош, как не позволяет фабрикам, насколько хромой является то, что !)
Но Hibernate не требует такого.
Hibernate поддерживает механизм перехвата (см. «Перехватчик» в документации ), который позволяет вам создавать объекты с любыми параметрами конструктора, в которых они нуждаются.
В основном, что вы делаете, так это то, что при настройке спящего режима вы передаете ему объект, реализующий интерфейс org.hibernate.Interceptor
, а hibernate будет вызывать метод instantiate()
этого интерфейса, когда ему нужен новый экземпляр вашего объекта , поэтому ваша реализация этого метода может создавать new
объекты, как вам нравится.
Я сделал это в проекте, и он работает как шарм. В этом проекте я делаю все через JPA, когда это возможно, и я использую только функции Hibernate, такие как перехватчик, когда у меня нет другого выбора.
Hibernate кажется несколько небезопасным, так как во время запуска он выдает информационное сообщение для каждого из моих classов сущностей, сообщая мне INFO: HHH000182: No default (no-argument) constructor for class
и class must be instantiated by Interceptor
, но затем позже я делаю их экземпляр перехватчиком, и он доволен этим.
Чтобы ответить на вопрос «почему» в вопросе о инструментах, отличных от Hibernate , ответ «абсолютно без веской причины», и это подтверждается наличием перехватчика спящего режима. Есть много инструментов, которые могли бы поддерживать какой-то аналогичный механизм для создания объектов клиента, но они этого не делают, поэтому они сами создают объекты, поэтому им нужно требовать конструкторы без параметров. У меня возникает соблазн полагать, что это происходит потому, что создатели этих инструментов считают себя программистами ниндзя-систем, которые создают фреймворки, полные магии, которые будут использоваться неосведомленными программистами приложений, которые (так они думают) никогда бы в своих самых смелых мечтах не имели нужны для таких продвинутых конструкций, как … Factory Pattern . (Хорошо, я искушаюсь так думать. На самом деле я так не думаю. Я шучу).
Фактически, вы можете создавать экземпляры classов, у которых нет конструктора 0-args; вы можете получить список конструкторов classа, выбрать один и вызвать его с фиктивными параметрами.
Хотя это возможно, и я думаю, что это сработает и не будет проблематичным, вам придется согласиться с тем, что это довольно странно.
Построить объекты так, как это делает Hibernate (я считаю, что он вызывает конструктор 0-arg, а затем он, вероятно, модифицирует поля экземпляра напрямую через Reflection. Возможно, он знает, как вызывать сеттеры) немного отличается от того, как объект должен быть построен в Java-вызов конструктора с соответствующими параметрами, чтобы новый объект был объектом, который вы хотите. Я считаю, что создание экземпляра объекта, а затем его мутация – это нечто вроде «анти-Java» (или, я бы сказал, анти чистой теоретической Java), и, безусловно, если вы это сделаете с помощью прямых манипуляций с полями, это будет инкапсуляция и все, что причудливо инкапсулирует ,
Я считаю, что правильным способом сделать это было бы определение в Hibernate-сопоставлении того, как объект должен быть создан из информации в строке базы данных с использованием соответствующего конструктора … но это было бы более сложным, поскольку оба Hibernate были бы четными более сложным, отображение будет более сложным … и все будет более «чистым»; и я не думаю, что это будет иметь преимущество перед текущим подходом (за исключением чувства хорошего в том, чтобы делать вещи «надлежащим образом»).
Сказав это и увидев, что подход Hibernate не очень «чист», обязательство иметь конструктор 0-arg не является строго необходимым, но я могу немного понять это требование, хотя я считаю, что они делали это исключительно «правильно» «основания, когда они отклонялись от« надлежащего пути »(хотя и по разумным причинам) задолго до этого.
Hibernate должен создавать экземпляры в результате ваших запросов (через reflection), Hibernate полагается на конструктор no-arg для объектов для этого, поэтому вам нужно предоставить конструктор no-arg. То, что не ясно?
Гораздо проще создать объект с помощью безпараметрического конструктора посредством отражения, а затем заполнить его свойства данными путем отражения, чем пытаться сопоставить данные с произвольными параметрами параметризованного конструктора с изменением конфликтов имен / имен, неопределенной логики внутри конструктора, параметры не соответствуют свойствам объекта и так далее.
Многие ORM и сериализаторы требуют конструкторов без параметров, поскольку параметризированные конструкторы через reflection очень хрупкие, а конструкторы без параметров обеспечивают как стабильность приложения, так и контроль над поведением объекта разработчику.
Hibernate использует прокси для ленивой загрузки. Если вы не определяете конструктор или не делаете его закрытым, некоторые вещи могут по-прежнему работать – те, которые не зависят от механизма прокси. Например, загрузка объекта (без конструктора) напрямую с использованием API запросов.
Но, если вы используете метод session.load (), вы столкнетесь с InstantiationException из генератора прокси-генератора из-за отсутствия доступности конструктора.
Этот парень сообщил об аналогичной ситуации:
http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html
Ознакомьтесь с этим разделом спецификации языка Java, который объясняет разницу между статическими и нестационарными внутренними classами: http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3
Статический внутренний class концептуально не отличается от обычного общего classа, объявленного в файле .java.
Поскольку Hibernate необходимо создавать ProjectPK независимо от экземпляра Project, ProjectPK либо должен быть статическим внутренним classом, либо объявлен в его собственном .java-файле.
reference org.hibernate.InstantiationException: Нет конструктора по умолчанию