findBy( ) methods not getting displayed - spring

I am trying to use Spring data JPA find inbuilt methods.
I want to use findByName() , findByDescription but as of now findById() is the only method getting displayed for me.
This is my Entity class.
package com.sood1.springdata.product.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Product {
#Id
private int id;
private String name;
#Column(name = "description")
private String desc;
private Double price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
This is my Repository
package com.sood1.springdata.product.repos;
import org.springframework.data.repository.CrudRepository;
import com.sood1.springdata.product.entities.Product;
public interface ProductRepo extends CrudRepository<Product, Integer> {
}
Can anyone suggest why findByName() or other find methods not coming for me.

You must declare a method in the repository interface like
List<Product> findProductByName(final string name);
or something like that
Johan

Related

SpringBoot StackOverflow error when getting entity

I have following problem. I'm new to Spring. I have created 2 entities and now using postman I want to get all books but I keep getting StackOverflowError.
Here is book model
package com.example.demo;
import jakarta.persistence.*;
import java.util.List;
#Entity
public class BookEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String title;
#ManyToMany
private List<Author> author;
public BookEntity() {
}
public BookEntity(String title) {
this.title = title;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<Author> getAuthor() {
return author;
}
public void setAuthor(List<Author> author) {
this.author = author;
}
}
Author class model
package com.example.demo;
import jakarta.persistence.*;
import java.util.List;
#Entity
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
#ManyToMany
private List<BookEntity> book;
public Author() {
}
public Author(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<BookEntity> getBook() {
return book;
}
public void setBook(List<BookEntity> book) {
this.book = book;
}
}
repository for books
package com.example.demo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface BookRepository extends JpaRepository<BookEntity, Long> {
}
repository for author
package com.example.demo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {
}
controller for books
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
#RequestMapping("/books")
public class BookController {
private final AuthorRepository authorRepository;
private final BookRepository bookRepository;
public BookController(AuthorRepository authorRepository, BookRepository bookRepository) {
this.authorRepository = authorRepository;
this.bookRepository = bookRepository;
}
#GetMapping
List<BookEntity> getAllBooks() {
return bookRepository.findAll();
}
}
Can you please explain what is happening? I can't get any further. I'm stuck
Well this is a common issue. The problem is that you have Book and Author related as ManyToMany. So now whenever you reach for Books, they have an Author field, and when Jackson is trying to add Author it turns out that Author has Books which again have an Author.
Im am aware of 2 ways out of here. First one is DTO you should create a class to be displayed by you controller looking somewhat like this:
public class BookDTO {
private long bookId;
private String bookTitle;
private List<AuthorDTO> authors;
// constructors getters setters
}
situation is a bit complicated because of Many to many so yo need another DTO for authors
public class AuthorDTO {
private long authorId;
private String authorName;
//constructors getters setters
}
you could use a service layer to do all of the mapping. Then you should return BookDTO in your controller.
Another way out are annotations:
#ManyToMany
#JsonManagedReference
private List<Author> author;
and
#ManyToMany
#JsonBackReference
private List<BookEntity> book;
#JsoonManaged and back References will stop Jackson from digging into another entity.
Another thing is you should consider mappedBy in one of your Entities to prevent creating 2 tables.

How to map multiple classes to one table in JPA?

I know this is a frequently asked question, but I couldn't find any answers because I have 3 classes and I generally have problems to build the given structure:
type OrderItem = {
count: number,
price: number,
order: number,
subItems: {
count: number,
name: string,
price: number,
extraItems: {
count: number,
name: string,
price: number,
}
}
};
This is my try at doing it in Java with JPA:
Order.java
package de.gabriel.mcdonaldsproject.models;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
#Entity
#Table(name = "orders", schema = "public")
public class Order implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "order_generator")
#SequenceGenerator(name = "order_generator", sequenceName = "order_seq")
private long id;
private List<Item> products; // <--------- 'Basic' attribute type should not be a container
public Order() {
}
public Order(List<Item> products) {
this.products = products;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<Item> getProducts() {
return products;
}
public void setProducts(List<Item> product) {
this.products = product;
}
}
Item.java
package de.gabriel.mcdonaldsproject.models;
import javax.persistence.*;
public class Item{
private double count;
private double price;
private double order;
private SubItems subItems;
public Item(){}
public Item(double count, double price, double order, SubItems subItems) {
this.count = count;
this.price = price;
this.order = order;
this.subItems = subItems;
}
public double getCount() {
return count;
}
public void setCount(double count) {
this.count = count;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getOrder() {
return order;
}
public void setOrder(double order) {
this.order = order;
}
public SubItems getSubItems() {
return subItems;
}
public void setSubItems(SubItems subItems) {
this.subItems = subItems;
}
}
SubItems.java
package de.gabriel.mcdonaldsproject.models;
import javax.persistence.*;
import java.util.List;
public class SubItems {
private double count;
private String name;
private double price;
private List<String> extraItems;
public SubItems(){}
public SubItems(double count, String name, double price, List<String> extraItems) {
this.count = count;
this.name = name;
this.price = price;
this.extraItems = extraItems;
}
public double getCount() {
return count;
}
public void setCount(double count) {
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public List<String> getExtraItems() {
return extraItems;
}
public void setExtraItems(List<String> extraItems) {
this.extraItems = extraItems;
}
}
Does someone have an idea on how to rebuild this structure in Java with JPA so it also gets saved in the database?
If this object orderitem is not going to expand, I would suggest JSON string saving in the database.
OR you can do following mappings:
#OneToMany(mappedBy="order")
public Order(List<Item> products) {
this.products = products;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "subitem_id", referencedColumnName = "id")
private SubItems subItems;
Update the following information like this :
#Embeddable
public class Item {
// .....
#Embedded
private SubItems subItems;
//.......
}
#Embeddable
public class SubItems {
// .....
#ElementCollection
private List<String> extraItems;
//.......
}
#Entity
#Table(name = "orders", schema = "public")
public class Order implements Serializable {
//.....
#ElementCollection
private List<Item> products;
//.......
}

optimistic locking in spring jpa is not updating the value if the version was more than 0

i used optimistic lock by only write #version in entity ..
and it work when version is 0 , so if i updated the entity and the version was 0 it work and do the update and make the version 1 automatically , but once the version is 1 , it wont accept any other update ... what can i do ..
i thought of doing it manually without #version , like compairing the entety version with its value before update if equall do update or else no ... but how to use it using #version
package com.hariri_stocks.models;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Version;
#Table
#Entity
public class Estates {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private long id;
#Column
private String place;
#Column
private int price;
#Column
private long stocks_num;
#Column
private boolean sold = false;
#Version
private long version;
#OneToOne(mappedBy = "estate_id",fetch = FetchType.EAGER, cascade = CascadeType.ALL )
private SoldEstates sold_estate_id;
public Estates() {
super();
}
public Estates(String place, int price, long stocks_num, SoldEstates sold_estate_id) {
super();
this.place = place;
this.price = price;
this.stocks_num = stocks_num;
this.sold_estate_id = sold_estate_id;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public long getStocks_num() {
return stocks_num;
}
public void setStocks_num(long stocks_num) {
this.stocks_num = stocks_num;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public boolean isSold() {
return sold;
}
public void setSold(boolean sold) {
this.sold = sold;
}
public SoldEstates getSold_estate_id() {
return sold_estate_id;
}
public void setSold_estate_id(SoldEstates sold_estate_id) {
this.sold_estate_id = sold_estate_id;
}
}

Relationship CRUD API Spring Boot

I am creating a crud api with a many to many relationship betwen role and user. When i make a Get HTTP Request, i get the mesage below but When i delete all relationship and make findall on single table, it works percfecttly. Where do you think the problem is?
Error Message in postman
{
"timestamp": "2021-07-10T04:28:24.877+0000",
"status": 500,
"error": "Internal Server Error",
"message": "JSON mapping problem: java.util.ArrayList[0]->com.notyfyd.entity.User[\"roles\"]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.notyfyd.entity.User.roles, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.notyfyd.entity.User[\"roles\"])",
"path": "/user/all"
}
Role Entity
package com.notyfyd.entity;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import java.util.List;
#Entity
#Table(name = "t_role")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#ManyToMany(targetEntity = User.class, mappedBy = "roles", cascade = {CascadeType.PERSIST, CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH})
private List<User> users;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
User Entity
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import java.util.List;
#Entity
#Table(name = "t_user")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String mobile;
#Column(unique = true)
private String email;
#ManyToMany(targetEntity = Role.class, cascade = {CascadeType.PERSIST, CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH} )
#JoinTable(
name="t_user_roles",
joinColumns=
#JoinColumn( name="user_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="role_id", referencedColumnName="id"))
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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 getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
here is the log error on MSSQL Server
2021-07-10 11:20:59.333 WARN 3124 --- [nio-6120-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: fdsa.edu.PNUFDSA.Model.AnneeAcademique.paiements, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: fdsa.edu.PNUFDSA.Model.AnneeAcademique.paiements, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->fdsa.edu.PNUFDSA.Model.AnneeAcademique["paiements"])]
the Entity is:
* "Visual Paradigm: DO NOT MODIFY THIS FILE!"
*
* This is an automatic generated file. It will be regenerated every time
* you generate persistence class.
*
* Modifying its content may cause the program not work, or your work may lost.
*/
/**
* Licensee:
* License Type: Evaluation
*/
package fdsa.edu.PNUFDSA.Model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
#Entity
#Data
//#org.hibernate.annotations.Proxy(lazy=false)
#Table(name="AnneeAcademique")
public class AnneeAcademique implements Serializable {
public AnneeAcademique() {
}
#Column(name="ID", nullable=false, length=10)
#Id
#GeneratedValue(generator="PNU_ANNEEACADEMIQUE_ID_GENERATOR")
#org.hibernate.annotations.GenericGenerator(name="PNU_ANNEEACADEMIQUE_ID_GENERATOR", strategy="native")
private int id;
#Column(name="Debut", nullable=true)
#Temporal(TemporalType.DATE)
private java.util.Date debut;
#Column(name="Fin", nullable=true)
#Temporal(TemporalType.DATE)
private java.util.Date fin;
#JsonIgnore
#ManyToMany(mappedBy="anneeAcademiques", targetEntity=fdsa.edu.PNUFDSA.Model.Cours.class)
#org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK})
#org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.TRUE)
private java.util.Set cours = new java.util.HashSet();
#JsonIgnore
#OneToMany(mappedBy="anneeAcademique", targetEntity=fdsa.edu.PNUFDSA.Model.Paiement.class)
#org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK})
#org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.TRUE)
private List paiements = new ArrayList();
private void setId(int value) {
this.id = value;
}
public int getId() {
return id;
}
public int getORMID() {
return getId();
}
public void setDebut(java.util.Date value) {
this.debut = value;
}
public java.util.Date getDebut() {
return debut;
}
public void setFin(java.util.Date value) {
this.fin = value;
}
public java.util.Date getFin() {
return fin;
}
public void setCours(java.util.Set value) {
this.cours = value;
}
public java.util.Set getCours() {
return cours;
}
public void setPaiements(List value) {
this.paiements = value;
}
public List getPaiements() {
return paiements;
}
public String toString() {
return String.valueOf(getId());
}
}
Are you returning that entity directly as json. Can add #JsonIgnore on below field.
#JsonIgnore
private List<Role> roles;
You can set fetch type to FetchType.EAGER on your many to many relations in your entities.
Try this and let me know what happened.

Spring JPARepository Update a field

I have a simple Model in Java called Member with fields - ID (Primary Key), Name (String), Position (String)
I want to expose an POST endpoint to update fields of a member. This method can accept payload like this
{ "id":1,"name":"Prateek"}
or
{ "id":1,"position":"Head of HR"}
and based on the payload received, I update only that particular field. How can I achieve that with JPARepository?
My repository interface is basic -
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository("memberRepository")
public interface MemberRepository extends JpaRepository<Member, Integer>{
}
My Member model -
#Entity
#Table(name="members")
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="member_id")
private Integer id;
#Column(name="member_name")
#NotNull
private String name;
#Column(name="member_joining_date")
#NotNull
private Date joiningDate = new Date();
#Enumerated(EnumType.STRING)
#Column(name="member_type",columnDefinition="varchar(255) default 'ORDINARY_MEMBER'")
private MemberType memberType = MemberType.ORDINARY_MEMBER;
public Member(Integer id, String name, Date joiningDate) {
super();
this.id = id;
this.name = name;
this.joiningDate = joiningDate;
this.memberType = MemberType.ORDINARY_MEMBER;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Date joiningDate) {
this.joiningDate = joiningDate;
}
public MemberType getMemberType() {
return memberType;
}
public void setMemberType(MemberType memberType) {
this.memberType = memberType;
}
public Member(String name) {
this.memberType = MemberType.ORDINARY_MEMBER;
this.joiningDate = new Date();
this.name = name;
}
public Member() {
}
}
Something like this should do the trick
public class MemberService {
#Autowired
MemberRepository memberRepository;
public Member updateMember(Member memberFromRest) {
Member memberFromDb = memberRepository.findById(memberFromRest.getid());
//check if memberFromRest has name or position and update that to memberFromDb
memberRepository.save(memberFromDb);
}
}

Resources