BeanCreationException because of Hibernate mapping - java

I'm getting this a BeanCreationException and I think it's because of my hibernate mappings.
I've been trying to figure out what mapping is wrong but no luck so far!
Customer class :
#Entity
#Data
#Table(name = "customer")
public class Customer {
#Id
#Column(name = "registration_code")
private String registrationCode;
private String name;
private String email;
private String phoneNumber;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer", cascade = {CascadeType.MERGE, CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST})
private List<Order> orders;
}
Order class:
#Data
#Entity
#Table(name = "order")
public class Order {
#ManyToOne
#JoinColumn(name = "customer_code")
private Customer customer;
#Id
#OneToMany
#JoinColumn(name = "order_line_id")
private List<OrderLine> orderLines;
#Column(name = "date",columnDefinition = "DATE")
private LocalDate dateOfSubmission;
}
OrderLine class:
#Data
#Entity
#Table(name = "order_line")
public class OrderLine {
#Id
#Column(name = "order_line_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#ManyToOne
#JoinColumn(name = "product_code")
private Product product;
private Integer quantity;
}
Product class:
#Data
#Entity
#Table(name = "product")
public class Product {
#Id
private String skuCode;
private String name;
private Long price;
}
It's a spring boot application and I'm using Spring Data JPA

Related

Accessing #JoinTable in many-to-many relationship in Springboot JPA

I've created an API that has actor, movie and category entities. Actor and movie are connected by many-to-many relationship that maps to a join table called movie_actor and category is connected with movie by one-to-many relationship.
I'm trying to write a native query that returns an integer that would represent the amount of movies from a specific category where specific actor has played so for example query would return 2 if actor played in 2 different sci-fi movies. I have no problem doing that from the database level where I can see the join table movie_actor but that table remains unaccessible in my api because it's not a separate entity. How can I create it that it automatically maps actor and movie ids as the movie_actor table ?
Here is an example code that works for me in the H2 Database:
SELECT COUNT(*) FROM MOVIE M JOIN MOVIE_ACTOR MA on M.MOVIE_ID = MA.MOVIE_ID WHERE ACTOR_ID = 1 AND CATEGORY_ID = 1
Here are my entities:
Actor:
#Entity
#Data
#Table(name = "actor")
#AllArgsConstructor
#NoArgsConstructor
public class Actor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private long actorId;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#Nullable
#ManyToMany(mappedBy = "actors", fetch = FetchType.EAGER)
#JsonBackReference
private List<Movie> movies = new ArrayList<>();
public Actor(String name, String surname){
this.name = name;
this.surname = surname;
}
}
Movie:
#Entity
#Data
#Table(name = "movie")
#AllArgsConstructor
#NoArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private long movieId;
#Column(name = "title")
private String title;
#ManyToMany
#JoinTable(
name = "movie_actor",
joinColumns = #JoinColumn(name = "movie_id"),
inverseJoinColumns = {#JoinColumn(name = "actor_id")}
)
#JsonManagedReference
private List<Actor> actors = new ArrayList<>();
#ManyToOne
#JoinColumn(name = "CATEGORY_ID")
#JsonManagedReference
private Category category;
}
So you have to make it accessible in your API. One option would be to map the intersection table movie_actor to the entity MovieActor and split ManyToMany relationship between Actor and Movie to OneToMany relationship with MovieActor, like that:
#Entity
#Data
#Table(name = "movie_actor")
#AllArgsConstructor
#NoArgsConstructor
public class MovieActor {
#EmbeddedId
private MovieActorId productOrderId = new MovieActorId();
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#MapsId("movieId")
#JoinColumn(name = "product_id", nullable = false)
private Movie movie;
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#MapsId("actorId")
#JoinColumn(name = "order_id", nullable = false)
private Actor actor;
public void addMovieActor(Movie aMovie, Actor aActor) {
movie = aMovie;
actor = aActor;
aMovie.getMovieActors().add(this);
aActor.getMovieActors().add(this);
}
}
#Embeddable
#Getter
#Setter
public class MovieActorId implements Serializable {
#Column(name = "movie_id")
private Long movieId;
#Column(name = "actor_id")
private Long actorId;
}
#Entity
#Data
#Table(name = "actor")
#AllArgsConstructor
#NoArgsConstructor
public class Actor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private long actorId;
#OneToMany(mappedBy = "actor")
private List<MovieActor> movieActors = new ArrayList<>();
}
#Entity
#Data
#Table(name = "movie")
#AllArgsConstructor
#NoArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private long movieId;
#OneToMany(mappedBy = "movie")
private List<MovieActor> movieActors = new ArrayList<>();
}
Now you can access the intersection table MovieActor inside the query. You can even add more columns to this table if you want.

Hibernate’s “Object References an Unsaved Transient Instance” Error

I recently startet Programming a Back-End in Spring Boot. When implementing the Entitys and their Relationships I soon faced Hibernate’s “Object References an Unsaved Transient Instance” Error. I searched for answers in this forum and tried to fix my Cascade Annotation with this Tutorial: https://www.baeldung.com/hibernate-unsaved-transient-instance-error (which is addressing the specific Error). But when I start my Project and fill in Hard Code Data with the init() method I always Face the Error again:
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : *.structure.Cart.customer -> *.structure.Customer; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : *.structure.Cart.customer -> *.structure.Customer
#Entity
#Table(name="arti")
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class Article {
#Id
#GeneratedValue
#Column(name = "id")
private Long articleId;
private String name;
private String manufactor;
private float price;
#ManyToMany
#Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.PERSIST})
#JoinColumn(name = "cart_id")
private Set<Cart> articleCart= new HashSet<>();
#ManyToMany
#Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.PERSIST})
#JoinColumn(name = "order_id")
private Set<Cart> articleOrder= new HashSet<>();
}
#Entity
#Table(name="cust")
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class Customer {
#Id
#GeneratedValue
#Column(name = "id")
private Long customerId;
#Column(name = "name")
private String name;
#Column(name = "address")
private String address;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "cart_id", referencedColumnName = "id")
private Cart cart;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Order> orders = new HashSet<>();
}
#Entity
#Table(name="cart")
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class Cart {
#Id
#GeneratedValue
#Column(name = "id")
private Long cartId;
#OneToOne(mappedBy = "cart")
private Customer customer;
#ManyToMany
#JoinColumn(name = "article_id")
private Set<Article> articles= new HashSet<>();
}
#Entity
#Table(name="orde")
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class Order {
#Id
#GeneratedValue
#Column(name = "id")
private Long orderId;
#ManyToOne
#Cascade(CascadeType.SAVE_UPDATE)
#JoinColumn(name = "customer_id")
private Customer customer;
#ManyToMany
#JoinColumn(name = "article_id")
private Set<Article> articles= new HashSet<>();
}
#SpringBootApplication
public class GqlApplication {
#Autowired
private ArticleRepository articleRepository;
#Autowired
private CartRepository cartRepository;
#Autowired
private CustomerRepository customerRepository;
#Autowired
private OrderRepository orderRepository;
public static void main(String[] args) {
SpringApplication.run(GqlApplication.class, args);
}
#PostConstruct
public void init() {
Article dress = Article.builder()
.name("red dress")
.manufactor("Prada")
.price(20)
.build();
Article hat = Article.builder()
.name("brown hat")
.manufactor("Gucci")
.price(280)
.build();
Set<Article> articles = new HashSet<>();
articles.add(dress);
articles.add(hat);
Customer tom = Customer.builder()
.name("tom")
.address("Am Baum 3")
.build();
Cart cart = Cart.builder()
.customer(tom)
.articles(articles)
.build();
Order order = Order.builder()
.customer(tom)
.articles(articles)
.build();
Set<Order> orders = new HashSet<>();
orders.add(order);
tom.setCart(cart);
tom.setOrders(orders);
articleRepository.save(dress);
articleRepository.save(hat);
cartRepository.save(cart);
customerRepository.save(tom);
orderRepository.save(order);
}
}

How to get parent entity with all child entities and child entities of children in Spring/JPA/Hibernate with Lombok

I have these entities where Shop entity is parent:
#Data
#NoArgsConstructor
#Entity
#DynamicUpdate
#Table(name = "Shop", schema = "public")
public class ShopDao {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String name;
private String processedStatus;
#OneToMany(mappedBy = "shopDao", cascade = CascadeType.ALL, orphanRemoval = true)
private List<BookDao> bookDaoList;
}
#Data
#NoArgsConstructor
#Entity
#ToString(exclude = {"shopDao"})
#Table(name = "Book", schema = "public")
public class BookDao {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String name;
private String author;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "other_id", referencedColumnName = "id")
private OtherDao otherDao;
#ManyToOne
#JoinColumn(name = "shop_id", nullable = false)
private ShopDao shopDao;
}
#Data
#NoArgsConstructor
#Entity
#ToString(exclude = {"bookDao"})
#Table(name = "Other", schema = "public")
public class OtherDao {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String metadata;
#OneToOne(mappedBy = "otherDao", fetch = FetchType.EAGER)
private BookDao bookDao;
}
And these are repos:
#Repository
public interface ShopRepo extends JpaRepository<ShopDao, Long> {
#EntityGraph(attributePaths = {"bookDaoList"})
List<ShopDao> findAllByProcessedStatus(String processedStatus);
}
#Repository
public interface BookRepo extends JpaRepository<BookDao, Long> {
}
#Repository
public interface OtherRepo extends JpaRepository<OtherDao, Long> {
}
When i'm using findAllByProcessedStatus() function, i get BookList inside Shop object correctly, but each Book can't reach their Other objects and i get LazyInitializationException:
screenshot
How do i fix that problem?
Actually, with spring data's #EntityGraph all you need is :
#Repository
public interface ShopRepo extends JpaRepository<ShopDao, Long> {
#EntityGraph(attributePaths = {"bookDaoList.otherDao"})
List<ShopDao> findAllByProcessedStatus(String processedStatus);
}
This is the most convenient way.
For more complex relations, you could define a #NamedEntityGraph, and provide subgraphs, like so.
What I find intriguing, is that the BookDao is the owner of this relation, so I would expect it to be eagerly loaded, since you haven't specified a the Lazy fetch mode explicitly ...

How to use multiple #Onetoone & #OnetoMany annotation

I'm newbie in Spring boot and making first time an experimental app. This app consist on 3 classes / tables:
Account:
has an account numbers that can be call by JournalEntryDetail, so I get #onetoone relation
JournalEntryMaster:
can have many JournalEntryDetail
I use here #OnetoMany annotation
JournalEntryDetail:
can have one JournalEntryMaster
Foreign key to Account, as Account number should be equal b/w JournalEntDetail & Account table
I get an error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'entityManagerFactory' defined in class path resource
[org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation
of init method failed; nested exception is org.hibernate.AnnotationException: #Column(s) not
allowed on a #OneToOne property: com.accounts.entity.JournalEntryMaster.jvNumber
I can understand what does error means but unfortunately I did not find solution, so I came here. Any one could advise will be appreciated.
I copy entities hereunder:
accountnumber
public class Account {
#Id
#GeneratedValue
#Column(name="account_id")
private Long id;
#Column(name="account_number")
private Long accountNumber;
#Column(name="account_name")
private String accountName;
#Enumerated(EnumType.STRING)
#Column(name="dr_or_credit")
private DrOrCrSide drOrCrSide;
#Enumerated(EnumType.STRING)
#Column(name="account_type")
private AccountType accountType;
#ManyToOne(cascade = CascadeType.ALL)
private JournalEntryDetail journalEntryDetail;
JournalEntryMaster
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#ToString
public class JournalEntryMaster {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private Long id;
#OneToOne
#Column(name="jv_number")
private Long jvNumber;
#Column(name="jv_master_date")
private Date Date;
#Column(name="jv_reference_no")
private String ReferenceNo;
#Column(name="memo")
private String Memo;
#Column(name="posted")
private boolean Posted;
#OneToMany(targetEntity = JournalEntryDetail.class, cascade = CascadeType.ALL)
private Set<JournalEntryDetail> journalEntryDetail = new HashSet<>();
}
JourEntryDetail
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#ToString
public class JournalEntryDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="account_number")
private Long accountNumber;
#Enumerated(EnumType.STRING)
#Column(name="jv_detail_drcr")
private DrOrCrSide DrCr;
#Column(name="amount")
private Double Amount;
#Column(name="memo")
private String Memo;
#ManyToOne
#JoinColumn(name = "jv", referencedColumnName = "id")
private JournalEntryMaster jv;
#JoinColumn(name = "account_fk_jv", referencedColumnName = "account_number")
#OneToOne(targetEntity = Account.class, cascade = CascadeType.ALL)
private Account account_number;
#JoinColumn(name = "jvnumber_fk", referencedColumnName = "jv_number")
#OneToOne(targetEntity = JournalEntryMaster.class, cascade = CascadeType.ALL)
private JournalEntryMaster jvNumber;
In
public class JournalEntryMaster {
...
#OneToOne <-- remove this annotation
#Column(name="jv_number")
private Long jvNumber;
You use Long for the jvNumber. If this is just a database column and its not related to an entity, don't use #OneToOne. You can remove the annotation and your error #Column(s) not allowed on a #OneToOne property: com.accounts.entity.JournalEntryMaster.jvNumber will disappear.
On the other hand, if it is related to an entity, you have to use JoinColumn instead of Column and use your EntityClass instead of Long.
Remove #OneToOne from JournalEntryMaster above #Column(name="jv_number") private Long jvNumber and relation of JournalEntryDetail with JournalEntryMaster
is #ManyToOne not #OneToOne. you give two relation together for one table in JournalEntryDetail
remove:
#JoinColumn(name = "jvnumber_fk", referencedColumnName = "jv_number")
#OneToOne(targetEntity = JournalEntryMaster.class, cascade = CascadeType.ALL)
private JournalEntryMaster jvNumber;
Here down modified code:
JournalEntryMaster
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#ToString
public class JournalEntryMaster {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private Long id;
#Column(name="jv_number")
private Long jvNumber;
#Column(name="jv_master_date")
private Date Date;
#Column(name="jv_reference_no")
private String ReferenceNo;
#Column(name="memo")
private String Memo;
#Column(name="posted")
private boolean Posted;
#OneToMany(targetEntity = JournalEntryDetail.class, cascade = CascadeType.ALL)
private Set<JournalEntryDetail> journalEntryDetail = new HashSet<>();
}
JourEntryDetail
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#ToString
public class JournalEntryDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="account_number")
private Long accountNumber;
#Enumerated(EnumType.STRING)
#Column(name="jv_detail_drcr")
private DrOrCrSide DrCr;
#Column(name="amount")
private Double Amount;
#Column(name="memo")
private String Memo;
#ManyToOne
#JoinColumn(name = "jv", referencedColumnName = "id")
private JournalEntryMaster jv;
#JoinColumn(name = "account_fk_jv", referencedColumnName = "account_number")
#OneToOne(targetEntity = Account.class, cascade = CascadeType.ALL)
private Account account_number;

StackOverflow Exception while using Hibernate and Jackson on bi-directional objects

I am trying some hibernate.The following is the pojo I am using,
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
#Column(name = "person_id")
private long person_id;
#Column(name = "name")
private String name;
#Column(name = "Address")
private String Address;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "person" )
private Set<Phone> phone;
//Getters ande Setters
}
#Entity
#Table(name = "phone")
public class Phone{
#Id
#GeneratedValue
#Column(name = "phone_id")
private long phone_id;
#Column(name = "name")
private String name;
#ManyToOne(cascade = CascadeType.MERGE,fetch = FetchType.EAGER)
#JoinColumn(name = "person_id")
private Person person ;
//Getters ande Setters
}
What I want is when I fetch a record from person and need corresponding all phone details. (Like Select * from person) I have around 1360 data in person and nearly double in phone. But for some reason error is thrown. I am not able to see full error stack . Below is the error I am getting.
at
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:117)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:23)
~[jackson-databind-2.4.6.jar:2.4.6] at
.....
I was not able to post all error that I got
Using JsonManagedReference and JsonBackReference annotations may solve your problem.
While jackson trying to convert objects to json, visits objects and
their attributes. So if objects have bi-directional relations, for
jackson we need to think about cyclic dependencies. Jackson starts
serialize person and see the phone list and take a phone from list and
start serialize phone and sees person in phone and take person from
phone and start serilize it bla bla bla so this is an endless loop. If
jackson sees these annotations, stops and breaks the loop.
Give it a try as below code;
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
#Column(name = "person_id")
private long person_id;
#Column(name = "name")
private String name;
#Column(name = "Address")
private String Address;
#JsonManagedReference
#OneToMany(fetch = FetchType.EAGER, mappedBy = "person" )
private Set<Phone> phone;
// Getters and Setters
}
#Entity
#Table(name = "phone")
public class Phone{
#Id
#GeneratedValue
#Column(name = "phone_id")
private long phone_id;
#Column(name = "name")
private String name;
#ManyToOne(cascade = CascadeType.MERGE,fetch = FetchType.EAGER)
#JoinColumn(name = "person_id")
#JsonBackReference
private Person person;
// Getters and Setters
}
You can alternatively use #JsonIdentityInfo on classes
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id")
#Table(name = "phone")
public class Phone {
}
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id")
#Table(name = "person")
public class Person {
}
I was also getting the same error.
Using #JsonBackReference and #JsonManagedReference was still giving me error so I used #JsonIdentityInfo and it worked like a charm.
Below are my classes :-
BookModel :
#Data
#Entity
#Table(name = "book")
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="bookId")
public class BookModel implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "book_id")
private int bookId;
#Column(name="book_name")
private String bookName;
#Column(name="book_author")
private String bookAuthor;
#Column(name="book_publish_date")
private Date bookPublishDate;
#Column(name="book_price")
private double bookPrice;
#OneToMany(mappedBy = "book_model")
List<BookImagesModel> bookImagesModels;
//getters and setters
//default constructor
}
BookImagesModel :
#Data
#Entity
#Table(name = "book_images")
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="imageId")
public class BookImagesModel implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "image_id")
private long imageId;
#ManyToOne
#JoinColumn(name = "book_id")
private BookModel book_model;
#Column(name = "image_path")
private String imagePath;
//getters and setters
//default constructor
}
I used Mysql8 database with spring boot.

Categories