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


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

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

9 73

9 ответов:

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

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

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

на hibernate documentation говорит:

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

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

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

1 что происходит, если ваш класс содержит много конструкторов

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

какой конструктор должен спящий вызов для получения объекта Person ? Ты видишь ?

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

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

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

Person.class.newInstance();

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

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

мораль

Person.class.newInstance();

похож на

new Person();

ничего

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

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

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

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

в основном, то, что вы делаете это при настройке 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. Там есть много инструментов, которые могли бы поддерживать какой-то подобный механизм для создания экземпляра объекта клиента, но они этого не делают, поэтому они создают объекты сами по себе, поэтому им нужны конструкторы без параметров. Я склонен полагать, что это происходит потому, что создатели этих инструментов считают себя программистами систем ниндзя, которые создают фреймворки, полные магии, которые будут использоваться невежественными программистами приложений, которые (так они думают) никогда не будут в своих самых смелых мечтах есть потребность в таких дополнительных конструкций, как... Шаблон Фабрики. (Хорошо, я соблазн думать так. Я не на самом деле думаю так. Я шучу.)

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

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

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

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

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

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

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

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

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

но, если вы используете сессии.load method () вы столкнетесь с InstantiationException от proxy generator lib из-за отсутствия конструктора.

этот парень сообщил о похожем ситуация:

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

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

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

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

ссылка org.зимовать.InstantiationException: нет конструктора по умолчанию