Reputation: 6124
I am having an Person
entity which has @ManyToOne
association with Contact
entity with fetch type LAZY. I am using spring-boot to expose REST API. One of my POST call contains nested JSON to save the parent entity Person
along with association Contact
Since Contact
fetch type is LAZY, I am encountering into following exception
ERROR 17415 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.rest.RestResultObject["results"]->java.util.ArrayList[0]->com.example.model.Person["contact"]->com.example.model.Contact_$$_jvst8d1_4["handler"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.rest.RestResultObject["results"]->java.util.ArrayList[0]->com.example.model.Person["contact"]->com.example.model.Contact_$$_jvst8d1_4["handler"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.3.jar:2.9.3]
Without changing Contact to EAGER. Is there any best way to solve this problem?
Updated:
Person.java
public class Person {
private long id;
private String name;
private String rno;
@ManyToOne(fetch = FetchType.LAZY)
private Contact contact;
// Getters and setters
}
Contact.java
public class Contact {
private long id;
private String info;
@OneToMany
private List<Person> persons;
}
Upvotes: 4
Views: 13954
Reputation: 1051
This is the one way to solve the problem by using @JsonIgnore
annotation along with fethType.LAZY
public class Person {
private long id;
private String name;
private String rno;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
private Contact contact;
// Getters and setters
}
public class Contact {
private long id;
private String info;
@OneToMany
private List<Person> persons;
}
Upvotes: 0
Reputation: 1945
I have added the following things
long
to Long
in id, this will help you if you use spring data JPA@Id
to declare id as primary key@JsonBackReference
& @JsonManagedReference
to avoid infinite loop by JacksonPerson class
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String rno;
@JsonManagedReference
@ManyToOne(fetch = FetchType.LAZY)
private Contact contact;
//setter & getter
}
Contact class
@Entity
public class Contact {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String info;
@JsonBackReference
@OneToMany(cascade = CascadeType.ALL, mappedBy = "contact")
private List<Person> persons;
//setter & getter
}
and add a dependency
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
and finally add a new config
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomBigDecimalDeserialization() {
return new Jackson2ObjectMapperBuilderCustomizer() {
@Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
jacksonObjectMapperBuilder.modules(new Hibernate5Module());
}
};
}
}
Upvotes: 5
Reputation: 444
The problem, most likely, is related to transaction processing. JSON serialization is executed out of transaction scope. If so, the easiest solution (not necessarily the best from the architectural point of view) is to create the service that wrap the entity loading (dedicated for REST operations) and perform "delazyfication" of related data, e.g. (the key element is @Transactional
anotation).
@Sevice
@Transactional(readOnly=true)
public class DataReaderServiceImpl extends DataLoaderService{
//initialization code
public Person loadPerson(PredicatesType somePredicate){
Person person = //get person using predicates expression
//"delazy" contacts in transaction scope
person.getContacts();
return person;
}
}
Architecturally, it would be better, in such a service, to have mapping to DTOs and return DTO instances instead of entities.
Upvotes: 1