Failed to lazily initialize a collection of role. Simple JPA findById - java

I'm using Spring and JPA (Hibernate with MySQL) and Lombok also.
Hi have this part of my entities:
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "entitya")
public class EntityA implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ea_id")
Long id;
....
#ManyToOne
#JoinColumn(name="g_id", nullable=false)
private Group group;
....
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "group")
public class Group implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="g_id")
private Long id;
#OneToMany(mappedBy="group")
private List<EntityA> enitiesA = new ArrayList<>();
...
}
I implemented also the repository extends JPARepository.
Into my controllers, if I try to retrieve an EntityA by Id I obtain this exception:
failed to lazily initialize a collection of role: com.mytest.entity.Group.enitiesA, could not initialize proxy - no Session
For me it's strange because I need to retrieve only the object. I not use some getter methods on this. So, in theory, using the default fetch types, I don't need to have also the group list.
What's wrong?

Are you debugging your object with toString()?
In case it could be an error caused by the #Data annotation.
The generated toString() method contains all fields, so it might call the enitiesA variable, producing the lazy initialization error.
https://mdeinum.github.io/2019-02-13-Lombok-Data-Ojects-Arent-Entities/

Likely it's because you're accessing group.enitiesA outside of the transactional boundaries. If you want to do this, you can eager fetch them by adding eager fetch type to your OneToMany mapping such as
#OneToMany(mappedBy="group", fetch = FetchType.EAGER)
This will load the entire object graph when the parent is loaded.
If you still want to do lazy loading, look to encapsulate all of the calls into the children under the session that loaded the parent.

Related

Infinite recursion with Jackson on intermediate table

I am using Spring Boot and Jackson and Hibernate to create an API. Hibernate connects to a MySQL database.
I understand the good practices but I'm stuck on a particular point.
I have an n:m relationship that contains an extra field.
Ex: Author(id, ...) -> Written(idAuthor, idBook, date) <- Book(id, ...)
I understand how to map a traditional n:m relationship, but this technique does not apply to me this time.
For this, I found a source on the internet that showed the solution: create an intermediate class in my code that contains an Author type object and a Book type object + my additional fields.
#Entity
#Table(name = "Author")
public class Author implements Serializable {
/...
#Id
#GeneratedValue
private int id;
#OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
private Set<Written> written= new HashSet<>();
/...
}
#Entity
#Table(name = "Book")
public class Book implements Serializable{
/...
#Id
#GeneratedValue
private int id;
#OneToMany(mappedBy = "book", cascade = CascadeType.ALL)
private Set<Written> written= new HashSet<>();
/...
}
public class Written implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "idAuthor")
private Author author;
#Id
#ManyToOne
#JoinColumn(name = "idBook")
private Book book;
//Extra fields ....
}
That's a bidirectional link.
With this code, I get an infinite recursivity error:
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]->com.exampleAPI.api.model.Book["written"])]
I tried to use #JsonIgnore, #JsonManagedReference and #JsonBackReference on the Written class, also tried to use transient keyword, but nothing worked.
I can't find any source on the internet that could help me, and neither can the documentation for this particular case.
Can someone help me?
When unhandled bidirectional relationship occurs, Jackson faces infinite recursion.
I tried to use #JsonIgnore, #JsonManagedReference and #JsonBackReference on the Written class
You need to use #JsonManagedReference and #JsonBackReference annotations separately to prevent these cycles between Book and Written. A side note, transient has nothing to do with the persistence but the serialization. JPA works with the #Transient annotation.
public class Book implements Serializable {
#OneToMany(mappedBy = "book", cascade = CascadeType.ALL)
#JsonBackReference
private Set<Written> written= new HashSet<>();
...
}
public class Written implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "idBook")
#JsonManagedReference
private Book book;
...
}
Important: Don't send database entities through REST (probably what you are up to do). Better create a DAO object without bidirectional relationship and map entities into DAOs. There are several libraries able to do that: I highly recommend MapStruct, however ModelMapper is also an option. If there is a lower number of such entities, using constructors/getters/setters would be enough.

JPA : How to create a self-join entity?

I have a user entity with an assistant column.
Every user has an assistant but there are circles as well.
For example : User A's assistant is User B and User B's assistant is
user A.
If I use #ManyToOne and #OneToMany annotations, then, there is an infinite recursion when converting objects to JSON, even #JsonManagedReference and
#JsonBackReference didn't help.
BaseEntity:
#MappedSuperclass
#Data
public class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
#Version
private int version;
}
User:
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Data
#EqualsAndHashCode(callSuper = true)
#Table(name = "Users")
public class User extends BaseEntity {
#Column
private String username;
#Column
private String name;
#JsonManagedReference
#ManyToOne
#JoinColumn(name = "assistant_id")
private User assistant;
#JsonBackReference
#OneToMany(mappedBy = "assistant")
private Set<User> assistants;
}
Are there any opportunity in Spring to solve this?
#JsonManagedReference/#JsonBackReference won't help, because the 'forward' references can still form a cycle, even when the 'inverse' references are not being serialized.
What you want is probably for the User assigned to the assistant property to be serialized without its own assistant property (so that any cycles break). Essentially, you have the same issue as here, except in your case A and B are the same class.
Apart from the solution described in the question I've linked to, you'll also want to specify which #JsonView to use when serializing the object. See the 'Using JSON Views with Spring' section here.
Could you create Assistant entity based on the same table and join?

Spring relationship get child id without load sub class

How to get DEPARTMENT_ID of the base class without loading sub-class in Spring boot JPA
For example we have a base model:
#Entity
#Table(name = "TM_POSITIONS")
public class PositionEntity {
#Id
#SequenceGenerator(name = "PositionsSequence", sequenceName = "TM_POSITIONS_SEQ", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PositionsSequence")
private long id;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
#JoinColumn(name = "DEPARTMENT_ID")
private DepartmentModel department;
...
So, how to just get DEPARTMENT_ID without bundle it and load another object. In some cases, I need to get related Model and in some cases, I need to get just DEPARTMENT_ID.
You can create a responseDTO class and a mapper class for that.
#ApiModel
public class positionEntityResponseDTO{
private long id;
private long departmentId;
//getter & setter
}
And the mapper class look like
#Service
public class ResponseMapper{
public positionEntityResponseDTO map (PositionEntity entity){
positionEntityResponseDTO response = new positionEntityResponseDTO();
response.setId(entity.getId);
response.setDepartmentId(entity.getDepartment.getId();
return response;
}
}
now suppose somewhere you write
#Autowired
private ResponseMapper mapper;
positionEntityResponseDTO response= mapper.map(repository.save(entity));
now you can pass only DEPARTMENT_ID by response object. hope this works for you.
First of all you need to set the fetch = FetchType.LAZY. In the EAGER way the sub-class will always be loaded.
If you set the fetch type lazy, you can reach the sub-class's id (primary-key) field without extra db queries.
So if you write position.getDepartment().getId() you will get the id and it won't cost anything.
Keep in mind, that other method calls on the sub-class will be load it from the database, e.g.: toString, equals, or getName() /if there is such a method/.
In the case you need the sub-class for some other functionalities, you should write another query in your reposiroty which will fetch the sub-class too.
#Query("SELECT pos FROM Position LEFT JOIN FETCH pos.department")
With JOIN FETCH Spring Data JPA will generate a single query which will join the two table, so you can avoid the N+1 problem.

Spring-Data Jpa Inheritance: Keeping Entity Id's in Children Entity

I'm dealing with a couple of Entities with Tree like structures that were getting more complicated so I decided to create an abstract class for it so code was a bit more mainainable:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class TreeStructure<T extends TreeStructure>
{
#ManyToOne
protected T parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
protected Set<T> children = new HashSet<>();
//...
Then I have two Entities which extend it:
#Entity(name = "TreeStructureOne")
public class TreeStructureOne extends TreeStructure<TreeStructureOne>
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty("TreeStructureOne_id")
private long id;
And I basically want the database to be completely unaware of this TreeStructure abstraction and save all of the fields in each Entities tableand expected InheritanceType.TABLE_PER_CLASS to deal with that. But it seems I need to define the Id in the TreeStructure Entity at least or I get:
Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: TreeStructure
And I don't want to add an ID into the abstract class since this makes three tables in the database called: HT_TREE_STRUCTURE, HT_TREE_STRUCTURE_ONE and HT_TREE_STRUCTURE_TWO with one field ID each one.
Is there any solution to that?
Since TreeStructure is not an #Entity use only #MappedSuperclass
#MappedSuperclass
public abstract class TreeStructure<T extends TreeStructure> {
instead of #Entity and #Inheritance for the parent class.
You can find #MappedSuperclass in the Oracle JEE API documentation.

Spring data lazy load not working

I have the two entities similar to the ones below:
#Entity
#DynamicUpdate
public class EntityOne {
#Id
public long id;
public String name;
public String displayName;
#JsonManagedReference
#OneToMany(mappedBy = "id", cascade = CascadeType.ALL)
#OrderBy(value = "name")
public List<EntityTwo> entityTwoList;
}
entity two is
#Entity
#DynamicUpdate
public class EntityTwo {
#Id
public long id;
#JsonBackReference
#ManyToOne
#JoinColumn(name = "id")
public EntityOne entityOne;
}
service:
Lists.newArrayList(repository.findAll());
The service calls the findAll() method of the CRUDRepository. I don't want the list of entity two objects to load when calling findall() but this solution doesn't work.
Anything incorrect that i am doing here to lazy load the collection. I basically don't want the collection to be loaded until its specified.
By default the mappings are lazy load.
I am assuming jackson is trying to load your child objects.
Try followjackson-datatype-hibernate4:2.4.4
Add jackson-datatype-hibernate4:2.4.4 to your dependency and define following bean
#Bean
public Jackson2ObjectMapperBuilder configureObjectMapper() {
return new Jackson2ObjectMapperBuilder()
.modulesToInstall(Hibernate4Module.class);
}
I don't know about jackson but according to jpa specs you can not force LAZY loading neither can you rely upon it ... you just provide the lazy load hint and it's totally up to the provider to load it lazily or not (unlike EAGER , it forces loading)
First try this,i think you need to specify fetch type lazy or Eager
ManyToOne(fetch= FetchType.LAZY)

Categories