Konstruktor bez argumentów jest wymagany (narzędzia takie jak Hibernate używają refleksji na tym konstruktorze do tworzenia instancji obiektów).
Otrzymałem tę falującą odpowiedź, ale czy ktoś mógłby wyjaśnić dalej? Dzięki
Konstruktor bez argumentów jest wymagany (narzędzia takie jak Hibernate używają refleksji na tym konstruktorze do tworzenia instancji obiektów).
Otrzymałem tę falującą odpowiedź, ale czy ktoś mógłby wyjaśnić dalej? Dzięki
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
jak w przypadku, w którym właśnie się zetknąłem
Odpowiedzi:
Hibernate i ogólnie kod, który tworzy obiekty za pomocą odbicia, Class<T>.newInstance()
aby utworzyć nowe wystąpienie klas. Ta metoda wymaga publicznego konstruktora no-arg, aby móc utworzyć wystąpienie obiektu. W większości przypadków użycie konstruktora bez argumentów nie stanowi problemu.
Istnieją hacki oparte na serializacji, które mogą obejść brak konstruktora bez arg, ponieważ serializacja używa magii jvm do tworzenia obiektów bez wywoływania konstruktora. Ale nie jest to dostępne we wszystkich maszynach wirtualnych. Na przykład XStream może tworzyć instancje obiektów, które nie mają publicznego konstruktora bez argonu, ale tylko działając w tak zwanym trybie „rozszerzonym”, który jest dostępny tylko na niektórych maszynach wirtualnych. (Zobacz łącze, aby uzyskać szczegółowe informacje). Projektanci Hibernate z pewnością zdecydowali się zachować zgodność ze wszystkimi maszynami wirtualnymi, unikając w ten sposób takich sztuczek i używają oficjalnie obsługiwanej metody odbicia Class<T>.newInstance()
wymagającej konstruktora bez argonu.
setAccessible(true)
na nim być.
ObjectInputStream
robi coś podobnego sun.reflect.ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToGetInstanceOf, Object.class.getConstructor()).newInstance()
do tworzenia instancji obiektów bez domyślnego konstruktora (JDK1.6 dla Windows)
It can have package visibility and Hibernate should setAccessible(true)
. Czy it
oznacza, że klasa jest tworzona przez odbicie? A co to Hibernate should setAccessible(true)
znaczy?
Hibernate tworzy instancje obiektów. Dlatego musi mieć możliwość ich utworzenia. Jeśli nie ma konstruktora bez argumentów, Hibernate nie będzie wiedział, jak go utworzyć, tj. Jaki argument przekazać.
Dokumentacja dotycząca hibernacji mówi:
4.1.1. Zaimplementuj konstruktora bez argumentów
Wszystkie trwałe klasy muszą mieć domyślny konstruktor (który może być niepubliczny), aby Hibernate mógł utworzyć ich instancję przy użyciu Constructor.newInstance()
. Zaleca się posiadanie domyślnego konstruktora z widocznością przynajmniej pakietu do generowania proxy w czasie wykonywania w Hibernate.
Przepraszam wszystkich, ale Hibernate nie wymaga, aby twoje klasy miały konstruktora bez parametrów. Specyfikacji JPA 2.0 wymaga, a to jest bardzo kulawy w imieniu WZP. Inne frameworki, takie jak JAXB, również tego wymagają, co jest również bardzo kiepskie w imieniu tych frameworków.
(Właściwie JAXB przypuszczalnie zezwala na fabryki jednostek, ale nalega na samodzielne tworzenie instancji tych fabryk, wymagając od nich - zgadnijcie - konstruktora bez parametrów , co w mojej książce jest dokładnie tak samo dobre, jak nie zezwalanie na fabryki; jakie to kiepskie !)
Ale Hibernate nie wymaga tego.
Hibernate obsługuje mechanizm przechwytywania (patrz „Interceptor” w dokumentacji ), który umożliwia tworzenie instancji obiektów z dowolnymi parametrami konstruktora, których potrzebują.
Zasadniczo to, co robisz, to to, że po skonfigurowaniu hibernacji przekazujesz mu obiekt implementujący org.hibernate.Interceptor
interfejs, a hibernacja będzie wtedy wywoływać instantiate()
metodę tego interfejsu, gdy będzie potrzebować nowej instancji twojego obiektu, więc twoja implementacja tej metody może new
swoje przedmioty w dowolny sposób.
Zrobiłem to w projekcie i działa jak urok. W tym projekcie robię rzeczy przez JPA, kiedy tylko jest to możliwe, i używam funkcji Hibernacji, takich jak przechwytywacz, tylko wtedy, gdy nie mam innej opcji.
Wydaje się, że Hibernate jest nieco niepewny, ponieważ podczas uruchamiania wyświetla komunikat informacyjny dla każdej z moich klas encji, informując mnie INFO: HHH000182: No default (no-argument) constructor for class
iclass must be instantiated by Interceptor
, ale później mam instancję je kolektora i jest zadowolony z tego.
Aby odpowiedzieć na pytanie „dlaczego”, część pytania o narzędzia faktycznie tak myślę. Żartuję.) innych niż Hibernate , odpowiedź brzmi „bez absolutnie żadnego powodu”, a potwierdza to istnienie przechwytywacza hibernacji. Istnieje wiele narzędzi, które mogłyby obsługiwać podobny mechanizm tworzenia instancji obiektu klienta, ale tak nie jest, więc tworzą one obiekty samodzielnie, więc muszą wymagać konstruktorów bez parametrów. Kusi mnie, by uwierzyć, że dzieje się tak, ponieważ twórcy tych narzędzi myślą o sobie jako o programistach systemów ninja, którzy tworzą frameworki pełne magii, do wykorzystania przez nieświadomych programistów aplikacji, którzy (tak im się wydaje) nigdy w swoich najśmielszych marzeniach nigdy nie mieliby potrzeba tak zaawansowanych konstrukcji, jak ... Wzorzec fabryczny, . (Okej, jestemtak myśleć. Nie
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
które ostatnio wystąpiło, ponieważ javax.persistence.*;
jest używane i tylko org.hibernate
podczas tworzeniaSession, SessionFactory, and Configuration
Hibernacja to struktura ORM, która obsługuje strategię dostępu do pól lub właściwości. Jednak nie obsługuje mapowania opartego na konstruktorze - może co byś chciał? - z powodu pewnych problemów, takich jak
1º Co się stanie, jeśli Twoja klasa zawiera dużo konstruktorów
public class Person {
private String name;
private Integer age;
public Person(String name, Integer age) { ... }
public Person(String name) { ... }
public Person(Integer age) { ... }
}
Jak widać, mamy do czynienia z problemem niespójności, ponieważ Hibernate nie może przewidzieć, który konstruktor powinien zostać wywołany. Na przykład załóżmy, że musisz pobrać przechowywany obiekt Person
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Który konstruktor powinien wywołać Hibernate, aby pobrać obiekt Person? Czy widzisz ?
2º I wreszcie, używając refleksji, Hibernate może utworzyć instancję klasy poprzez jej konstruktor bezargumentowy. Więc kiedy dzwonisz
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Hibernate utworzy wystąpienie obiektu Person w następujący sposób
Person.class.newInstance();
Które zgodnie z dokumentacją API
Instancja klasy jest tworzona tak, jakby za pomocą nowego wyrażenia z pustą listą argumentów
Morał historii
Person.class.newInstance();
jest podobne do
new Person();
Nic więcej
name
i age
? Jeśli nie, to później użyje innego konstruktora?
Właściwie można tworzyć instancje klas, które nie mają konstruktora 0-args; możesz uzyskać listę konstruktorów klasy, wybrać jeden i wywołać go z fałszywymi parametrami.
Chociaż jest to możliwe i myślę, że zadziałałoby i nie byłoby problematyczne, musisz się zgodzić, że jest to dość dziwne.
Konstruowanie obiektów w sposób, w jaki robi to Hibernate (wydaje mi się, że wywołuje konstruktor 0-arg, a następnie prawdopodobnie modyfikuje pola instancji bezpośrednio przez Reflection. Być może wie, jak wywoływać metody ustawiające) jest trochę sprzeczne z tym, jak obiekt ma być zbudowany w Java - wywołaj konstruktora z odpowiednimi parametrami, aby nowy obiekt był tym, którego chcesz. Uważam, że utworzenie instancji obiektu, a następnie jego mutacja jest w pewnym sensie „anty-Java” (lub powiedziałbym, anty-czysto teoretyczna Java) - i zdecydowanie, jeśli zrobisz to przez bezpośrednią manipulację polem, nastąpi hermetyzacja i wszystkie te fantazyjne elementy enkapsulacji .
Myślę, że właściwym sposobem na zrobienie tego byłoby zdefiniowanie w mapowaniu Hibernate, w jaki sposób obiekt powinien być utworzony na podstawie informacji w wierszu bazy danych przy użyciu odpowiedniego konstruktora ... ale byłoby to bardziej złożone - co oznacza, że oba Hibernate byłyby równe bardziej złożone, mapowanie byłoby bardziej złożone ... a wszystko po to, by być bardziej „czystym”; i nie sądzę, żeby to miało przewagę nad obecnym podejściem (poza poczuciem zadowolenia z robienia rzeczy „we właściwy sposób”).
Powiedziawszy to i widząc, że podejście Hibernate nie jest zbyt „czyste”, obowiązek posiadania konstruktora 0-argowego nie jest bezwzględnie konieczny, ale mogę nieco zrozumieć ten wymóg, chociaż uważam, że zrobili to w czysto „właściwy sposób” „powodów, kiedy zboczyli z„ właściwej drogi ”(aczkolwiek z uzasadnionych powodów) dużo wcześniej.
Hibernate musi tworzyć instancje w wyniku twoich zapytań (przez odbicie), Hibernate opiera się na konstruktorze encji bez argonu, więc musisz zapewnić konstruktor bez argonu. Co nie jest jasne?
private
konstruktor jest nieprawidłowy? Widzę java.lang.InstantiationException
nawet z private
konstruktorem dla mojej jednostki JPA. odniesienie .
Znacznie łatwiej jest stworzyć obiekt z konstruktorem bez parametrów poprzez odbicie, a następnie wypełnić jego właściwości danymi poprzez odbicie, niż próbować dopasować dane do dowolnych parametrów konstruktora sparametryzowanego, ze zmieniającymi się nazwami / konfliktami nazw, niezdefiniowaną logiką wewnątrz konstruktora, zestawy parametrów nie pasują do właściwości obiektu i tak dalej.
Wiele ORM i serializatorów wymaga konstruktorów bez parametrów, ponieważ konstruktory sparametryzowane przez odbicie są bardzo delikatne, a konstruktory bez parametrów zapewniają zarówno stabilność aplikacji, jak i kontrolę nad zachowaniem obiektu dla dewelopera.
Hibernate wykorzystuje serwery proxy do leniwego ładowania. Jeśli nie zdefiniujesz konstruktora lub nie ustawisz go jako prywatnego, kilka rzeczy może nadal działać - te, które nie są zależne od mechanizmu proxy. Na przykład ładowanie obiektu (bez konstruktora) bezpośrednio przy użyciu interfejsu API zapytań.
Ale jeśli użyjesz metody session.load (), napotkasz wyjątek InstantiationException z biblioteki generatora proxy z powodu niedostępności konstruktora.
Ten facet zgłosił podobną sytuację:
http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html
Zapoznaj się z tą sekcją specyfikacji języka Java, która wyjaśnia różnicę między statycznymi i niestatycznymi klasami wewnętrznymi: http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3
Statyczna klasa wewnętrzna koncepcyjnie nie różni się od zwykłej klasy ogólnej zadeklarowanej w pliku .java.
Ponieważ Hibernate musi utworzyć wystąpienie ProjectPK niezależnie od instancji Project, ProjectPK musi być statyczną klasą wewnętrzną lub zadeklarowaną we własnym pliku .java.
odwołanie org.hibernate.InstantiationException: Brak domyślnego konstruktora
The no-argument constructor is a requirement
jest błędne , i wszystkie odpowiedzi, które prowadzą do wyjaśnienia, dlaczego tak jest, bez kwestionowania, czy tak jest w rzeczywistości (w tym zaakceptowana odpowiedź, która nawet otrzymała nagrodę) są błędne . Zobacz tę odpowiedź: stackoverflow.com/a/29433238/773113