Getting null reference on One-to-Many Mapping - spring

I am trying to implement ONE-TO-MANY Mapping in REST but getting null reference of USERDETAILS table in Companies table.
Also added the commented part, when I was using the commented part I was getting expected output while fetching the data through getAllUsers(). But it was creating one extra column don't know how to deal with the same.
Below are the Model classes :
USERDETAILS : :
package com.restapi.user.entity;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Entity
#Table(name = "USER_DETAIL_INFORMATION")
#Data
#AllArgsConstructor
#NoArgsConstructor
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties(value = {"createdDate","modifyDate"},allowGetters = true)
public class UserDetails {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "user_id_sequence")
#SequenceGenerator(name = "user_id_sequence",sequenceName = "user_Detail_information_Seq")
#JsonProperty(value ="id" )
private Long userId;
#JsonProperty("name")
#Column(name = "user_name")
private String userName;
#JsonProperty("email")
#Column(name = "user_email")
private String userEmail;
#JsonProperty("address")
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_address_id")
#JsonManagedReference
private Address userAddress;
#Column(name ="user_creation_date")
#Temporal(TemporalType.DATE)
#CreatedDate
#JsonProperty("createdDate")
private Date userCreationDate;
#LastModifiedDate
#Temporal(TemporalType.DATE)
#JsonProperty("modifyDate")
#Column(name = "user_modification_date")
private Date modifyDate;
#JsonProperty("companies")
#OneToMany(mappedBy = "userDetailsid",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private List<Companies> companies;
/*#JsonProperty("companies")
#OneToMany(cascade = CascadeType.ALL)
//, mappedBy = "userDetailsid"
#JoinColumn
private List<Companies> companies;
*/
}
Address : :
package com.restapi.user.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "Address_Details")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "address_seq")
#SequenceGenerator(name = "address_seq",sequenceName = "Address_detail_seq")
#Column(name = "ad_id")
private Long addressId;
#JsonProperty(value = "city")
#Column(name = "ad_city")
private String city;
#JsonProperty(value = "state")
#Column(name = "ad_state")
private String state;
#OneToOne(mappedBy ="userAddress")
#JsonBackReference
private UserDetails userDetails;
}
COMPANIES : :
package com.restapi.user.entity;
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.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonProperty;
#Entity
#Table(name = "COMPANY_INFO_DETAILS")
public class Companies {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "company_seq")
#SequenceGenerator(name = "company_seq",sequenceName = "Compamy_seq_generator")
private Long companyId;
#JsonProperty("c_code")
#Column(name = "c_code")
private String companyCode;
#JsonProperty("c_name")
#Column(name = "c_name")
private String companyName;
#ManyToOne
#JoinColumn(name = "COMAPNY_user_id")
private UserDetails userDetailsid;
/* #ManyToOne(cascade = CascadeType.ALL)
private UserDetails userDetailsid; */
public Companies() {
super();
// TODO Auto-generated constructor stub
}
public Companies(Long companyId, String companyCode, String companyName, UserDetails userDetails) {
super();
this.companyId = companyId;
this.companyCode = companyCode;
this.companyName = companyName;
this.userDetailsid = userDetails;
}
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getCompanyCode() {
return companyCode;
}
public void setCompanyCode(String companyCode) {
this.companyCode = companyCode;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public UserDetails getUserDetails() {
return userDetailsid;
}
public void setUserDetails(UserDetails userDetails) {
System.out.println("user DETAILD"+userDetails.toString());
this.userDetailsid = userDetails;
}
}
Controller
package com.restapi.user.controller;
import java.util.List;
import java.util.Optional;
import javax.management.loading.PrivateClassLoader;
import javax.websocket.server.PathParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.restapi.user.entity.UserDetails;
import com.restapi.user.exceptionHandling.DataInsertionException;
import com.restapi.user.exceptionHandling.DataNotFoundException;
import com.restapi.user.helper.HelperMethods;
import com.restapi.user.service.UserService;
#RestController
#RequestMapping("/api/user")
public class UserController {
#Autowired
private UserService userService;
#Autowired
private HelperMethods helper;
/***
* This API will save the user Details in the database table.
*
* #return
*/
#PostMapping("/addnewUser")
public ResponseEntity<UserDetails> addNewUser(#RequestBody UserDetails userDetails) {
try {
if (helper.isNullEmpty(userDetails.getUserName())) {
throw new DataInsertionException("UserName is missing from the request- it is a mandatory parameter!!");
} else if (userDetails.getUserAddress()==null) {
throw new DataInsertionException(
"UserAddress is missing from the request- it is a mandatory parameter!!");
} else if (helper.isNullEmpty(userDetails.getUserEmail())) {
throw new DataInsertionException(
"User's Email address is missing from the request- it is a mandatory parameter!!");
} else {
UserDetails details = userService.saveUserDetails(userDetails);
return ResponseEntity.status(HttpStatus.CREATED).body(details);
}
} catch (Exception e) {
throw new DataInsertionException(e.getMessage());
}
}
/***
* This API will fetch the list of users available
*
* #return
* #throws Exception
*/
#GetMapping("/getAllUserDetails")
public ResponseEntity<List<UserDetails>> getListOfUsers() throws Exception {
try {
List<UserDetails> userDetails = userService.getAllUsers();
System.out.println(userDetails.size());
if (userDetails.size() < 1) {
throw new DataNotFoundException("No Data FOUND!!");
} else {
return new ResponseEntity<List<UserDetails>>(userDetails, HttpStatus.OK);
}
} catch (Exception e) {
throw new DataNotFoundException(e.getMessage());
}
}
/***
* This API will fetch the user Details by using the ID
*
* #return
* #throws Exception
*/
#GetMapping("/id/{id}")
public ResponseEntity<UserDetails> getUserById(#PathParam("id") Long id) throws Exception {
try {
Optional<UserDetails> userDetails = userService.getUserById(id);
if (!userDetails.isPresent()) {
throw new DataNotFoundException("No Data FOUND!!");
} else {
return new ResponseEntity<UserDetails>(userDetails.get(), HttpStatus.OK);
}
} catch (Exception e) {
throw new DataNotFoundException(e.getMessage());
}
}
}
REQUEST STRUCTURE ::
{
"name": "test_NAME",
"email": "abc#gmail",
"address": {
"city": "abc",
"state": "JK"
},
"companies": [
{
"c_code": "TCS",
"c_name": "TATA"
},
{
"c_code": "CTS",
"c_name": "COGNI"
}
]
}
RESPONSE_BODY ::
{
"id": 3,
"name": "test_NAME",
"email": "abc#gmail",
"address": {
"addressId": 3,
"city": "abc",
"state": "JK"
},
"createdDate": "2021-05-14T20:13:32.154+00:00",
"modifyDate": "2021-05-14T20:13:32.154+00:00",
"companies": [
{
"companyId": 5,
"userDetails": **null**,
"c_code": "TCS",
"c_name": "TATA"
},
{
"companyId": 6,
"userDetails": **null**,
"c_code": "CTS",
"c_name": "COGNI"
}
]
}
SERVICE CLASS :
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.restapi.user.entity.UserDetails;
import com.restapi.user.repository.UserRepository;
#Service
public class UserService {
#Autowired
private UserRepository repository;
public UserDetails saveUserDetails(UserDetails userDetails) {
return repository.save(userDetails);
}
public List<UserDetails> getAllUsers() {
return repository.findAll();
}
public Optional<UserDetails> getUserById(Long id) {
Optional<UserDetails> user = repository.findById(id);
return user;
}
}
Repository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.restapi.user.entity.UserDetails;
#Repository
public interface UserRepository extends JpaRepository<UserDetails, Long>{
}
GetRequest result After Commented part
{
"id": 1,
"name": "test_NAME",
"email": "abc#gmail",
"address": {
"addressId": 1,
"city": "abc",
"state": "JK"
},
"createdDate": "2021-05-15",
"modifyDate": "2021-05-15",
"companies": [
{
"companyId": 2,
"userDetails": null,
"c_code": "CTS",
"c_name": "COGNI"
},
{
"companyId": 1,
"userDetails": null,
"c_code": "TCS",
"c_name": "TATA"
}
]
}
]
If not using Commented part
{
"id": 1,
"name": "test_NAME",
"email": "abc#gmail",
"address": {
"addressId": 1,
"city": "abc",
"state": "JK"
},
"createdDate": "2021-05-15",
"modifyDate": "2021-05-15",
"companies": []
}
]
When using Commented part :
When not using commented part :
Expected output should be :
Someone please highlight what I am missing or doing wrong ? Thanks in advance

Thanks for sharing the UserService. Based from your code in saving user details:
public UserDetails saveUserDetails(UserDetails userDetails) {
return repository.save(userDetails);
}
You are not defining any reference between a user and his/her companies. Again, the cascade you did on the UserDetails object will only means that (since you use CascadeType.ALL) once you save the UserDetails object the save operation will also be cascaded to the Company object however, JPA still needs to know the references between these objects, thus you have to set the userDetailsid for each Company object (during construction). Update your service to something like this:
public UserDetails saveUserDetails(UserDetails userDetails) {
userDetails.getCompanies().stream().forEach(company -> company.setUserDetailsid(userDetails));
return repository.save(userDetails);
}
Note: Just remove your commented codes. They would not work anyways without the update of your service as above.
Lastly, I am seeing you are using Lombok here, so why not use it all through out of your classes to remove boilerplates and update the company something like below. I have put #JsonBackReference to avoid infinite recursion of jackson on your response during add new user and create a getter method getUserReferenceId just for you to see the response of company with a reference userId.
#Entity
#Table(name = "COMPANY_INFO_DETAILS")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Companies {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "company_seq")
#SequenceGenerator(name = "company_seq", sequenceName = "Compamy_seq_generator")
private Long companyId;
#JsonProperty("c_code")
#Column(name = "c_code")
private String companyCode;
#JsonProperty("c_name")
#Column(name = "c_name")
private String companyName;
#ManyToOne
#JsonBackReference
#JoinColumn(name = "COMAPNY_user_id")
private UserDetails userDetailsid;
public Long getUserReferenceId() {
return userDetailsid != null ? userDetailsid.getUserId() : null;
}
}

Related

#Notnull on update not on add

I have a model class which is used in post(create) and put(update) rest API
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
#Getter
#Setter
#NoArgsConstructor
#Entity(name= "employee")
public class employeeDetail {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long employeeId;
#NonNull
private String employeeName;
}
So since employee id to be nullable on add, while it has to be passed when update operation. What is the best to implement?
Note: In this case employee id is a primary key, the same situation is possible for non-primary key fields as well. I use Spring boot, Spring data JPA and hibernate. Database is mariadb.
Something like this:
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.transaction.Transactional;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Optional;
#Getter
#Setter
#NoArgsConstructor
#Entity(name = "employee")
class EmployeeDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long employeeId; //Long is better!
#NotNull
private String employeeName;
// Needed just for conversion -> use some mapper, and remove this constructor
public EmployeeDetail(EmployeeDetailDTO employeeDetailDTO) {
this.employeeId = employeeDetailDTO.getEmployeeId();
this.employeeName = employeeDetailDTO.getEmployeeName();
}
}
interface EmployeeDetailRepo extends JpaRepository<EmployeeDetail, Long> {
}
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
class EmployeeDetailDTO {
private Long employeeId;
#NotNull
private String employeeName;
// Other fields
// Needed just for conversion -> use some mapper, and remove this constructor
public EmployeeDetailDTO(EmployeeDetail employeeDetail) {
this.employeeId = employeeDetail.getEmployeeId();
this.employeeName = employeeDetail.getEmployeeName();
}
}
#Service
class EmpDetailService {
private EmployeeDetailRepo employeeDetailRepo;
#Autowired
public EmpDetailService(EmployeeDetailRepo employeeDetailRepo) {
this.employeeDetailRepo = employeeDetailRepo;
}
public EmployeeDetailDTO add(EmployeeDetailDTO employeeDetailDTO) {
// map EmployeeDetailDTO to EmployeeDetail
EmployeeDetail employeeDetail = new EmployeeDetail(employeeDetailDTO);
EmployeeDetail employeeDetail1FromDB = employeeDetailRepo.save(employeeDetail);
// map back to dto
return new EmployeeDetailDTO(employeeDetail1FromDB);
}
#Transactional
public EmployeeDetailDTO edit(Long id, EmployeeDetailDTO employeeDetailDTO) {
// map EmployeeDetailDTO to EmployeeDetail
Optional<EmployeeDetail> byId = employeeDetailRepo.findById(id);
EmployeeDetail employeeDetailFromDB = byId.orElseThrow(() -> new RuntimeException("No such user with id: " + id));
employeeDetailFromDB.setEmployeeName(employeeDetailDTO.getEmployeeName());
return new EmployeeDetailDTO(employeeDetailFromDB);
}
}
#RequestMapping
class Controller {
private EmpDetailService empDetailService;
#Autowired
Controller(EmpDetailService empDetailService) {
this.empDetailService = empDetailService;
}
#PostMapping("/add")
public ResponseEntity<EmployeeDetailDTO> add(#Valid #RequestBody EmployeeDetailDTO employeeDetailDTO) {
EmployeeDetailDTO added = empDetailService.add(employeeDetailDTO);
return new ResponseEntity<>(added, HttpStatus.OK);
}
#PostMapping("/edit/{id}")
public ResponseEntity<EmployeeDetailDTO> edit(#PathVariable Long id,
#Valid #RequestBody EmployeeDetailDTO employeeDetailDTO) {
EmployeeDetailDTO edited= empDetailService.edit(id, employeeDetailDTO);
return new ResponseEntity<>(edited, HttpStatus.OK);
}
}
Since you expect Hibernate to generate yuor id on insert it should be nullable, so its type.
Just change employeeId to Integer.
From a design point of view, consider to create 2 different business domain classes, one for insert with no id and one for update/select with non nullable id.
public class EmployeeRegistration {
#NonNull
private String name;
}
public class EmployeeDetail {
#NonNull
private Integer employeeId;
#NonNull
private String name;
}
Then provade methods to transform them to database entities.

Leads to implement cart in shopping cart using Spring

I have implemented shopping cart up to product. But have no idea on how to implement separate cart for each user.
Please share your ideas
Please share your effort / code along with your question always.
According to me this can go with many scenarios
One of the scenarios would be like,
User have One Cart, Cart will have many products and many Products belongs to many carts
Code goes as below, You can go ahead and add required parameters to the entity.
User Entity
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;
#Entity
#Table(name = "USERS")
public class User {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "USER_NAME")
private String userName;
#OneToOne(mappedBy = "user", fetch = FetchType.LAZY)
private Cart cart;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Cart getCart() {
return cart;
}
public void setCart(Cart cart) {
this.cart = cart;
}
}
Cart Entity
import java.util.Set;
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.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "CART")
public class Cart {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "CART_PRODUCT", joinColumns = #JoinColumn(name = "CART_ID") , inverseJoinColumns = #JoinColumn(name = "PRODUCT_ID") )
private Set<Product> products;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}
Product Entity
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
#Entity
#Table(name = "PRODUCT")
public class Product {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String productName;
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "products")
private Set<Cart> carts;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Set<Cart> getCarts() {
return carts;
}
public void setCarts(Set<Cart> carts) {
this.carts = carts;
}
}

Hibernate Error Invalid Column Name

I am trying to make a one to many and many to one relation in hibernate and spring.
below is my code for product class
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="Product")
public class Product implements Serializable{
#Id
#Column(name="productId")
#GeneratedValue
private Integer productId;
#Column(name="productName")
private String productName;
#Column(name="productPrice")
private int productPrice;
//---------------------------------------item mapped to category------------------------------------------//
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinTable(
name="CategoryProduct",
joinColumns= #JoinColumn(name="productId")
)
private Category category;
//--------------------------------------------------------------------------------------------------------//
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public int getProductPrice() {
return productPrice;
}
public void setProductPrice(int productPrice) {
this.productPrice = productPrice;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
below is my code for category class
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.io.Serializable;
#Entity
#Table(name="Category")
public class Category implements Serializable{
#Id
#Column(name="categoryId")
#GeneratedValue
private Integer categoryId;
#Column(name="categoryName")
private String categoryName;
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#JoinTable(
name="CategoryProduct",
joinColumns = #JoinColumn(name="categoryId"),
inverseJoinColumns = #JoinColumn(name="productId")
)
public Set<Product> product;
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Set<Product> getProduct() {
return product;
}
public void setProduct(Set<Product> product) {
this.product = product;
}
}
Whenever i run the code i am getting Invalid column name 'category_categoryId'.
Structure of my tables
Product has column as productId, poductName and productPrice
category has columns as categoryId, categoryName
categoryproducts has columns as categoryId and productId
you forgot to put inverseJoinColumns at your #JoinTable in Product Class. This cause hibernate to use their convention of joinTable which is <ClassName>_<columnName>. Change it to
#JoinTable(
name="CategoryProduct",
joinColumns = #JoinColumn(name="productId"),
inverseJoinColumns = #JoinColumn(name="categoryId")
)
private Category category;
However, seeing at your design, you are actually creating 2 uni-directional association between product and category. If you want to create bi-directional association, I suggest you change the One side (Category), to use mappedBy
#OneToMany(mappedBy="category", cascade=CascadeType.ALL,fetch=FetchType.EAGER)
public Set<Product> product;
It will generally achieve the same result. Hope it helps!

How to Fetch Data using Spring Data

Hey i want to create a repository extending JpaRepository and fetch result without writing actual query,
In my example i have 2 tables Book and Author mapped by many to many relationship, suppose i want to fetch list of books by a particular author_id, since in my book entity, i don't have any field named author_id, so how will i use JPARepository to fetch results without writing actual query.
I was doing something like this: I created a bookDTO which contain object of Book and Author, and i created bookDTORepository extending JpaRepository and was calling List<Book> findByAuthor_Id(Integer id); , but its throwing error as: Not an managed type: class golive.data.bookdto My book class is
package golive.data;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sun.istack.internal.NotNull;
#Entity
#Table(name="book")
public class Book implements java.io.Serializable{
#Id
#GeneratedValue
private Integer id;
#NotNull
#Column(name="name")
private String name;
#ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
#JoinTable(name = "writes", joinColumns = { #JoinColumn(name = "book_id") }, inverseJoinColumns = { #JoinColumn(name = "author_id") })
private Set<Author> authors = new HashSet<Author>();
public Set<Author> getAuthors() {
return authors;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setAuthors(Set<Author> authors) {
this.authors = authors;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
My author class is
package golive.data;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sun.istack.internal.NotNull;
#Entity
#Table(name="author")
public class Author implements java.io.Serializable{
#Id
#GeneratedValue
#Column(name="id")
private Integer Id;
#NotNull
#Column(name="name")
private String name;
public Integer getId() {
return Id;
}
public String getName() {
return name;
}
public void setId(Integer id) {
Id = id;
}
public void setName(String name) {
this.name = name;
}
}
My bookdto class is
package golive.data;
public class bookdto {
private Book book;
private Author author;
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
and my bookDTORepository is :
package golive.data;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface bookDTORepository extends JpaRepository<bookdto, Book> {
List<Book> findByAuthor_Id(Integer id);
}
My book controller method, i added:
#RequestMapping(value = "/listbyauthor", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<List<Book>> getBookByAuthorId(#RequestBody Author author,HttpServletResponse response) {
try {
Author temp = new Author();
temp.setId(author.getId());
temp.setName(author.getName());
return new ResponseEntity<>(bookRepository.findByAuthor(temp), HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
}
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
You want to find all books for a specific author so, given an Author, retrieve all Books whose set of Authors contains the specified Author.
The relevant JPQL operator is:
http://www.objectdb.com/java/jpa/query/jpql/collection#NOT_MEMBER_OF_
[NOT] MEMBER [OF] The [NOT] MEMBER OF operator checks if a specified
element is contained in a specified persistent collection field.
For example:
'English' MEMBER OF c.languages is TRUE if languages contains
'English' and FALSE if not. 'English' NOT MEMBER OF c.languages is
TRUE if languages does not contain 'English'.
As you may (or may not) be aware, you are using Spring Data which can derive some queries for you depending on method name. The docs do not however mention support for the [NOT] MEMBER [OF] operator:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
You will therefore need to add a custom query method to your repository which will look something like:
public interface BookRepository extends JpaRepository<Book, Integer> {
#Query("select b from Book b where ?1 MEMBER OF b.authors")
List<Book> findByAuthor(Author author);
}
and where the Author passed as a parameter is a persistent instance retrieved from the Database (via your AuthorRepository).

Can't persist entity with child entity (#OneToOne relationship) using gwt requestfactory because of getting NullPointerException

I'm using GWT RequestFactory + Hibernate + Spring in my web app.
I have Principal and Profile entities that relate to each other as one to one. They share the same primary key.
On a client side I write such a code, which causes NullPointerException:
If I exclude "principal.setProfile(profile);" code line, principal entity will be stored successfully. I can't figure out why profile entity can't be stored along with principal.
Any suggestions will be highly appreciated. Thanks in advance!
public RegistrationPanel() {
TarantulaFactory factory = GWT.create(TarantulaFactory.class);
factory.initialize(new SimpleEventBus());
PrincipalRequestContext principalCtx = factory.createPrincipalRequest();
ProfileRequestContext profileCtx = factory.createProfileRequest();
PrincipalProxy principal = principalCtx.create(PrincipalProxy.class);
principal.setLogin("Billy");
principal.setPassword("Corgan");
ProfileProxy profile = profileCtx.create(ProfileProxy.class);
profile.setNickname("A");
profile.setName("b");
profile.setEmail("ABCD34#gmail.com");
profile.setBirthDate(new Date());
profile.setCurrentLocation("Chicago");
principal.setProfile(profile);
profile.setPrincipal(principal);
principalCtx.save(principal).fire();
}
Stack trace:
//------------------------------------------------------------------------
21:09:24.992 [ERROR] [application] Uncaught exception escaped
java.lang.NullPointerException: null
at com.google.web.bindery.requestfactory.shared.impl.AbstractRequestContext$MyConstraintViolation.<init>(AbstractRequestContext.java:434)
at com.google.web.bindery.requestfactory.shared.impl.AbstractRequestContext$StandardPayloadDialect.processPayload(AbstractRequestContext.java:366)
at com.google.web.bindery.requestfactory.shared.impl.AbstractRequestContext$5.onTransportSuccess(AbstractRequestContext.java:1151)
at com.google.web.bindery.requestfactory.gwt.client.DefaultRequestTransport$1.onResponseReceived(DefaultRequestTransport.java:136)
at com.google.gwt.http.client.Request.fireOnResponseReceived(Request.java:258)
at com.google.gwt.http.client.RequestBuilder$1.onReadyStateChange(RequestBuilder.java:412)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:338)
at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:219)
at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571)
at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:279)
at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:242)
at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:293)
at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:547)
at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:364)
at java.lang.Thread.run(Thread.java:722)
//------------------------------------------------------------------------
Below is the source code for entities, proxies and RequestFactory.
Here are entity classes:
Profile.java
package com.szybieka.tarantula.core.domain;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
/**
*
* A Profile representing the user profile entity. Each user has single profile.
* Profile and {#link Principal} entities relate to each other as one-to-one.
* Shared primary key is used to join corresponding tables.
*
* #author Zmicer Szybieka
*
*/
#Entity
#Table(name = "profile", uniqueConstraints = { #UniqueConstraint(
columnNames = "id") })
public class Profile {
#Id
#NotNull
#Column(name = "id", unique = true)
#GeneratedValue(generator = "gen")
#GenericGenerator(name = "gen", strategy = "foreign",
parameters = #Parameter(name = "property", value = "principal"))
private Long id;
#Length(min = 1, max = 30)
private String nickname;
#Length(max = 30)
private String name;
#Column(name = "birth_date")
private Date birthDate; // date of birth, e.g. "20.01.1985"
#Length(max = 30)
#Column(name = "current_location")
private String currentLocation; // current location city, e.g. "NYC"
#Email
private String email;
private Date version;
#OneToOne(mappedBy = "profile", cascade = CascadeType.ALL)
private Principal principal; // the user principal corresponding to the
// profile
public Profile() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
// omit setters/getters
}
Principal.java
package com.szybieka.tarantula.core.domain;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.hibernate.validator.constraints.Length;
/**
* A Principal representing an identity used to determine access rights to
* application. Principal relates to {#link Profile} entity as one-to-one.
* Shared primary key is used to join corresponding tables.
*
* #author Zmicer Szybieka
*
*/
#Entity
#Table(name = "principal", uniqueConstraints = { #UniqueConstraint(
columnNames = "id") })
public class Principal {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Length(max = 20)
private String login;
#Length(max = 10)
private String password;
private Date version;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Profile profile;
public Principal() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
// omit setters/getters
}
I use RequestFactory to connect with server side.
Here is my RequestFactory:
TarantulaFactory.java
package com.szybieka.tarantula.gwt.client.requestfactory;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.RequestContext;
import com.google.web.bindery.requestfactory.shared.RequestFactory;
import com.google.web.bindery.requestfactory.shared.Service;
import com.szybieka.tarantula.gwt.client.proxy.PrincipalProxy;
import com.szybieka.tarantula.gwt.client.proxy.ProfileProxy;
import com.szybieka.tarantula.gwt.server.locator.PrincipalServiceLocator;
import com.szybieka.tarantula.gwt.server.locator.ProfileServiceLocator;
import com.szybieka.tarantula.gwt.server.service.PrincipalService;
import com.szybieka.tarantula.gwt.server.service.ProfileService;
public interface TarantulaFactory extends RequestFactory {
PrincipalRequestContext createPrincipalRequest();
ProfileRequestContext createProfileRequest();
#Service(value = ProfileService.class,
locator = ProfileServiceLocator.class)
public interface ProfileRequestContext extends RequestContext {
Request<Void> save(ProfileProxy profile);
Request<ProfileProxy> findProfile(Long id);
}
#Service(value = PrincipalService.class,
locator = PrincipalServiceLocator.class)
public interface PrincipalRequestContext extends RequestContext {
Request<PrincipalProxy> findPrincipal(String login, String password);
Request<PrincipalProxy> findPrincipal(Long id);
Request<PrincipalProxy> findPrincipalByLogin(String login);
Request<Void> save(PrincipalProxy principal);
Request<Void> remove(PrincipalProxy principal);
}
}
Here are proxies for entity classes:
ProfileProxy.java
package com.szybieka.tarantula.gwt.client.proxy;
import java.util.Date;
import com.google.web.bindery.requestfactory.shared.EntityProxy;
import com.google.web.bindery.requestfactory.shared.ProxyFor;
import com.szybieka.tarantula.core.domain.Profile;
import com.szybieka.tarantula.gwt.server.locator.ProfileLocator;
#ProxyFor(value = Profile.class, locator = ProfileLocator.class)
public interface ProfileProxy extends EntityProxy {
Long getId();
void setId(Long id);
// omit other getter/setter methods
}
PrincipalProxy.java
package com.szybieka.tarantula.gwt.client.proxy;
import com.google.web.bindery.requestfactory.shared.EntityProxy;
import com.google.web.bindery.requestfactory.shared.ProxyFor;
import com.szybieka.tarantula.core.domain.Principal;
import com.szybieka.tarantula.gwt.server.locator.PrincipalLocator;
#ProxyFor(value = Principal.class, locator = PrincipalLocator.class)
public interface PrincipalProxy extends EntityProxy {
Long getId();
String getLogin();
// omit other getter/setter methods
}
A RequestContext is a builder for a batch request that you eventually fire to send to the server for processing. All proxies have to be created and edited from the same RequestContext in a batch request.
Remove your use of ProfileRequestContext and replace profileCtx.create(ProfileProxy.class) with principalCtx.create(ProfileProxy.class).

Resources