ตัวสร้างไม่มีอาร์กิวเมนต์เป็นข้อกำหนด (เครื่องมือเช่นไฮเบอร์เนตใช้การสะท้อนบนตัวสร้างนี้เพื่อสร้างอินสแตนซ์อ็อบเจ็กต์)
ฉันได้รับคำตอบที่เป็นคลื่น แต่ใครช่วยอธิบายเพิ่มเติมได้ไหม ขอบคุณ
ตัวสร้างไม่มีอาร์กิวเมนต์เป็นข้อกำหนด (เครื่องมือเช่นไฮเบอร์เนตใช้การสะท้อนบนตัวสร้างนี้เพื่อสร้างอินสแตนซ์อ็อบเจ็กต์)
ฉันได้รับคำตอบที่เป็นคลื่น แต่ใครช่วยอธิบายเพิ่มเติมได้ไหม ขอบคุณ
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
เหมือนในกรณีที่ฉันเพิ่งพบ
คำตอบ:
ไฮเบอร์เนตและรหัสโดยทั่วไปที่สร้างวัตถุผ่านการสะท้อนใช้Class<T>.newInstance()
เพื่อสร้างอินสแตนซ์ใหม่ของคลาสของคุณ วิธีนี้ต้องการตัวสร้าง no-arg สาธารณะเพื่อให้สามารถสร้างอินสแตนซ์วัตถุได้ สำหรับกรณีการใช้งานส่วนใหญ่การจัดหาคอนสตรัคเตอร์แบบไม่มีอาร์กิวเมนต์ไม่ใช่ปัญหา
มีแฮ็กที่ใช้การทำให้เป็นอนุกรมที่สามารถแก้ไขได้โดยไม่ต้องมีตัวสร้างที่ไม่มีอาร์กิวเมนต์เนื่องจากการทำให้เป็นอนุกรมใช้เวทมนตร์ jvm เพื่อสร้างวัตถุโดยไม่ต้องเรียกใช้ตัวสร้าง แต่ไม่สามารถใช้ได้กับ VM ทั้งหมด ตัวอย่างเช่นXStreamสามารถสร้างอินสแตนซ์ของออบเจ็กต์ที่ไม่มีตัวสร้าง no-arg แบบสาธารณะ แต่โดยการเรียกใช้ในโหมดที่เรียกว่า "ขั้นสูง" ซึ่งพร้อมใช้งานบน VM บางเครื่องเท่านั้น (ดูลิงค์สำหรับรายละเอียด) นักออกแบบของ Hibernate เลือกที่จะรักษาความเข้ากันได้กับ VM ทั้งหมดดังนั้นจึงหลีกเลี่ยงกลเม็ดดังกล่าวและใช้วิธีการสะท้อนที่ได้รับการสนับสนุนอย่างเป็นทางการซึ่ง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
ได้หมายความว่าเป็นชั้น instantiated ผ่านการสะท้อน? และHibernate should setAccessible(true)
หมายความว่าอย่างไร?
ไฮเบอร์เนตสร้างอินสแตนซ์วัตถุของคุณ ดังนั้นจึงจำเป็นต้องสามารถสร้างอินสแตนซ์ได้ หากไม่มีตัวสร้างที่ไม่มีอาร์กิวเมนต์ไฮเบอร์เนตจะไม่ทราบวิธีการสร้างอินสแตนซ์นั่นคืออาร์กิวเมนต์ที่จะส่งผ่าน
เอกสาร Hibernateพูดว่า:
4.1.1. ใช้ตัวสร้างที่ไม่มีอาร์กิวเมนต์
ทุกชั้นเรียนถาวรจะต้องมีการสร้างเริ่มต้น (ซึ่งอาจจะไม่เป็นสาธารณะ) เพื่อให้ Hibernate Constructor.newInstance()
สามารถยกตัวอย่างได้โดยใช้ ขอแนะนำให้คุณมีตัวสร้างเริ่มต้นที่มีการมองเห็นแพ็กเกจเป็นอย่างน้อยสำหรับการสร้างพร็อกซีรันไทม์ในไฮเบอร์เนต
เอิ่มขอโทษทุกคน แต่ไฮเบอร์เนตไม่ต้องการให้คลาสของคุณต้องมีคอนสตรัคเตอร์แบบไม่มีพารามิเตอร์ ข้อกำหนดของJPA 2.0ต้องการและนี่เป็นเรื่องง่อยมากในนามของ JPA เฟรมเวิร์กอื่น ๆ เช่น JAXB ก็ต้องการเช่นกันซึ่งก็ถือว่าอ่อนแอมากในนามของเฟรมเวิร์กเหล่านั้น
(อันที่จริง JAXB ควรจะอนุญาตโรงงานเอนทิตี แต่มันยืนยันที่จะสร้างอินสแตนซ์โรงงานเหล่านี้ด้วยตัวเองโดยกำหนดให้พวกเขามี - เดาว่าอะไร - ตัวสร้างแบบไร้พารามิเตอร์ซึ่งในหนังสือของฉันดีพอ ๆ กับการไม่อนุญาตให้โรงงาน; ง่อยแค่ไหน !)
แต่ไฮเบอร์เนตไม่ต้องการสิ่งนั้น
Hibernate สนับสนุนกลไกการสกัดกั้น (ดู"Interceptor" ในเอกสารประกอบ ) ซึ่งช่วยให้คุณสามารถสร้างอินสแตนซ์วัตถุของคุณด้วยพารามิเตอร์ตัวสร้างที่ต้องการ
โดยพื้นฐานแล้วสิ่งที่คุณทำคือเมื่อคุณตั้งค่าไฮเบอร์เนตคุณจะส่งผ่านวัตถุที่ใช้org.hibernate.Interceptor
อินเทอร์เฟซและไฮเบอร์เนตจะเรียกใช้instantiate()
เมธอดของอินเทอร์เฟซนั้นเมื่อใดก็ตามที่ต้องการอินสแตนซ์ใหม่ของวัตถุของคุณดังนั้นการใช้วิธีการดังกล่าวของคุณสามารถทำได้new
วัตถุของคุณในแบบที่คุณต้องการ
ฉันได้ทำในโปรเจ็กต์และมันได้ผลเหมือนมีเสน่ห์ ในโปรเจ็กต์นี้ฉันทำสิ่งต่างๆผ่าน JPA ทุกครั้งที่ทำได้และฉันจะใช้ฟีเจอร์ไฮเบอร์เนตเช่นตัวสกัดกั้นเมื่อฉันไม่มีตัวเลือกอื่น
ดูเหมือนว่าไฮเบอร์เนตจะค่อนข้างไม่ปลอดภัยเนื่องจากในระหว่างการเริ่มต้นระบบจะออกข้อความข้อมูลสำหรับแต่ละคลาสเอนทิตีของฉันบอกฉันINFO: HHH000182: No default (no-argument) constructor for class
และclass must be instantiated by Interceptor
หลังจากนั้นฉันจะสร้างอินสแตนซ์โดย interceptor และก็พอใจกับสิ่งนั้น
หากต้องการตอบคำถามส่วนหนึ่งของ "ทำไม" สำหรับเครื่องมืออื่นที่ไม่ใช่ไฮเบอร์เนตคำตอบคือ "ด้วยเหตุผลที่ไม่ดีอย่างแน่นอน" และสิ่งนี้ได้รับการพิสูจน์โดยการมีอยู่ของตัวสกัดกั้นที่จำศีล มีเครื่องมือมากมายที่สามารถรองรับกลไกบางอย่างที่คล้ายกันสำหรับการสร้างอินสแตนซ์อ็อบเจ็กต์ไคลเอ็นต์ แต่ไม่ทำดังนั้นพวกเขาจึงสร้างอ็อบเจ็กต์ด้วยตัวเองดังนั้นจึงต้องใช้คอนสตรัคเตอร์แบบไม่มีพารามิเตอร์ ฉันอยากจะเชื่อว่าสิ่งนี้เกิดขึ้นเพราะผู้สร้างเครื่องมือเหล่านี้คิดว่าตัวเองเป็นโปรแกรมเมอร์ระบบนินจาที่สร้างเฟรมเวิร์กที่เต็มไปด้วยเวทมนตร์เพื่อใช้โดยโปรแกรมเมอร์แอปพลิเคชันที่ไม่รู้ซึ่ง (พวกเขาคิดว่า) จะไม่เคยมี ความจำเป็นในการสร้างขั้นสูงเช่น ... แบบโรงงาน (ตกลง,คิดอย่างนั้น ฉันไม่จริงคิดอย่างนั้น ฉันล้อเล่น.)
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) session.get(Person.class, <IDENTIFIER>);
ตัวสร้างใดที่ไฮเบอร์เนตควรเรียกเพื่อดึงวัตถุบุคคล คุณมองเห็นไหม ?
2ºและในที่สุดโดยใช้การสะท้อนไฮเบอร์เนตสามารถสร้างอินสแตนซ์คลาสผ่านตัวสร้างที่ไม่มีอาร์กิวเมนต์ ดังนั้นเมื่อคุณโทร
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
ไฮเบอร์เนตจะสร้างอินสแตนซ์วัตถุบุคคลของคุณดังนี้
Person.class.newInstance();
ซึ่งตามเอกสาร API
คลาสถูกสร้างอินสแตนซ์ราวกับว่าด้วยนิพจน์ใหม่ที่มีรายการอาร์กิวเมนต์ว่างเปล่า
นิทานสอนใจ
Person.class.newInstance();
เหมือนกับ
new Person();
ไม่มีอะไรอีกแล้ว
name
และage
? ถ้าไม่เช่นนั้นจะใช้ตัวสร้างอื่นในภายหลัง?
ที่จริงคุณสามารถสร้างอินสแตนซ์คลาสที่ไม่มีตัวสร้าง 0-args คุณสามารถรับรายชื่อตัวสร้างของคลาสเลือกหนึ่งและเรียกใช้ด้วยพารามิเตอร์ปลอม
แม้ว่าจะเป็นไปได้และฉันคิดว่ามันจะใช้งานได้และจะไม่มีปัญหา แต่คุณจะต้องยอมรับว่ามันค่อนข้างแปลก
การสร้างอ็อบเจกต์ในแบบที่ Hibernate ทำ (ฉันเชื่อว่ามันเรียกใช้ตัวสร้าง 0-arg จากนั้นมันอาจจะปรับเปลี่ยนฟิลด์ของอินสแตนซ์โดยตรงผ่าน Reflection บางทีมันอาจจะรู้วิธีการเรียก setters) จะขัดกับวิธีการสร้างอ็อบเจกต์ใน Java- เรียกใช้ตัวสร้างด้วยพารามิเตอร์ที่เหมาะสมเพื่อให้วัตถุใหม่เป็นวัตถุที่คุณต้องการ ฉันเชื่อว่าการสร้างอินสแตนซ์อ็อบเจ็กต์แล้วทำการกลายพันธุ์นั้นค่อนข้าง "ต่อต้าน Java" (หรือฉันจะพูดว่าต่อต้าน Java เชิงทฤษฎีบริสุทธิ์) - และแน่นอนว่าถ้าคุณทำสิ่งนี้ผ่านการจัดการฟิลด์โดยตรงมันจะไปห่อหุ้มและสิ่งห่อหุ้มแฟนซีทั้งหมด .
ฉันคิดว่าวิธีที่เหมาะสมในการทำเช่นนี้คือการกำหนดในการทำแผนที่ไฮเบอร์เนตว่าวัตถุควรถูกสร้างอินสแตนซ์จากข้อมูลในแถวฐานข้อมูลโดยใช้ตัวสร้างที่เหมาะสม ... แต่สิ่งนี้จะซับซ้อนกว่า - หมายความว่าไฮเบอร์เนตทั้งสองจะเท่ากัน ซับซ้อนมากขึ้นการทำแผนที่จะซับซ้อนมากขึ้น ... และทั้งหมดจะ "บริสุทธิ์" มากขึ้น และฉันไม่คิดว่าสิ่งนี้จะได้เปรียบกว่าแนวทางปัจจุบัน (นอกเหนือจากความรู้สึกดีที่ได้ทำสิ่งต่างๆ "วิธีที่เหมาะสม")
ต้องบอกว่าและเมื่อเห็นว่าวิธีการไฮเบอร์เนตนั้นไม่ "สะอาด" มากนักภาระหน้าที่ที่จะต้องมีตัวสร้าง 0-arg นั้นไม่จำเป็นอย่างยิ่ง แต่ฉันสามารถเข้าใจข้อกำหนดได้บ้างแม้ว่าฉันจะเชื่อว่าพวกเขาทำโดย "วิธีที่เหมาะสมเท่านั้น "เหตุเกิดเมื่อพวกเขาหลงจาก" วิธีที่เหมาะสม "(แม้ว่าจะมีเหตุผลที่สมเหตุสมผล) มากก่อนหน้านั้น
ไฮเบอร์เนตจำเป็นต้องสร้างอินสแตนซ์อันเป็นผลมาจากการสืบค้นของคุณ (ผ่านการสะท้อน) ไฮเบอร์เนตต้องอาศัยตัวสร้างเอนทิตีที่ไม่มีอาร์กิวเมนต์ดังนั้นคุณต้องระบุตัวสร้างที่ไม่มีอาร์กิวเมนต์ อะไรไม่ชัดเจน?
private
สร้างไม่ถูกต้องภายใต้เงื่อนไขใด ฉันเห็นjava.lang.InstantiationException
แม้จะมีตัวprivate
สร้างสำหรับเอนทิตี JPA ของฉัน เอกสารอ้างอิง .
การสร้างออบเจ็กต์ด้วยตัวสร้างแบบไม่มีพารามิเตอร์ผ่านการสะท้อนนั้นง่ายกว่ามากจากนั้นเติมคุณสมบัติด้วยข้อมูลผ่านการสะท้อนแทนที่จะพยายามจับคู่ข้อมูลกับพารามิเตอร์ตามอำเภอใจของตัวสร้างที่กำหนดพารามิเตอร์ด้วยการเปลี่ยนชื่อ / การตั้งชื่อความขัดแย้งตรรกะที่ไม่ได้กำหนดภายในตัวสร้าง ชุดพารามิเตอร์ไม่ตรงกับคุณสมบัติของวัตถุและอื่น ๆ
ORM และ serializers จำนวนมากต้องการตัวสร้างแบบไม่มีพารามิเตอร์เนื่องจากตัวสร้างพารามิเตอร์ที่ผ่านการสะท้อนนั้นบอบบางมากและตัวสร้างแบบไม่มีพารามิเตอร์ให้ทั้งความเสถียรต่อแอปพลิเคชันและการควบคุมพฤติกรรมของอ็อบเจ็กต์แก่ผู้พัฒนา
ไฮเบอร์เนตใช้พร็อกซีสำหรับการโหลดที่ขี้เกียจ หากคุณไม่กำหนดตัวสร้างหรือกำหนดให้เป็นแบบส่วนตัวบางสิ่งอาจยังใช้งานได้ - สิ่งที่ไม่ขึ้นอยู่กับกลไกของพร็อกซี ตัวอย่างเช่นการโหลดวัตถุ (โดยไม่มีตัวสร้าง) โดยตรงโดยใช้ Query 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: ไม่มีตัวสร้างเริ่มต้น
Hibernate ใช้ Reflection API เพื่อสร้างอินสแตนซ์ของ Entity beans โดยปกติเมื่อคุณเรียกใช้get()
หรือload()
วิธีการ วิธีClass.newInstance()
นี้ใช้สำหรับสิ่งนี้และต้องใช้ตัวno-args
สร้าง ดังนั้นหากคุณไม่มีตัวสร้าง no-args ในถั่วเอนทิตีไฮเบอร์เนตจะไม่สามารถสร้างอินสแตนซ์ได้และคุณจะได้รับ HibernateException
The no-argument constructor is a requirement
เป็นสิ่งที่ผิดและคำตอบทั้งหมดที่ดำเนินการอธิบายว่าทำไมเป็นเช่นนี้ได้โดยไม่ต้องตั้งคำถามว่านี่คือในความเป็นจริงเป็นเช่นนั้น (รวมถึงคำตอบที่ได้รับการยอมรับซึ่งได้รับแม้แต่เงินรางวัล) จะไม่ถูกต้อง ดูคำตอบนี้: stackoverflow.com/a/29433238/773113