Saya sedang mengerjakan SpringMVC
, Hibernate
& JSON
tetapi saya mendapatkan kesalahan ini.
HTTP Status 500 - Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.SerializationFeature.FAIL_ON_EMPTY_BEANS) )
Silakan periksa Entitas saya di bawah
@Entity
@Table(name="USERS")
public class User {
@Id
@GeneratedValue
@Column(name="USER_ID")
private Integer userId;
@Column(name="USER_FIRST_NAME")
private String firstName;
@Column(name="USER_LAST_NAME")
private String lastName;
@Column(name="USER_MIDDLE_NAME")
private String middleName;
@Column(name="USER_EMAIL_ID")
private String emailId;
@Column(name="USER_PHONE_NO")
private Integer phoneNo;
@Column(name="USER_PASSWORD")
private String password;
@Column(name="USER_CONF_PASSWORD")
private String confPassword;
@Transient
private String token;
@Column(name="USER_CREATED_ON")
private Date createdOn;
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@Fetch(value = FetchMode.SUBSELECT)
@JoinTable(name = "USER_ROLES", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") })
private List<ActifioRoles> userRole = new ArrayList<ActifioRoles>();
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL,mappedBy="userDetails")
@Fetch(value = FetchMode.SUBSELECT)
private List<com.actifio.domain.Address> userAddress = new ArrayList<com.actifio.domain.Address>();
@OneToOne(cascade=CascadeType.ALL)
private Tenant tenantDetails;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfPassword() {
return confPassword;
}
public void setConfPassword(String confPassword) {
this.confPassword = confPassword;
}
public Date getCreatedOn() {
return createdOn;
}
public void setCreatedOn(Date createdOn) {
this.createdOn = createdOn;
}
public List<ActifioRoles> getUserRole() {
return userRole;
}
public void setUserRole(List<ActifioRoles> userRole) {
this.userRole = userRole;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public Integer getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(Integer phoneNo) {
this.phoneNo = phoneNo;
}
public List<com.actifio.domain.Address> getUserAddress() {
return userAddress;
}
public void setUserAddress(List<com.actifio.domain.Address> userAddress) {
this.userAddress = userAddress;
}
public Tenant getTenantDetails() {
return tenantDetails;
}
public void setTenantDetails(Tenant tenantDetails) {
this.tenantDetails = tenantDetails;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
Bagaimana saya bisa memecahkan masalah ini?
Jawaban:
Saya memiliki masalah serupa dengan pemuatan lambat melalui objek proxy hibernasi. Mengatasinya dengan memberi anotasi kelas yang memiliki properti pribadi lazy dimuat dengan:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
Saya berasumsi bahwa Anda dapat menambahkan properti pada objek proxy Anda yang merusak serialisasi JSON ke anotasi itu.
Masalahnya adalah entitas dimuat dengan malas dan serialisasi terjadi sebelum mereka dimuat sepenuhnya.
Hibernate.initialize(<your getter method>);
sumber
Hanya untuk menambahkan ini, saya mengalami masalah yang sama ini, tetapi jawaban yang diberikan tidak berfungsi. Saya memperbaikinya dengan mengambil saran pengecualian dan menambahkan ke file application.properties ...
spring.jackson.serialization.fail-on-empty-beans=false
Saya menggunakan Spring Boot v1.3 dengan Hibernate 4.3
Sekarang serialisasi seluruh objek dan objek bersarang.
EDIT: 2018
Karena ini masih mendapat komentar saya akan klarifikasi di sini. Ini benar-benar hanya menyembunyikan kesalahan. Implikasi kinerja ada di sana. Pada saat itu, saya membutuhkan sesuatu untuk dikirimkan dan dikerjakan nanti (yang saya lakukan dengan tidak menggunakan pegas lagi). Jadi ya, dengarkan orang lain jika Anda benar-benar ingin menyelesaikan masalah. Jika Anda hanya ingin itu pergi sekarang, lanjutkan dan gunakan jawaban ini. Itu ide yang buruk, tapi mungkin berhasil untuk Anda. Sebagai catatan, tidak pernah mengalami crash atau masalah lagi setelah ini. Tapi itu mungkin sumber dari apa yang akhirnya menjadi mimpi buruk kinerja SQL.
sumber
"handler":{},"hibernateLazyInitializer":{}
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
Seperti yang disarankan dengan benar dalam jawaban sebelumnya, lazy loading berarti bahwa saat Anda mengambil objek dari database, objek bertingkat tidak akan diambil (dan dapat diambil nanti saat diperlukan).
Sekarang Jackson mencoba untuk membuat serial objek bersarang (== membuat JSON darinya), tetapi gagal karena menemukan JavassistLazyInitializer alih-alih objek normal. Ini adalah kesalahan yang Anda lihat. Sekarang, bagaimana cara mengatasinya?
Seperti yang disarankan oleh CP510 sebelumnya, salah satu opsinya adalah untuk menekan kesalahan dengan baris konfigurasi ini:
spring.jackson.serialization.fail-on-empty-beans=false
Tapi ini berurusan dengan gejalanya, bukan penyebabnya . Untuk menyelesaikannya dengan elegan, Anda perlu memutuskan apakah Anda memerlukan objek ini di JSON atau tidak?
Jika Anda memerlukan objek di JSON, hapus
FetchType.LAZY
opsi dari kolom yang menyebabkannya (mungkin juga kolom di beberapa objek bersarang, tidak hanya di entitas root yang Anda ambil).Jika tidak membutuhkan objek dalam JSON, beri anotasi pada pengambil bidang ini (atau bidang itu sendiri, jika Anda juga tidak perlu menerima nilai yang masuk) dengan
@JsonIgnore
, misalnya:// this field will not be serialized to/from JSON @JsonIgnore private NestedType secret;
Jika Anda memiliki kebutuhan yang lebih kompleks (mis. Aturan berbeda untuk pengontrol REST yang berbeda menggunakan entitas yang sama), Anda dapat menggunakan tampilan atau pemfilteran jackson atau untuk kasus penggunaan yang sangat sederhana, ambil objek bersarang secara terpisah.
sumber
RangeError: Maximum call stack size exceeded
Anda dapat menggunakan modul add-on untuk Jackson yang menangani pemuatan lambat Hibernate.
Info lebih lanjut di https://github.com/FasterXML/jackson-datatype-hibernate yang mendukung hibernate 3 dan 4 secara terpisah.
sumber
Saya pikir masalahnya adalah cara Anda mengambil entitas.
Mungkin Anda melakukan sesuatu seperti ini:
Person p = (Person) session.load(Person.class, new Integer(id));
Coba gunakan metode ini
get
daripadaload
Person p = (Person) session.get(Person.class, new Integer(id));
Masalahnya adalah bahwa dengan metode pemuatan Anda hanya mendapatkan proxy tetapi bukan objek yang sebenarnya. Objek proxy tidak memiliki properti yang sudah dimuat sehingga ketika serialisasi terjadi, tidak ada properti yang akan diserialkan. Dengan metode get, Anda benar-benar mendapatkan objek sebenarnya, objek ini sebenarnya bisa menjadi serial.
sumber
itu berhasil untuk saya
@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})
misalnya
@Entity @Table(name = "user") @Data @NoArgsConstructor @JsonIgnoreProperties({"hibernateLazyInitializer","handler"}) public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private Date created; }
sumber
Ada dua cara untuk mengatasi masalah tersebut.
Cara 1 :
Tambahkan
spring.jackson.serialization.fail-on-empty-beans=false
ke application.propertiesCara 2 :
Gunakan
join fetch
dalam query JPQL untuk mengambil data objek induk, lihat di bawah ini:@Query(value = "select child from Child child join fetch child.parent Parent ", countQuery = "select count(*) from Child child join child.parent parent ") public Page<Parent> findAll(Pageable pageable);
sumber
Tambahkan Anotasi ini ke Kelas Entitas (Model) yang berfungsi untuk saya, ini menyebabkan pemuatan lambat melalui objek proxy hibernate.
sumber
Pengecualian ini
mendapatkan karena, saya harap demikian, Anda mengirimkan keluaran respons sebagai objek Serializable.
Ini masalah yang terjadi di musim semi. Untuk mengatasi masalah ini, kirim objek POJO sebagai output respons.
Contoh:
@Entity @Table(name="user_details") public class User implements Serializable{ @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name="id") private Integer id; @Column(name="user_name") private String userName; @Column(name="email_id") private String emailId; @Column(name="phone_no") private String phone; //setter and getters
Kelas POJO:
public class UserVO { private int Id; private String userName; private String emailId; private String phone; private Integer active; //setter and getters
Dalam pengontrol, ubah bidang objek yang dapat diserifikasi menjadi bidang kelas POJO dan kembalikan kelas pojo sebagai keluaran.
User u= userService.getdetials(); // get data from database UserVO userVo= new UserVO(); // created pojo class object userVo.setId(u.getId()); userVo.setEmailId(u.getEmailId()); userVo.setActive(u.getActive()); userVo.setPhone(u.getPhone()); userVo.setUserName(u.getUserName()); retunr userVo; //finally send pojo object as output.
sumber
Di Hibernate 5.2 dan yang lebih baru, Anda dapat menghapus proxy hibernate seperti di bawah ini, ini akan memberi Anda objek yang sebenarnya sehingga Anda dapat membuat serial dengan benar:
Object unproxiedEntity = Hibernate.unproxy( proxy );
sumber
Hibernate.initialize
sebelumnya juga.Untuk Hibernate Anda dapat menggunakan proyek jackson-datatype-hibernate untuk mengakomodasi serialisasi / deserialisasi JSON dengan objek yang dimuat lambat.
Sebagai contoh,
import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JacksonDatatypeHibernate5Configuration { // Register Jackson Hibernate5 Module to handle JSON serialization of lazy-loaded entities // Any beans of type com.fasterxml.jackson.databind.Module are automatically // registered with the auto-configured Jackson2ObjectMapperBuilder // https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper @Bean public Module hibernate5Module() { Hibernate5Module hibernate5Module = new Hibernate5Module(); hibernate5Module.enable( Hibernate5Module.Feature.FORCE_LAZY_LOADING ); hibernate5Module.disable( Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION ); return hibernate5Module; } }
sumber
can't parse JSON. Raw result:
. Ada bantuan?Solusinya terinspirasi dari solusi di bawah ini oleh @marco. Saya juga telah memperbarui jawabannya dengan datails ini.
Masalahnya di sini adalah tentang pemuatan lambat sub-objek, di mana Jackson hanya menemukan proxy hibernasi, bukan objek yang sepenuhnya meledak.
Jadi kita dibiarkan dengan dua pilihan - Tekan pengecualian, seperti yang dilakukan di atas pada sebagian besar jawaban yang dipilih di sini, atau pastikan bahwa objek LazyLoad dimuat.
Jika Anda memilih untuk menggunakan opsi terakhir, solusinya adalah menggunakan pustaka jackson-datatype , dan mengonfigurasi pustaka untuk menginisialisasi dependensi lazy-load sebelum serialisasi.
Saya menambahkan kelas konfigurasi baru untuk melakukan itu.
@Configuration public class JacksonConfig extends WebMvcConfigurerAdapter { @Bean @Primary public MappingJackson2HttpMessageConverter jacksonMessageConverter(){ MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); ObjectMapper mapper = new ObjectMapper(); Hibernate5Module module = new Hibernate5Module(); module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING); mapper.registerModule(module); messageConverter.setObjectMapper(mapper); return messageConverter; }
}
@Primary
memastikan bahwa tidak ada konfigurasi Jackson lain yang digunakan untuk menginisialisasi kacang lainnya.@Bean
seperti biasa.module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);
adalah mengaktifkan pemuatan lambat dependensi.Perhatian - Harap perhatikan dampak kinerjanya. terkadang pengambilan EAGER membantu, tetapi meskipun Anda membuatnya bersemangat, Anda masih akan membutuhkan kode ini, karena objek proxy masih ada untuk semua Pemetaan lainnya kecuali
@OneToOne
PS: Sebagai komentar umum, saya akan melarang praktik pengiriman seluruh objek data kembali ke respons Json, Seseorang harus menggunakan Dto untuk komunikasi ini, dan menggunakan beberapa mapper seperti mapstruct untuk memetakannya. Ini menyelamatkan Anda dari celah keamanan yang tidak disengaja, serta pengecualian di atas.
sumber
Saya punya masalah yang sama sekarang. periksa apakah Anda memperbaiki fetch in lazy dengan @jsonIQgnore
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="teachers") @JsonIgnoreProperties("course") Teacher teach;
Hapus saja "(fetch = ...)" atau anotasi "@jsonIgnore" dan itu akan berfungsi
@ManyToOne @JoinColumn(name="teachers") @JsonIgnoreProperties("course") Teacher teach;
sumber
Atau Anda bisa mengkonfigurasi mapper sebagai:
// konfigurasi khusus untuk pemuatan lambat
public static class HibernateLazyInitializerSerializer extends JsonSerializer<JavassistLazyInitializer> { @Override public void serialize(JavassistLazyInitializer initializer, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { jsonGenerator.writeNull(); } }
dan konfigurasikan mapper:
mapper = new JacksonMapper(); SimpleModule simpleModule = new SimpleModule( "SimpleModule", new Version(1,0,0,null) ); simpleModule.addSerializer( JavassistLazyInitializer.class, new HibernateLazyInitializerSerializer() ); mapper.registerModule(simpleModule);
sumber
Bisa jadi hubungan entitas Hibernate Anda yang menyebabkan masalah ... cukup hentikan pemuatan lambat entitas terkait itu ... misalnya ... Saya menyelesaikan di bawah ini dengan menyetel lazy = "false" untuk customerType.
<class name="Customer" table="CUSTOMER"> <id name="custId" type="long"> <column name="CUSTID" /> <generator class="assigned" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <property name="phone" type="java.lang.String"> <column name="PHONE" /> </property> <property name="pan" type="java.lang.String"> <column name="PAN" /> </property> <many-to-one name="customerType" not-null="true" lazy="false"></many-to-one> </class> </hibernate-mapping>
sumber
Saya berubah (di kelas model Anotasi)
untuk
dan bekerja dengan cara yang cantik ...
Suka.
sumber
fetch
strategi pada model memiliki beberapa konsekuensi dalam kinerja. Dengan perubahan ini, Anda membawa lebih banyak data dari database. Ini mungkin solusi yang valid, tetapi pertama-tama studi kinerja diperlukan.Ini adalah masalah Jackson. Untuk mencegah hal ini, perintahkan Jackson untuk tidak membuat serial hubungan bertingkat atau kelas bertingkat.
Lihat contoh berikut. Kelas alamat dipetakan ke kelas Kota , Negara Bagian , dan Negara dan Negara Bagian itu sendiri menunjuk ke Negara dan Negara menunjuk ke Kawasan. Ketika Anda mendapatkan nilai alamat melalui Spring boot REST API Anda akan mendapatkan kesalahan di atas. Untuk mencegahnya, cukup buat serialisasi kelas yang dipetakan (yang mencerminkan JSON tingkat satu) dan abaikan hubungan bertingkat dengan
@JsonIgnoreProperties(value = {"state"})
,@JsonIgnoreProperties(value = {"country"})
dan@JsonIgnoreProperties(value = {"region"})
Ini akan mencegah pengecualian Lazyload bersama dengan kesalahan di atas. Gunakan kode di bawah ini sebagai contoh dan ubah kelas model Anda.
Address.java
@Entity public class Address extends AbstractAuditingEntity { private static final long serialVersionUID = 4203344613880544060L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "street_name") private String streetName; @Column(name = "apartment") private String apartment; @ManyToOne @JoinColumn(name = "city_id") @JsonIgnoreProperties(value = {"state"}) private City city; @ManyToOne @JoinColumn(name = "state_id") @JsonIgnoreProperties(value = {"country"}) private State state; @ManyToOne @JoinColumn(name = "country_id") @JsonIgnoreProperties(value = {"region"}) private Country country; @ManyToOne @JoinColumn(name = "region_id") private Region region; @Column(name = "zip_code") private String zipCode; @ManyToOne @JoinColumn(name = "address_type_id", referencedColumnName = "id") private AddressType addressType; }
City.java
@EqualsAndHashCode(callSuper = true) @Entity @Table(name = "city") @Cache(region = "cityCache",usage = CacheConcurrencyStrategy.READ_WRITE) @Data public class City extends AbstractAuditingEntity { private static final long serialVersionUID = -8825045541258851493L; @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") //@Length(max = 100,min = 2) private String name; @ManyToOne @JoinColumn(name = "state_id") private State state; }
State.java
@Entity @Table(name = "state") @Data @EqualsAndHashCode(callSuper = true) public class State extends AbstractAuditingEntity { private static final long serialVersionUID = 5553856435782266275L; @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "code") private String code; @Column(name = "name") @Length(max = 200, min = 2) private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "country_id") private Country country; }
Country.java
@Entity @Table(name = "country") @Data @EqualsAndHashCode(callSuper = true) public class Country extends AbstractAuditingEntity { private static final long serialVersionUID = 6396100319470393108L; @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") @Length(max = 200, min = 2) private String name; @Column(name = "code") @Length(max = 3, min = 2) private String code; @Column(name = "iso_code") @Length(max = 3, min = 2) private String isoCode; @ManyToOne @JoinColumn(name = "region_id") private Region region; }
sumber
@JsonIgnoreProperties ({"hibernateLazyInitializer", "handler"})
itu berhasil untuk saya
sumber
Mencoba
implements interface Serializable
sumber