I am getting an error when trying to fetch data from the database (the data exists in the db). I am able to perform the action when there is no data in the db.
This is my entities:
#Table(name = "tbl_task")
public class Task {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long taskId;
private String title;
private String description;
private Status status;
#ManyToOne
#JoinColumn(name = "user_id")
private User assignee;
#OneToMany(mappedBy = "task", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments;
and:
#Entity
#Table(name = "tbl_user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
private String name;
#Column(unique = true)
private String email;
private Active active;
private String password;
#OneToMany(mappedBy = "assignee", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Task> tasks;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments;
the error is:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw
exception [Request processing failed; nested exception is
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:
com.tasksmanagement.entity.Task["assignee"]-
>com.tasksmanagement.entity.User["tasks"]-
>org.hibernate.collection.internal.PersistentBag[0]
This is the method:
public List<TaskResponse> getAllTasks() {
List<Task> tasks = taskRepository.findAll();
return
tasks.stream().map(this::mapToTaskResponse).collect(Collectors.toList());
}
Any idea how to solve this?
Thanks
I added #JsonManagedReference in the User class (List tasks field)
and added #JsonBackReference in the Task class (User asignee field) and it solved the issue
Related
repository:
#Repository
public interface PostRepository extends PagingAndSortingRepository<Post, Long> {
#Query(value = "SELECT p.postComments FROM Post p WHERE p.webId = ?1")
Page<PostComment> findCommentsByWebId(String webid, Pageable pageable);
}
Post entity:
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "web_id")
private String webId;
#Column(nullable = false, name = "title")
private String title;
#Column(nullable = false, name = "description")
private String description;
#Column(nullable = false, name = "mature")
private boolean mature;
#OneToOne(mappedBy = "post")
private Cover cover;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#OneToMany(mappedBy = "post")
private List<PostView> postViews;
#ManyToMany
#JoinTable(name = "post_tag",
joinColumns = #JoinColumn(name = "post_id"),
inverseJoinColumns = #JoinColumn(name = "tag_id"))
private List<Tag> tags;
#OneToMany(mappedBy = "post")
private List<PostDownvote> postDownvotes;
#OneToMany(mappedBy = "post")
private List<PostUpvote> postUpvotes;
#OneToMany(mappedBy = "post")
private List<PostComment> postComments;
#Column(name = "created_at")
private Timestamp createdAt;
#Column(name = "updated_at")
private Timestamp updatedAt;
}
The problem: When returning plain List<PostComment> from the query method everything works fine. But if I change it to Page<PostComment> (I need total elements count), I get the following error:
2022-08-03 22:29:41.399 ERROR 9192 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: syntax error at or near "."
Position: 14
Hibernate: select tags0_.post_id as post_id1_6_0_, tags0_.tag_id as tag_id2_6_0_, tag1_.id as id1_10_1_, tag1_.name as name2_10_1_ from post_tag tags0_ inner join tag tag1_ on tags0_.tag_id=tag1_.id where tags0_.post_id=?
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
It is very difficult to debug this. Does anyone have any clue on what is wrong?
I need BOTH paging and total amount of elements.
Basically you are not able to fetch the part of the inner collection. But you could reach it from the another side of the bi-directional relationship
#Repository
public interface PostCommentRepository extends PagingAndSortingRepository<PostComment, Long> {
#Query(value = "SELECT pc FROM PostComment pc WHERE pc.post.webId = ?1")
Page<PostComment> findCommentsByWebId(String webid, Pageable pageable);
// or better using Spring Data naming conventions just
Page<PostComment> findAllByPostWebId(String webid, Pageable pageable);
}
If you only need a total count you should avoid querying list of entities which could be very memory intensive.
So in your PostCommentRepository try the following:
long countAllByPost_WebId(String webId);
I have this below entity classes.
Parent Entity:
---------------
public class MLW implements Serializable {
#Id
#Column(name = "mlwId", updatable = false, nullable = false)
private String mlwId;
#OneToOne(optional = false, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="mlwId")
private MLWJob mlwJob;
private Date createdDate;
private Date lastUpdatedDate;
}
public class MLWJob implements Serializable {
#Id
private String mlwId;
#Column(name = "Id")
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="mlwId")
private List<MLWJobItem> items;
}
public class MLWJobItem implements Serializable {
#Id
private String itemId;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="itemId")
private List<MLWJobItemExtension> mlwJobItemExtensions;
}
public class MLWJobItemExtension implements Serializable {
#Id
private String extnId;
#Id
private String itemId;
private String name;
private String value;
}
Repository class:
------------------
public interface MLWRepository extends JpaRepository<MLW, String> {
}
When I try to call save method using above repository I am getting below exception. Could someone help me to understand and fix this issue? TIA
could not delete collection rows:
[com.cpc.wgln.entity.MLWJobItem.mlwJobItemExtensions#0105021001713441];
nested exception is org.hibernate.exception.GenericJDBCException:
could not delete collection rows:
[com.cpc.wgln.entity.MLWJobItem.mlwJobItemExtensions#0105021001713441]
I am getting StackOverflow recursion error when I run query in Postman or Browser .
When i run says:
.w.s.m.s.DefaultHandlerExceptionResolver : Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)
Here is the model classes :
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private String title;
#NotNull
private String description;
#NotNull
private double price;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "category_id", nullable = false)
private Category category;
private boolean isSealed;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "currency_id", nullable = false)
private Currency currency;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id", nullable = false)
private User user;
#Nullable
#OneToMany(mappedBy = "product",
cascade = CascadeType.ALL, orphanRemoval = true)
private List<Images> images;
private Date createdDate = new Date();
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "product")
private View view;
#OneToOne(fetch = FetchType.LAZY,cascade=CascadeType.ALL)
#JoinColumn(name="type_id")
private Type type;
private Long viewCount; }
#Entity public class Images{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String imagePath;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "product_id")
private Product product; }
#Entity public class User implements UserDetails, Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty
private String fullName;
#NotEmpty
#Email
#Column(unique = true)
private String email;
#NotNull
#Column(unique = true)
private int phoneNumber;
#NotEmpty
#Size(min = 5)
private String password;
private Date createAt = new Date();
#Nullable
private String picPath;
#Nullable
private String token;
#ManyToMany
#JoinTable(name = "user_roles", joinColumns = {#JoinColumn(
name = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "role_id")})
private List<Role> roles;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "user")
private Product product;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "user")
private View view; }
#Entity
public class Currency{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String code;
private String currency;
private String region_country;
#OneToOne(mappedBy = "currency", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Product product; }
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String imagePath;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY,
mappedBy = "category")
private Product product;
#OneToMany(mappedBy = "category", fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
private Set<Brand> brands; }
#Entity public class Brand {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "category_id", nullable = false)
private Category category; }
#Entity public class View {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id", nullable = false)
private User user;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "product_id", nullable = false)
private Product product; }
#Entity public class Type {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private String name;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "type")
private Product product; }
#Id
private String role;
#ManyToMany(mappedBy = "roles")
private List<User> users;
}
More than one of your entities have each other in themselves.
For example, Product has an object of User, and User has an object of Product.
To solve this, you have to write
#JsonBackReference(value = "user-product")
private User user;
in the Product class,
and
#JsonManagedReference(value = "user-product")
private Product product;
In the user class.
Do it in every field and for every class that call each other.
Also, Check this out
JPA: Having lists on both ends without infinite loop
You have cycles in your data model. For example, Product holds Images and Images point back to Products.
This works in an object oriented world, because only pointer references are stored in those fields.
When serialized, however, the actual object is written out as json text. Your Product prints the Images object which in turn prints the Product object which again prints the Image object and so on.
You need to decide how you want to represent your json, map your database model into simple plain old java object and use this for serializations. These POJOs are often called View Model or Transport Objects.
i'm trying to solve infinity recursion issue with no success !
project: spring boot and postgresql
i have 3 entities : course, course outline and course schedule :
public class Course implements Serializable {
private static final long serialVersionUID = -6645577819394287204L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#OneToMany(mappedBy = "course", cascade = CascadeType.REMOVE)
#OrderBy("rank ASC")
private List<CourseOutline> outlines;
....
}
public class CourseOutline implements Serializable {
private static final long serialVersionUID = -6645577819394287204L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#ManyToOne
#JoinColumn(name = "course", nullable = false)
#JsonIgnore
private Course course;
private Integer rank;
#OneToMany(mappedBy = "outline", cascade = CascadeType.REMOVE)
#OrderBy("day DESC, started ASC")
private Set<CourseSchedule> schedules;
...
}
public class CourseSchedule implements Serializable {
private static final long serialVersionUID = -6645577819394287204L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#ManyToOne
#JoinColumn(name = "instructor", nullable = true)
#JsonManagedReference
private Person instructor;
#ManyToOne
#JoinColumn(name = "outline", nullable = false)
#JsonIgnore
private CourseOutline outline;
...
}
in REST API i make a call to retrieve a List of CourseOutline by course
using CourseOutline Repository :
List<CourseOutline> findAllByCourse(Course course);
but i get below error :
Could not write JSON: Infinite recursion (StackOverflowError); nested
exception is com.fasterxml.jackson.databind.JsonMappingException:
Infinite recursion (StackOverflowError) (through reference chain:
java.util.ArrayList[2]-myDomain.api.models.entities.CourseOutline[\"schedules\"])"
I have two entity types in Spring with a relationship:
#Entity
public class Domain {
public Domain() {}
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
private String name;
private String description;
private String image;
#OneToMany(cascade=CascadeType.ALL, targetEntity=Subdomain.class,fetch = FetchType.LAZY)
#JoinColumn(name="domain_id")
private Set<Subdomain> subdomain = new HashSet<>();
//Default getters and setters
}
And the type subdomain:
#Entity
public class Subdomain {
public Subdomain() {}
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
private String name;
#JsonIgnore
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "domain_id", nullable = false)
public Domain domain;
//Default getters and setters
}
This works perfect with a get request, the relation is fetched. But how does it works with post request? I would create a new subdomain with the relationship to an existing domain:
"domain_id": "2"
And this:
"domain_id": "http://localhost/subdomain/2"
But this doesn't work. What is the best way to solve this?
Could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement