Dlaczego Hibernate nie wymaga konstruktora argumentów?

Konstruktor bez argumentu jest Wymaganie (narzędzia takie jak Hibernate używają refleksja nad tym konstruktorem do instantiate objects).

[1]}dostałem tę ręczną odpowiedź, ale czy ktoś mógłby wyjaśnić dalej? Dzięki
Author: Mike Nakis, 2010-05-29

9 answers

Hibernate, oraz ogólnie kod, który tworzy obiekty za pomocą Class<T>.newInstance() Aby utworzyć nową instancję klas. Ta metoda wymaga publicznego konstruktora no-arg, aby móc utworzyć instancję obiektu. W większości przypadków użycie konstruktora no-arg nie stanowi problemu.

Istnieją hacki oparte na serializacji, które mogą obejść się bez konstruktora no-arg, ponieważ serializacja używa jvm magic do tworzenia obiektów bez wywoływania konstruktora. Ale to nie jest dostępne we wszystkich maszynach wirtualnych. Na przykład, XStream może tworzyć instancje obiektów, które nie mają publicznego konstruktora no-arg, ale tylko poprzez uruchomienie w tak zwanym trybie "rozszerzonym", który jest dostępny tylko na niektórych maszynach wirtualnych. (Szczegóły w linku.) Projektanci Hibernate z pewnością zdecydowali się zachować kompatybilność ze wszystkimi maszynami wirtualnymi i dlatego unikają takich sztuczek i używają oficjalnie wspieranej metody reflection Class<T>.newInstance() wymagającej konstruktora no-arg.

 105
Author: mdma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-14 20:25:24

Hibernate tworzy instancje obiektów. Więc musi być w stanie je utworzyć. Jeśli nie ma konstruktora no-arg, Hibernate nie będzie wiedział Jak utworzyć instancję, tzn. jaki argument przekazać.

Dokumentacja Hibernate mówi:

4.1.1. Implementacja konstruktora bez argumentu

Wszystkie trwałe klasy muszą mieć domyślny konstruktor (który może być Niepubliczny), aby Hibernate mógł utworzyć ich instancję za pomocą Constructor.newInstance(). Zaleca się masz domyślny konstruktor z widocznością co najmniej pakietu dla generowania proxy w trybie Runtime w Hibernate.

 42
Author: Bozho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-07 17:15:06

Hibernate jest frameworkiem ORM, który obsługuje strategię dostępu do pól lub właściwości. Jednak nie obsługuje mapowania opartego na konstruktorach - może co byś chciał ? - z powodu niektórych problemów, takich jak

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 widzisz, masz do czynienia z problemem niespójności, ponieważ Hibernate nie może przypuszczać, który konstruktor powinien zostać wywołany. Załóżmy na przykład, że musisz odzyskać przechowywaną osobę obiekt

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

Który konstruktor powinien wywołać Hibernate, aby odzyskać obiekt Person ? Widzisz ?

i wreszcie, używając reflection, Hibernate może utworzyć instancję klasy poprzez swój konstruktor no-arg. Więc kiedy zadzwonisz

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

Hibernate utworzy instancję obiektu Person w następujący sposób

Person.class.newInstance();

Które zgodnie z dokumentacją API

Klasa jest tworzona jako instancja przez nowe wyrażenie z argumentem empty lista

Morał z historii

Person.class.newInstance();

Jest podobny do

new Person();

Nothing else

 32
Author: Arthur Ronald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-22 05:31:08

ERM, sorry wszystkim, ale Hibernate robi nie Wymagaj, aby Twoje klasy miały konstruktor bez parametru. Specyfikacja JPA 2.0 tego wymaga, a to jest bardzo słabe w imieniu JPA. Inne frameworki, takie jak JAXB również tego wymagają, co jest również bardzo słabe w imieniu tych frameworków.

(właściwie, JAXB rzekomo pozwala fabrykom Bytów, ale nalega na utworzenie tych fabryk samodzielnie, wymagając od nich ... -- konstruktor bez parametru , który w mojej książce jest dokładnie tak samo dobry, jak nie pozwalanie fabrykom; jakie to lamerskie!)

Ale Hibernate nie wymaga czegoś takiego.

Hibernate obsługuje mechanizm przechwytywania (zobacz "Interceptor" w dokumentacji ,), który pozwala tworzyć instancje obiektów z dowolnymi parametrami konstruktora, których potrzebują.

Zasadniczo, to co robisz to to, że po skonfigurowaniu hibernate przekazujesz mu obiekt implementujący org.hibernate.Interceptor interfejs i hibernate będą wywoływać metodę instantiate() tego interfejsu, kiedy tylko będzie potrzebna nowa instancja Twojego obiektu, więc twoja implementacja tej metody może new Twoje obiekty w dowolny sposób.

Zrobiłem to w projekcie i działa jak urok. W tym projekcie robię rzeczy za pośrednictwem JPA, kiedy tylko jest to możliwe, i używam funkcji Hibernate, takich jak interceptor, gdy nie mam innej opcji.

Hibernate wydaje się być nieco niepewny, ponieważ podczas uruchamiania wydaje komunikat informacyjny dla każdej z moich klas encji, mówiący mi INFO: HHH000182: No default (no-argument) constructor for class i class must be instantiated by Interceptor, ale później robię ich instancję przez interceptor i jest z tego zadowolony.

Aby odpowiedzieć na pytanie" dlaczego " dla narzędzi innych niż Hibernate, odpowiedź brzmi "absolutnie bez powodu", a jest to udowodnione przez istnienie Hibernate interceptor. Istnieje wiele narzędzi, które mogły obsługiwać podobny mechanizm dla obiektu klienta instancjacji, ale nie robią tego, więc same tworzą obiekty, więc muszą wymagać konstruktorów bez parametru. Kusi mnie, aby wierzyć, że tak się dzieje, ponieważ twórcy tych narzędzi uważają się za programistów systemów ninja, którzy tworzą pełne magii frameworki do wykorzystania przez ignorantów programistów aplikacji, którzy (tak myślą) nigdy w swoich najśmielszych marzeniach nie mają potrzeby tak zaawansowanych konstrukcji jak... Wzór Fabryczny . (OK, jestem kuszony , aby tak myśleć. Nie wydaje mi się. Żartuję.)

 32
Author: Mike Nakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-05 22:48:28

W rzeczywistości, możesz 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 to zadziała i nie będzie problematyczne, musisz się zgodzić, że jest to dość dziwne.

Konstruowanie obiektów tak, jak robi to Hibernate (wierzę, że wywołuje konstruktor 0-arg, a następnie prawdopodobnie modyfikuje pola instancji bezpośrednio poprzez odbicie. Być może wie jak wywoływać settery) jest trochę sprzeczne z tym, jak obiekt ma być zbudowany w Javie - wywołaj konstruktor z odpowiednimi parametrami, aby nowy obiekt był obiektem, który chcesz. Uważam, że tworzenie instancji obiektu, a następnie mutowanie go jest w pewnym sensie "anty-Java" (lub powiedziałbym, anty czysta teoretyczna Java)- i zdecydowanie, jeśli zrobisz to poprzez bezpośrednią manipulację polową, to będzie to enkapsulacja i cała ta fantazyjna enkapsulacja.

Myślę, że właściwy sposób na w tym celu należy zdefiniować w mapowaniu Hibernate jak obiekt powinien być utworzony z informacji w wierszu bazy danych przy użyciu odpowiedniego konstruktora... ale byłoby to bardziej złożone - co oznacza, że oba Hibernaty byłyby jeszcze bardziej złożone, mapowanie byłoby bardziej złożone... a wszystko po to, aby być bardziej "czystym"; I nie sądzę, że miałoby to przewagę nad obecnym podejściem (poza dobrym samopoczuciem w robieniu rzeczy "we właściwy sposób").

[[0]] Powiedziawszy to i widząc, że Hibernacja podejście nie jest bardzo "czyste", obowiązek posiadania konstruktora 0-arg nie jest bezwzględnie konieczny, ale mogę zrozumieć nieco wymóg, chociaż wierzę, że zrobili to na czysto" właściwą drogę "podstawy, kiedy zbłądzili z" właściwą drogę " (choć z rozsądnych powodów) dużo wcześniej.
 6
Author: alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-08 21:46:45

Hibernate musi tworzyć instancje w wyniku Twoich zapytań (poprzez odbicie), Hibernate opiera się na konstruktorze no-arg encji, więc musisz DOSTARCZYĆ konstruktor no-arg. Co nie jest jasne?

 4
Author: Pascal Thivent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-29 16:50:08

O wiele łatwiej jest stworzyć obiekt z parametryzowanym konstruktorem poprzez odbicie, a następnie wypełnić jego właściwości danymi poprzez odbicie, niż próbować dopasować dane do dowolnych parametrów parametryzowanego konstruktora, ze zmieniającymi się nazwami/konfliktami nazw, niezdefiniowaną logiką wewnątrz konstruktora, zestawami parametrów Nie pasującymi do Właściwości obiektu itp.

Wiele ORM i serializerów wymaga konstruktorów bez parametru, ponieważ konstruktory paramteryzowane przez odbicia są bardzo delikatne, a konstruktory bez parametru zapewniają zarówno stabilność aplikacji, jak i kontrolę nad zachowaniem obiektu deweloperowi.

 2
Author: Kaerber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-10 08:48:26

Hibernate używa proxy do leniwego ładowania. Jeśli nie zdefiniujesz konstruktora lub uczynisz go prywatnym, kilka rzeczy może nadal działać - te, które nie zależą od mechanizmu proxy. Na przykład, ładowanie obiektu (bez konstruktora) bezpośrednio przy użyciu query API.

Ale, jeśli używasz sesji.load method() napotkasz InstantiationException z lib generatora proxy ze względu na niedostępność konstruktora.

Ten facet zgłosił podobny sytuacja:

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

 1
Author: haps10,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-28 11:23:26

Sprawdź 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 nie różni się koncepcyjnie od zwykłej klasy ogólnej zadeklarowanej w a .plik java.

Ponieważ Hibernate musi utworzyć instancję ProjectPK niezależnie od instancji projektu, ProjectPK musi być albo statyczną klasą wewnętrzną, albo zadeklarowaną w jej własne .plik java.

Reference org.hibernacja.InstantiationException: No default constructor

 0
Author: Amitābha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-13 02:29:08