Почему Hibernate не требует конструктора аргументов?

Конструктор без аргументов является требование (такие инструменты, как использование Hibernate отражение этого конструктора объекты-экземпляры).

Я получил этот волнистый ответ, но может ли кто-нибудь объяснить дальше? Благодаря

Ответ 1

Спящий режим и код в целом, который создает объекты через отражение, использует Class<T>.newInstance(), чтобы создать новый экземпляр ваших классов. Этот метод требует, чтобы публичный конструктор no-arg мог создавать экземпляр объекта. Для большинства случаев использование конструктора no-arg не является проблемой.

Существуют хаки, основанные на сериализации, которые могут работать без создания конструктора no-arg, поскольку сериализация использует jvm magic для создания объектов без вызова конструктора. Но это не доступно для всех виртуальных машин. Например, XStream может создавать экземпляры объектов, у которых нет открытого конструктора no-arg, но только путем запуска в так называемом "так называемый" расширенный" режим, который доступен только на некоторых виртуальных машинах. (Подробнее см. Ссылку). Дизайнеры Hibernate, безусловно, решили поддерживать совместимость со всеми виртуальными машинами и поэтому избегают таких трюков и используют официально поддерживаемый метод отражения Class<T>.newInstance(), требующий конструктора no-arg.

Ответ 2

Спящий режим создает экземпляры объектов. Таким образом, он должен иметь возможность создавать их. Если конструктор no-arg не существует, Hibernate не будет знать, как его создать, то есть какой аргумент передать.

Документация hibernate говорит:

4.1.1. Внесите конструктор без аргументов

У всех постоянных классов должен быть конструктор по умолчанию (который может быть непубличным), так что Hibernate может создавать экземпляры с помощью Constructor.newInstance(). Рекомендуется, чтобы у вас был конструктор по умолчанию, имеющий хотя бы видимость пакета для генерации прокси-сервера во время работы в Hibernate.

Ответ 3

Спящий режим - это структура ORM, которая поддерживает стратегию доступа к полям или свойствам. Однако он не поддерживает построение на основе конструктора - возможно, что бы вы хотели? - из-за некоторых проблем, таких как

Что произойдет, если ваш класс содержит много конструкторов

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, <IDENTIFIER>);

Какой конструктор должен вызвать вызов Hibernate для извлечения объекта Person? Вы видите?

И, наконец, используя рефлексию, Hibernate может создать экземпляр класса через его конструктор no-arg. Поэтому, когда вы вызываете

Person person = (Person) session.get(Person.class, <IDENTIFIER>);

Hibernate будет создавать экземпляр объекта Person следующим образом

Person.class.newInstance();

Что в соответствии с документацией API

Класс создается так, как будто новым выражением с пустым списком аргументов

Мораль истории

Person.class.newInstance();

похож на

new Person();

Больше ничего

Ответ 4

Erm, извините всех, но Hibernate не требует, чтобы ваши классы должны иметь конструктор без параметров. Спецификация JPA 2.0 требует этого, и это очень слабо от имени JPA. Другие рамки, такие как JAXB, также требуют этого, что также очень слабое от имени этих фреймворков.

(На самом деле JAXB, предположительно, позволяет предприятиям-основателям, но он настаивает на создании этих фабрик сам по себе, требуя, чтобы у них был какой-то беспредметный конструктор, который в моей книге точно так же хорош, как не позволяет фабрикам, как ламе это!)

Но Hibernate не требует такой вещи.

Hibernate поддерживает механизм перехвата (см. "Interceptor" в документации,), который позволяет вам создавать объекты с любыми параметрами конструктора, которые им нужны.

В основном, что вы делаете, так это то, что при настройке hibernate вы передаете ему объект, реализующий интерфейс org.hibernate.Interceptor, а спящий режим будет вызывать метод instantiate() этого интерфейса всякий раз, когда ему нужен новый экземпляр объекта т.е. ваша реализация этого метода может new ваши объекты так, как вам нравится.

Я сделал это в проекте, и он работает как шарм. В этом проекте я делаю все через JPA, когда это возможно, и я использую только функции Hibernate, такие как перехватчик, когда у меня нет другого выбора.

Hibernate, похоже, несколько не уверен в этом, так как во время запуска он выдает информационное сообщение для каждого из моих классов сущностей, сообщая мне INFO: HHH000182: No default (no-argument) constructor for class и class must be instantiated by Interceptor, но затем я делаю их экземпляр перехватчиком, и это доволен этим.

Чтобы ответить на вопрос "почему" в вопросе о инструментах, отличных от Hibernate, ответ "абсолютно без веской причины", и это подтверждается наличием перехватчика спящего режима. Есть много инструментов, которые могли бы поддерживать какой-то аналогичный механизм для создания объектов клиента, но они этого не делают, поэтому они сами создают объекты, поэтому им нужно требовать конструкторы без параметров. У меня возникает соблазн полагать, что это происходит потому, что создатели этих инструментов считают себя программистами ниндзя-систем, которые создают фреймворки, полные магии, которые будут использоваться неосведомленными программистами приложений, которые (так они думают) никогда бы в своих самых смелых мечтах не имели нужны для таких продвинутых конструкций, как... Factory Шаблон. (Хорошо, у меня есть соблазн думать так. На самом деле я так не думаю. Я шучу.)

Ответ 5

Собственно, вы можете создавать экземпляры классов, у которых нет конструктора 0-args; вы можете получить список конструкторов класса, выбрать один и вызвать его с фиктивными параметрами.

Пока это возможно, и я думаю, что это сработает и не будет проблематичным, вам придется согласиться с тем, что это довольно странно.

Построение объектов так, как это делает Hibernate (я считаю, что он вызывает конструктор 0-arg, а затем он, вероятно, модифицирует поля экземпляра непосредственно через Reflection. Возможно, он знает, как вызывать сеттеры) немного отличается от того, как объект должен быть построенным в Java - вызвать конструктор с соответствующими параметрами, чтобы новый объект был объектом, который вы хотите. Я считаю, что создание экземпляра объекта, а затем его мутация - это нечто вроде "анти-Java" (или, я бы сказал, анти чистой теоретической Java), и, безусловно, если вы это сделаете с помощью прямых манипуляций с полями, это будет инкапсуляция и все, что причудливо инкапсулирует.

Я думаю, что правильным способом сделать это было бы определение в Hibernate-сопоставлении того, как объект должен быть создан из информации в строке базы данных с использованием соответствующего конструктора... но это было бы более сложным, что означало бы и Hibernate было бы еще более сложным, отображение было бы более сложным... и все было бы более "чистым"; и я не думаю, что это будет иметь преимущество перед текущим подходом (кроме чувства хорошего в том, чтобы делать вещи "надлежащим образом" ).

Сказав это и увидев, что подход Hibernate не очень "чист", обязательство иметь конструктор с 0-arg не является строго необходимым, но я могу немного понять это требование, хотя я считаю, что они сделали это чисто "надлежащим образом", когда они отклонялись от "надлежащего пути" (хотя и по разумным причинам) задолго до этого.

Ответ 6

Спящий режим должен создавать экземпляры в результате ваших запросов (через отражение), Hibernate полагается на конструктор объектов no-arg для этого, поэтому вам нужно предоставить конструктор no-arg. То, что не ясно?

Ответ 7

Гораздо проще создать объект с помощью конструктора без параметров через отражение, а затем заполнить его свойства данными посредством отражения, чем пытаться сопоставить данные с произвольными параметрами параметризованного конструктора с изменением конфликтов имен/имен, undefined логический внутренний конструктор, набор параметров, не соответствующих свойствам объекта, и т.д.

Многие ORM и сериализаторы требуют конструкторов без параметров, поскольку параметризированные конструкторы через отражение очень хрупкие, а конструкторы без параметров обеспечивают как стабильность приложения, так и контроль над поведением объекта разработчику.

Ответ 8

Hibernate использует прокси для ленивой загрузки. Если вы не определяете конструктор или не делаете его закрытым, некоторые вещи могут по-прежнему работать - те, которые не зависят от механизма прокси. Например, загрузка объекта (без конструктора) напрямую с помощью API запросов.

Но если вы используете метод session.load(), вы столкнетесь с InstantiationException из генератора прокси-генератора из-за отсутствия конструктора.

Этот парень сообщил об аналогичной ситуации:

http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html

Ответ 9

Ознакомьтесь с этим разделом спецификации языка Java, который объясняет разницу между статическими и нестационарными внутренними классами: http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3

Статический внутренний класс концептуально не отличается от обычного общего класса, объявленного в .java файле.

Так как Hibernate необходимо инстанцировать ProjectPK независимо от экземпляра Project, ProjectPK либо должен быть статическим внутренним классом, либо объявлен в нем собственный .java файл.

ссылка org.hibernate.InstantiationException: конструктор по умолчанию