Конструктор без аргументов является обязательным (такие инструменты, как Hibernate, используют отражение в этом конструкторе для создания экземпляров объектов).
Я получил этот волнистый ответ, но не мог бы кто-нибудь объяснить дальше? Спасибо
Конструктор без аргументов является обязательным (такие инструменты, как Hibernate, используют отражение в этом конструкторе для создания экземпляров объектов).
Я получил этот волнистый ответ, но не мог бы кто-нибудь объяснить дальше? Спасибо
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
как в случае, с которым я только что столкнулся
Ответы:
Hibernate и код в целом, который создает объекты посредством отражения, используются Class<T>.newInstance()
для создания нового экземпляра ваших классов. Этот метод требует, чтобы общедоступный конструктор без аргументов мог создать экземпляр объекта. В большинстве случаев использование конструктора без аргументов не является проблемой.
Существуют хаки, основанные на сериализации, которые могут обойтись без конструктора без аргументов, поскольку сериализация использует магию jvm для создания объектов без вызова конструктора. Но это доступно не для всех виртуальных машин. Например, XStream может создавать экземпляры объектов, у которых нет общедоступного конструктора no-arg, но только в так называемом «расширенном» режиме, который доступен только на определенных виртуальных машинах. (Подробности см. По ссылке.) Разработчики Hibernate, безусловно, решили поддерживать совместимость со всеми виртуальными машинами и поэтому избегают таких уловок и используют официально поддерживаемый метод отражения, Class<T>.newInstance()
требующий конструктора без аргументов.
setAccessible(true)
на нем.
ObjectInputStream
делает что-то вроде sun.reflect.ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToGetInstanceOf, Object.class.getConstructor()).newInstance()
создания экземпляров объектов без конструктора по умолчанию (JDK1.6 для Windows)
It can have package visibility and Hibernate should setAccessible(true)
. Означает ли it
это, что класс создается через отражение? А что Hibernate should setAccessible(true)
значит?
Hibernate создает экземпляры ваших объектов. Таким образом, он должен иметь возможность создавать их экземпляры. Если нет конструктора без аргументов, Hibernate не будет знать, как создать его экземпляр, то есть какой аргумент передать.
В документации по гибернации говорится:
4.1.1. Реализуйте конструктор без аргументов
Все постоянные классы должны иметь конструктор по умолчанию (который может быть непубличным), чтобы Hibernate мог их создать с помощью Constructor.newInstance()
. Рекомендуется иметь конструктор по умолчанию с хотя бы видимостью пакета для создания прокси-сервера во время выполнения в Hibernate.
Эмм, извините всех, но Hibernate не требует, чтобы ваши классы имели конструктор без параметров. Спецификация JPA 2.0 требует этого, и это очень неубедительно для JPA. Другие фреймворки, такие как JAXB, также требуют этого, что также очень неубедительно для этих фреймворков.
(На самом деле, JAXB предположительно разрешает фабрики сущностей, но он настаивает на создании экземпляров этих фабрик самостоятельно, требуя, чтобы у них был конструктор без параметров - угадай , что - в моей книге точно так же хорошо, как и не разрешать фабрики; !)
Но 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 , ответ будет «без всякой уважительной причины», и это подтверждается существованием перехватчика гибернации. Существует множество инструментов, которые могли бы поддерживать аналогичный механизм для создания экземпляров клиентских объектов, но они этого не делают, поэтому они создают объекты сами по себе, поэтому им требуются конструкторы без параметров. У меня есть соблазн поверить, что это происходит потому, что создатели этих инструментов думают о себе как о системных программистах-ниндзя, которые создают фреймворки, полные магии, для использования невежественными программистами, которые (как они думают) никогда бы в своих самых смелых мечтах не имели потребность в таких продвинутых конструкциях, как ... Factory Pattern . (Ладно,так думать. Я не на самом деле так думаю. Я шучу.)
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
которое недавно произошло, потому что javax.persistence.*;
используется и только org.hibernate
при созданииSession, SessionFactory, and Configuration
Гибернация - это структура 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>);
Какой конструктор должен вызывать Hibernate для получения объекта Person? Видишь ?
2º И, наконец, используя отражение, Hibernate может создать экземпляр класса через конструктор без аргументов. Итак, когда вы звоните
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Hibernate создаст экземпляр вашего объекта Person следующим образом
Person.class.newInstance();
Что согласно документации API
Экземпляр класса создается как новое выражение с пустым списком аргументов.
Мораль истории
Person.class.newInstance();
похоже на
new Person();
Ничего больше
name
и age
? Если нет, то позже он использует другой конструктор?
Фактически, вы можете создавать экземпляры классов, у которых нет конструктора с 0 аргументами; вы можете получить список конструкторов класса, выбрать один и вызвать его с фиктивными параметрами.
Хотя это возможно, и я думаю, это сработает и не вызовет проблем, согласитесь, что это довольно странно.
Создание объектов так, как это делает Hibernate (я считаю, что он вызывает конструктор 0-arg, а затем, вероятно, изменяет поля экземпляра напрямую через Reflection. Возможно, он знает, как вызывать сеттеры) немного противоречит тому, как объект должен быть построен в Java - вызовите конструктор с соответствующими параметрами, чтобы новый объект был тем объектом, который вам нужен. Я считаю, что создание экземпляра объекта с последующим его изменением - это своего рода «анти-Java» (или, я бы сказал, анти-чисто теоретическая Java) - и определенно, если вы сделаете это с помощью прямых манипуляций с полями, это будет инкапсуляция и все эти причудливые инкапсуляционные штуки. .
Я думаю, что правильный способ сделать это - определить в отображении Hibernate, как объект должен быть создан из информации в строке базы данных с использованием подходящего конструктора ... но это было бы более сложно, то есть оба Hibernate были бы даже чем сложнее, тем сложнее отображение ... и все будет более "чистым"; и я не думаю, что это будет иметь преимущество перед текущим подходом (кроме того, что вы чувствуете себя хорошо, когда делаете что-то «должным образом»).
Сказав это и видя, что подход Hibernate не очень "чистый", обязательство иметь конструктор с 0 аргументами не является строго необходимым, но я могу частично понять требование, хотя я считаю, что они сделали это чисто "надлежащим образом". "основания, когда они отклонились от" правильного пути "(хотя и по разумным причинам) задолго до этого.
Hibernate должен создавать экземпляры в результате ваших запросов (посредством отражения), Hibernate полагается для этого на конструктор сущностей без аргументов, поэтому вам необходимо предоставить конструктор без аргументов. То, что не ясно?
private
некорректен конструктор? Я вижу java.lang.InstantiationException
даже с private
конструктором для моей сущности JPA. ссылка .
Намного проще создать объект с конструктором без параметров посредством отражения, а затем заполнить его свойства данными посредством отражения, чем пытаться сопоставить данные с произвольными параметрами параметризованного конструктора с изменением имен / конфликтов имен, неопределенной логикой внутри конструктора, наборы параметров, не соответствующие свойствам объекта и т. д.
Для многих ORM и сериализаторов требуются конструкторы без параметров, потому что параметризованные конструкторы посредством отражения очень хрупкие, а конструкторы без параметров обеспечивают как стабильность для приложения, так и контроль над поведением объекта для разработчика.
Hibernate использует прокси для отложенной загрузки. Если вы не определяете конструктор или не делаете его закрытым, некоторые вещи могут по-прежнему работать - те, которые не зависят от механизма прокси. Например, загрузка объекта (без конструктора) напрямую с помощью API запросов.
Но, если вы используете метод session.load (), вы столкнетесь с InstantiationException из прокси-генератора 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
Статический внутренний класс концептуально ничем не отличается от обычного общего класса, объявленного в файле .java.
Поскольку Hibernate должен создавать экземпляр ProjectPK независимо от экземпляра Project, ProjectPK должен быть либо статическим внутренним классом, либо объявлен в собственном файле .java.
ссылка org.hibernate.InstantiationException: нет конструктора по умолчанию
The no-argument constructor is a requirement
которое неверно , и все ответы, которые объясняют, почему это так, без сомнения, так ли это на самом деле (включая принятый ответ, который даже получил награду) , неверны . См. Ответ: stackoverflow.com/a/29433238/773113