Почему Hibernate не требует конструктора аргументов? - PullRequest
87 голосов
/ 29 мая 2010

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

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

Ответы [ 9 ]

122 голосов
/ 04 июня 2010

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

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

44 голосов
/ 29 мая 2010

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

Документация в спящем режиме гласит:

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

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

35 голосов
/ 03 апреля 2015

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

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

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

Hibernate поддерживает механизм перехвата (см. «Перехватчик» в документации ,), который позволяет создавать экземпляры ваших объектов с любыми необходимыми им параметрами конструктора.

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

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

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

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

33 голосов
/ 09 июня 2010

Hibernate - это среда 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 может создать экземпляр класса через конструктор без аргументов. Поэтому, когда вы звоните

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

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

Person.class.newInstance();

Который согласно документации API

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

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

Person.class.newInstance();

похоже на

new Person();

Ничего другого

6 голосов
/ 09 июня 2010

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

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

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

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

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

5 голосов
/ 29 мая 2010

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

2 голосов
/ 10 июня 2010

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

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

1 голос
/ 28 октября 2011

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

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

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

http://kristian -domagala.blogspot.com / 2008/10 / прокси-конкретизации-проблемно-from.html

0 голосов
/ 13 октября 2014

Ознакомьтесь с этим разделом спецификации языка 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: Нет конструктора по умолчанию

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...