How to store java objects in mysql using jpa? - mysql

I have converted the JSON into POJO using GSON.
I am looking to store Employee entity object into mysql using JPA's save() method. But I am getting an error saying "cannot determine the type for Address". So how should I go with this?
Here is the error:
Could not determine type for : Address
Employee.java
package com.example.demo;
import java.math.BigDecimal;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import com.google.gson.annotations.Expose;
#Entity
public class Employee {
#Id
private int id;
private String name;
private int age;
private BigDecimal salary;
private String designation;
private Address address;
private long[] phoneNumbers;
/*Getter and Setter Methods*/
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public BigDecimal getSalary() {
return salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
public long[] getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(long[] phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address.java
package com.example.demo;
import javax.persistence.Entity;
import javax.persistence.Id;
//#Entity
public class Address {
#Id
private String street;
private String city;
private int zipCode;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public int getZipCode() {
return zipCode;
}
public void setZipcode(int zipcode) {
this.zipCode = zipcode;
}
#Override
public String toString(){
return getStreet() + ", "+getCity()+", "+getZipCode();
}
}
Controller Class
package com.example.demo;
import net.sf.json.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import net.sf.json.JSONObject;
#Controller // This means that this class is a Controller
#RequestMapping(path="/demo") // This means URL's start with /demo
(after Application path)
public class MainController {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it
to handle the data
private UserRepository userRepository;
#GetMapping(path="/add") // Map ONLY GET Requests
public #ResponseBody String addNewUser (#RequestBody String json) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
//JSONObject jsonObject = JSONObject.fromObject(json);
Gson gson=new GsonBuilder().create();
Employee employee =gson.fromJson(json,Employee.class);
userRepository.save(employee);
return "Successfully added to database using JPA!";
}
#GetMapping(path="/all")
public #ResponseBody Iterable<Employee> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
}

Try adding implements Serializable for your Entity classes.
ie.
#Entity
public class Employee implements Serializable{
}

Whenever you use #Entity annotation in your class and trying to save its instance in database. At very intially a create table command is formed in hibernate which creates table in the database with the given specifications. As in employee table you specify the datatypes of all data-members. When cursor come to 'Address', it gave error because hibernate not able to find any datatype related this or any table related this.
As you commented #Entity annoatation in Address class. So no table regarding that will be created in database.
Address is class reference for this hibernate need the class(table). As class(table) is not there ,so the error comes.

Related

Postman SpringBoot RestApi status code 415 on POSTrequest

I have just started studying Springboot. Everything worked fine until I run into this problem. I've searched every StackOverFlow topic and internet overall and none resolved my problems. I tried to set Content-Type and Accepts the right way but it still didn't work.
UserController:
package com.example.carnet.api;
import com.example.carnet.model.User;
import com.example.carnet.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#RequestMapping("/carnet/user")
public class UserController {
private final UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService = userService;
}
#GetMapping("/all")
public List<User> getUsers() {
return userService.getUsers();
}
#GetMapping(path = "/{email}")
public User getUserByEmail(#PathVariable("email") String email) {
return userService.getUserByEmail(email);
}
#GetMapping("/validate")
public boolean validateUser(#RequestParam("email") String email, #RequestParam("password") String password) {
return userService.validateUser(email, password);
}
#PostMapping("/add")
public void addUser(#RequestBody User user) {
userService.addUser(user);
}
#DeleteMapping(path = "/{id}")
public void deleteUserById(#PathVariable("id") int id) {
userService.deleteUserById(id);
}
#PutMapping
public void updatePassword(#RequestBody User user) {
userService.updatePassword(user);
}
}
User Model:
package com.example.carnet.model;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.sql.Date;
import java.util.List;
#Table(name = "users")
#Entity
public class User {
#Id
private int user_id;
private String email;
private String password;
private String name;
private String surname;
private Date birth_date;
#OneToMany(mappedBy = "user")
#JsonManagedReference
private List<Rental> rentals;
public User() {
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Date getBirth_date() {
return birth_date;
}
public void setBirth_date(Date birth_date) {
this.birth_date = birth_date;
}
}
Error after doing POST request with Postman:
{
"timestamp": "2020-05-06T19:01:16.498+0000",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type 'application/json;charset=UTF-8' not supported",
"path": "/carnet/user/add"
}
SOLVED: Removing #JsonManagedReference from User Model solved the problem!
This problem is because of the #JsonManagedReference in your model class,
Try interchanging #JsonBackReference and #JsonManagedReference. It should work.
Just explore the documentation for more info.
This is one similar issue reported for the same case.

How can I read a JSON with header and body with spring boot

Good morning I have a small query, I am doing a small web service rest with spring boot, the issue is that it is working fine and everything else, as I am doing as follows, receives a parameter and returns a response based on a Stored Procedue in the database:
But now I have changed the request, and it is including header and body, like the following:
{
"ValidateClient": {
"Header": {
"country": "VE",
"lang": "ES",
"entity": "TMVE",
"system": "76",
"subsystem": "APP",
"operation": "ValidateClient",
"timestamp": "2019-10-23T08:48:08.474Z",
"msgType": "REQUEST"
},
"Body": {
"validateClientRequest": {
"movil": "04141734272"
}
}
}
}
Which when executing it gives me an answer of not found the mobile, it is a default response when it cannot read the mobile parameter or it is sent empty
My Code
Main Class
package com.app.validate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ValidateClientApp {
public static void main(String[] args) {
SpringApplication.run(ValidateClientApp.class, args);
}
}
Controller
package com.app.validate.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.app.validate.dao.ValidateClientAppRepository;
import com.app.validate.entity.DriverBonificados;
import com.app.validate.entity.ResponseVo;
#RestController
public class ValidateClientAppController {
#Autowired
private ValidateClientAppRepository dao;
#PostMapping(value = "/ValidateClientApp",consumes = "application/json",produces="application/json")
public ResponseVo ValidateClient(#RequestBody DriverBonificados driver) {
//System.out.println(driver.getMovil());
return dao.validarClienteBonifiado(driver.getMovil());
}
}
Dao
package com.app.validate.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.app.validate.entity.DriverBonificados;
import com.app.validate.entity.ResponseVo;
#Repository
public interface ValidateClientAppRepository extends JpaRepository<DriverBonificados, Integer> {
#Query(nativeQuery = true,value = "call ValidacionClienteBonificado(:movil)")
ResponseVo validarClienteBonifiado(#Param("movil") String pMovil);
}
Entity
package com.app.validate.entity;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="DriverBonificados")
public class DriverBonificados {
#Id
private int id;
private String movil;
private String contador;
private Date fecha_driver;
private Date fecha_alta;
private Date fecha_fin;
private Date codigo_transaccion;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMovil() {
return movil;
}
public void setMovil(String movil) {
this.movil = movil;
}
public String getContador() {
return contador;
}
public void setContador(String contador) {
this.contador = contador;
}
public Date getFecha_driver() {
return fecha_driver;
}
public void setFecha_driver(Date fecha_driver) {
this.fecha_driver = fecha_driver;
}
public Date getFecha_alta() {
return fecha_alta;
}
public void setFecha_alta(Date fecha_alta) {
this.fecha_alta = fecha_alta;
}
public Date getFecha_fin() {
return fecha_fin;
}
public void setFecha_fin(Date fecha_fin) {
this.fecha_fin = fecha_fin;
}
public Date getCodigo_transaccion() {
return codigo_transaccion;
}
public void setCodigo_transaccion(Date codigo_transaccion) {
this.codigo_transaccion = codigo_transaccion;
}
}
Interface Response Stored Procedue
package com.app.validate.entity;
public interface ResponseVo {
String getCode();
String getResult();
}
How could you do to read the Json with header and body? I'm new to spring boot
UPDATE
According to what Silverfang said, I created the classes said by him, but I get an error that I describe next:
BodyRequest.java
public class BodyRequest {
private String validateClientRequest;
private String movil;
public String getValidateClientRequest() {
return validateClientRequest;
}
public void setValidateClientRequest(String validateClientRequest) {
this.validateClientRequest = validateClientRequest;
}
public String getMovil() {
return movil;
}
public void setMovil(String movil) {
this.movil = movil;
}
}
HeaderRequest.java
package com.app.validate.controller;
import java.util.Date;
public class HeaderRequest {
private String country;
private String lang;
private String entity;
private String system;
private String subsystem;
private String operation;
private Date timestamp;
private String msgType;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public String getEntity() {
return entity;
}
public void setEntity(String entity) {
this.entity = entity;
}
public String getSystem() {
return system;
}
public void setSystem(String system) {
this.system = system;
}
public String getSubsystem() {
return subsystem;
}
public void setSubsystem(String subsystem) {
this.subsystem = subsystem;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
}
RequestBodyDemo.java
package com.app.validate.controller;
public class RequestBodyDemo {
private ValidateClientRequest ValidateClient;
public ValidateClientRequest getValidateClient() {
return ValidateClient;
}
public void setValidateClient(ValidateClientRequest validateClient) {
ValidateClient = validateClient;
}
}
ValidateClientRequest
package com.app.validate.controller;
public class ValidateClientRequest {
private BodyRequest Body;
private HeaderRequest Header;
public BodyRequest getBody() {
return Body;
}
public void setBody(BodyRequest body) {
Body = body;
}
public HeaderRequest getHeader() {
return Header;
}
public void setHeader(HeaderRequest header) {
Header = header;
}
}
My Controller (Update)
package com.app.validate.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.app.validate.dao.ValidateClientAppRepository;
import com.app.validate.entity.DriverBonificados;
import com.app.validate.entity.ResponseVo;
#RestController
public class ValidateClientAppController {
#Autowired
private ValidateClientAppRepository dao;
#PostMapping(value = "/ValidateClientApp",consumes = "application/json",produces="application/json")
public ResponseVo ValidateClient(#RequestBody RequestBodyDemo req) {
System.out.println(req.getValidateClient().getBody().getMovil());
return dao.validarClienteBonifiado(req.getValidateClient().getBody().getMovil());
}
}
The error I get:
From what I understand you have changed the request format and now want the same request body to work for the same controller.
I think you were trying to add the fields to the header. What you are doing here is not the right way to do it. It should goes to header section rather than in the body section of the Postman app. But doing so, you will have to specify these header separately as these are custom headers which will be a lot of work.
Answer to your question
Going by what you were trying to do. Since now you have changed the request body. You will have to make changes in the controller class too. Now it will require three classes If you want to do it in a modular way.
The first class will be BodyRequest.java
private string validateClientRequest;
private string movil;
The next class will be HeaderRequest.java
private string country;
private string lang;
private string entity;
private string system;
private string subsystem;
private string operation;
private Date timestamp;
private string msgType;
Next class will be ValidateClientRequest.java
private HeaderRequest Header;
private BodyRequest Body;
Now for the RequestBodyDemo class;
private ValidateClientRequest ValidateClient;
Note : Use appropriate Getter and setter along with #JsonProperty if you are masking the input request data.
Once these things are done. In your controller Instead of using Entity in #RequestBody Use the class RequestBodyDemo. Once that is done. Just try printing the values just to check whether you are getting them right or not. Then use getter for fetching any value that you need.
Edit :
public ResponseVo ValidateClient(#RequestBody RequestBodyDemo req) {
System.out.println(req.getValidateClient().getBodyrequest().getMovil());
return dao.validarClienteBonifiado(req.getValidateClient().getBodyrequest().getMovil());
}
Note : Use appropriate getter method here.

How to correct sql statement to give correct result

I'm running a local MySQL Server on port 3306 with a schema "sys" featuring a table "users"
Now I have a small spring boot application to query all entries from that table.
Model for that table is:
package com.example.databaseneu.model;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Users {
#Id
// #Column(name = "id")
private int id;
// #Column(name = "name")
private String name;
// #Column(name = "salary")
private int salary;
// #Column(name = "team_name")
private String team_name;
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 int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getTeam_name() {
return team_name;
}
public void setTeam_name(String team_name) {
this.team_name = team_name;
}}
The connection works, but the query doesnt seem to deliver the right result as I get the Whitelabel Error Page.
Query to get all elements from the table (autogenerated by repository)
Hibernate:
select
users0_.id as id1_0_,
users0_.name as name2_0_,
users0_.salary as salary3_0_,
users0_.team_name as team_nam4_0_
from
users users0_
So I'm uncertain if i defined the Entity wrong or something else alltogether
#Column Tag doesnt do the trick.
---Edit---
package com.example.databaseneu.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.databaseneu.model.Users;
import com.example.databaseneu.repository.UserRepository;
#Controller // This means that this class is a Controller
#RequestMapping(path = "/demo") // This means URL's start with /demo (after Application path)
public class MainController {
#Autowired
private UserRepository userRepository;
#GetMapping(path = "/add")
public #ResponseBody String addNewUser(#RequestParam String name, #RequestParam int salary,
#RequestParam String team_name) {
Users n = new Users();
n.setName(name);
n.setSalary(salary);
n.setTeam_name(team_name);
userRepository.save(n);
return "Saved";
}
#GetMapping(path = "/all")
public Iterable<Users> getAllUsers() {
return userRepository.findAll();
}}
So id navigate to localhost:8080/demo/all
You have written all correct expect for one thing. Mark your return-type with #ResponseBody annotation -- similar to your addNewUser method.
#GetMapping(path = "/all")
public #ResponseBody Iterable<Users> getAllUsers() {
return userRepository.findAll();
}}
Hopefully this should work. If you still face issues, post it here.

Spring Boot: Found shared references to a collection error

I'm trying to build a small Spring Boot CRUD app with some basic e-commerce functionality (i.e. add to cart, etc.). My Basic entities are customer, cheese, roles and orders.
Customer's have a many-to-many relationship with Cheese (the fictional object I'm selling) objects. In addition, Orders have a many-to-many relationship with Cheese objects. When my customer checks out, I am intending to transfer the cart contents (i.e. the list of Cheeses) to the Order object, along with customer id, total price, etc. I want the "Orders" to be able to be logged by myself, as well as to provide an order history for the customer. The instantiating of the order object with customer.getCheeses() is what is giving me the shared collection error.
I can somewhat get around this by creating new Cheese items, however, that messes up my database, creating duplicates upon every new order.
The processing of orders is done in the completeOrder() function in UserController. All of the html/thymeleaf seems to be working - I can post it if it will help.
Cheese
package com.example.demo.models;
import javax.persistence.*;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
#Entity
public class Cheese {
#NotNull
#Size(min=2, max=20)
private String name;
#NotNull
#Size(min=2, max=20)
private String description;
#NotNull
#DecimalMax("10000.0") #DecimalMin("0.0")
private BigDecimal price;
#Id
#GeneratedValue
private int id;
#ManyToMany(mappedBy = "cheeses")
private List<Customer> customers = new ArrayList<>();
#ManyToMany(mappedBy = "cheeses")
private List<Orders> orders = new ArrayList<>();
public Cheese() {}
public Cheese(String name, String description, BigDecimal price) {
this.name = name;
this.description = description;
this.price = price;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Orders> getOrders() {
return orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
}
Customer
package com.example.demo.models;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
#Entity
public class Customer implements Serializable {
#NotNull
#Size(min = 2, max = 25)
private String name;
#GeneratedValue
#Id
private int accountNumber;
private BigDecimal accountFunds;
#NotNull
#Size(min = 2)
private String password;
#NotNull
#Size(min = 2, max = 25)
#Email
private String email;
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name="user_roles",
joinColumns={#JoinColumn(name="CUSTOMER_EMAIL", referencedColumnName = "email")},
inverseJoinColumns={#JoinColumn(name="ROLE_ID", referencedColumnName="id")})
private List<Role> roles;
//#ElementCollection
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name="cheese_customers",
joinColumns={#JoinColumn(name="CUSTOMER_ID", referencedColumnName = "accountNumber")},
inverseJoinColumns={#JoinColumn(name="PRODUCT_ID", referencedColumnName="id")})
private List<Cheese> cheeses = new ArrayList<>();
public Customer(String name, String password, String email) {
this.name = name;
this.password = password;
this.email = email;
this.accountFunds = new BigDecimal(225.00);
}
public Customer() {}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAccountNumber() {
return accountNumber;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public BigDecimal getAccountFunds() {
return accountFunds;
}
public void setAccountFunds(BigDecimal accountFunds) {
this.accountFunds = accountFunds;
}
public List<Cheese> getCheeses() {
return cheeses;
}
public void setCheeses(List<Cheese> cheeses) {
this.cheeses = cheeses;
}
}
Orders
package com.example.demo.models;
import javax.persistence.*;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
#Entity
public class Orders {
#GeneratedValue
#Id
private int orderId;
#ManyToMany(cascade= CascadeType.ALL)
#JoinTable(name="customer_orders",
joinColumns={#JoinColumn(name="ORDER_ID", referencedColumnName = "orderId")},
inverseJoinColumns={#JoinColumn(name="PRODUCT_ID", referencedColumnName="id")})
private List<Cheese> cheeses = new ArrayList<>();
private int customerId;
private BigDecimal totalPrice;
private Date date;
public Orders() {}
public Orders(List<Cheese> cheeses, int customerId, BigDecimal totalPrice) {
this.cheeses = cheeses;
this.customerId = customerId;
this.totalPrice = totalPrice;
this.date = new Date();
}
private String getFormattedDate() {
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
return format.format(this.date);
}
public int getOrderId() {
return orderId;
}
public List<Cheese> getCheeses() {
return cheeses;
}
public void setCheeses(List<Cheese> cheeses) {
this.cheeses = cheeses;
}
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public BigDecimal getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
UserController
package com.example.demo.controllers;
import com.example.demo.models.Customer;
import com.example.demo.models.Orders;
import com.example.demo.models.data.CheeseDao;
import com.example.demo.models.data.CustomerDao;
import com.example.demo.models.data.OrdersDAO;
import com.example.demo.models.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
#Controller
#RequestMapping("cheese")
public class UserController {
#Autowired
private CustomerDao customerDao;
#Autowired
UserService userService;
#Autowired
CheeseDao cheeseDao;
#Autowired
OrdersDAO ordersDAO;
#RequestMapping(value = "login")
public String loginPage(Model model) {
model.addAttribute("title", "Login Page");
model.addAttribute("customer", new Customer());
return "cheese/login";
}
#RequestMapping(value = "account")
public String accountInfo(Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Customer customer = customerDao.findByEmail(authentication.getName());
model.addAttribute("name", customer.getName());
model.addAttribute("funds", customer.getAccountFunds());
model.addAttribute("customer", customer);
model.addAttribute("cheeses", customer.getCheeses());
model.addAttribute("total", userService.getCartTotal(customer));
return "cheese/account";
}
#PostMapping(value = "account")
public String removeItem(#RequestParam int cheeseId) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Customer customer = customerDao.findByEmail(authentication.getName());
if (customer.getCheeses().contains(cheeseDao.getCheeseById(cheeseId))) {
customer.getCheeses().remove(cheeseDao.getCheeseById(cheeseId));
}
customerDao.save(customer);
return "redirect:/cheese/account";
}
#RequestMapping(value = "checkout")
public String orderCheckout(Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Customer customer = customerDao.findByEmail(authentication.getName());
model.addAttribute("cheeses", customer.getCheeses());
model.addAttribute("total", userService.getCartTotal(customer));
return "cheese/checkout";
}
#GetMapping("signup")
public String displaySignUpForm(Model model) {
model.addAttribute("title", "Sign Up");
model.addAttribute("customer", new Customer());
return "cheese/signup";
}
#PostMapping(value = "signup")
public String processSignUp(Model model, #ModelAttribute Customer customer, Errors errors) {
if (errors.hasErrors()) {
return "cheese/signup";
}
userService.createUser(customer);
return "cheese/success";
}
#GetMapping("ordersuccess")
public String showForm() {
return "cheese/ordersuccess";
}
#PostMapping("checkout")
public String completeOrder() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Customer customer = customerDao.findByEmail(authentication.getName());
double accountFunds = customer.getAccountFunds().doubleValue();
double cartTotal = userService.getCartTotal(customer).doubleValue();
if (accountFunds >= cartTotal) {
accountFunds = accountFunds - cartTotal;
customer.setAccountFunds(new BigDecimal(accountFunds));
Orders order = new Orders(customer.getCheeses(), customer.getAccountNumber(), new BigDecimal(cartTotal));
customer.getCheeses().clear();
customerDao.save(customer);
ordersDAO.save(order);
return "redirect:/cheese/ordersuccess";
}
return "redirect:cheese/checkout";
}
#GetMapping("orders")
public String viewOrderHistory(Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Customer customer = customerDao.findByEmail(authentication.getName());
List<Orders> orders = ordersDAO.findOrdersByCustomerId(customer.getAccountNumber());
model.addAttribute("orders", orders);
return "cheese/orders";
}
}
So what you are trying to do is fetch and fill the cheese collection when you get a customer? Normally, in order to do that, you must set lazy loading to false, otherwise the session closes before you can fetch the collection.
To be able to load the customer with it's cheese collection, you must got to your Hibernate query and use a "join fetch" command. Something like this.
sessionFactory.getCurrentSession().createQuery("from Customer C join fetch C.cheeses").list();
This will force the query to fetch the cheese collection before the session closes. Also, one more thing, normally I would use a Set to avoid duplicates in the collection. I hope this helps.

JPA Entity, JSON serialization

I have my JPA Entity class, AssetOrder. And I have defined a custom JSONSerializer for another entity called Product, which is used by AssetOrder entity internally to map the productID from the Product. As we can see the AssetOrder also has a JSONSerializer for formatting the Date objects.
The Date object JSON serialization works perfectly. However, I am not sure whether the JSONSerializer for the Product works perfectly. When I retrieve the AssetOrder objects from the JPA DAO and try to display on my client page, I get a response saying - Response contains invalid JSON data. I have enclosed the three java classes, AssetOrder.java, Product.java and JSONProductSerializer.java.
Please help, where I have done wrong.
Thanks.
//===================== AssetOrder.java ============================
package my.pkg;
import java.util.Date;
import javax.persistence.CascadeType;
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 com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
#JsonAutoDetect
#Entity
public class AssetOrder {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long orderId;
private String orderRequesterSignum;
private String orderOwnerSignum;
#JoinColumn(name = "productID")
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Product product;
//private String productId;
private int duartion;
private String processInstanceUUID;
private Date orderDate;
private Date orderDeliveryDate;
private Date modifiedDate;
private String status;
private String comments;
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public String getOrderRequesterSignum() {
return orderRequesterSignum;
}
public void setOrderRequesterSignum(String orderRequesterSignum) {
this.orderRequesterSignum = orderRequesterSignum;
}
public String getOrderOwnerSignum() {
return orderOwnerSignum;
}
public void setOrderOwnerSignum(String orderOwnerSignum) {
this.orderOwnerSignum = orderOwnerSignum;
}
public int getDuartion() {
return duartion;
}
public void setDuartion(int duartion) {
this.duartion = duartion;
}
public String getProcessInstanceUUID() {
return processInstanceUUID;
}
public void setProcessInstanceUUID(String processInstanceUUID) {
this.processInstanceUUID = processInstanceUUID;
}
#JsonSerialize(using=JsonDateSerializer.class)
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
#JsonSerialize(using=JsonDateSerializer.class)
public Date getOrderDeliveryDate() {
return orderDeliveryDate;
}
public void setOrderDeliveryDate(Date orderDeliveryDate) {
this.orderDeliveryDate = orderDeliveryDate;
}
#JsonSerialize(using=JsonDateSerializer.class)
public Date getModifiedDate() {
return modifiedDate;
}
public void setModifiedDate(Date modifiedDate) {
this.modifiedDate = modifiedDate;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
#JsonSerialize(using=JsonProductSerializer.class)
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
//============================Product.java=========================
package my.pkg;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long productID;
private String productName;
private String productCategory;
private String productDesc;
private Long productOwnerId;
private Long productHierarchyId;
private String productProcessID;
private Long productGroupID;
public Long getProductID() {
return productID;
}
public void setProductID(Long productID) {
this.productID = productID;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getProductCategory() {
return productCategory;
}
public void setProductCategory(String productCategory) {
this.productCategory = productCategory;
}
public String getProductDesc() {
return productDesc;
}
public void setProductDesc(String productDesc) {
this.productDesc = productDesc;
}
public Long getProductOwnerId() {
return productOwnerId;
}
public void setProductOwnerId(Long productOwnerId) {
this.productOwnerId = productOwnerId;
}
public Long getProductHierarchyId() {
return productHierarchyId;
}
public void setProductHierarchyId(Long productHierarchyId) {
this.productHierarchyId = productHierarchyId;
}
public String getProductProcessID() {
return productProcessID;
}
public void setProductProcessID(String productProcessID) {
this.productProcessID = productProcessID;
}
public Long getProductGroupID() {
return productGroupID;
}
public void setProductGroupID(Long productGroupID) {
this.productGroupID = productGroupID;
}
}
//=================JSONProductSerializer.java=========================
//the commented part in the below code didn't work either
//=====================================================================
package my.pkg;
import java.io.IOException;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* Used to serialize com.xxxx.persistence.entity.Product, which is not a common JSON
* type, so we have to create a custom serialize method;.
*
* source: google.com
*/
#Component
public class JsonProductSerializer extends JsonSerializer<Product>{
#Override
public void serialize(Product product, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException {
synchronized(product) {
/*gen.writeStartObject();
gen.writeNumberField("productID", product.getProductID());
gen.writeStringField("productName", product.getProductName());
gen.writeStringField("productCategory", product.getProductCategory());
gen.writeStringField("productDesc", product.getProductDesc());
gen.writeNumberField("productOwnerId", product.getProductOwnerId());
gen.writeNumberField("productHierarchyId", product.getProductHierarchyId());
gen.writeStringField("productProcessID", product.getProductProcessID());
gen.writeNumberField("productGroupID", product.getProductGroupID());
gen.writeEndObject();*/
gen.writeNumber(product.getProductID());
gen.writeString(product.getProductName());
gen.writeString(product.getProductCategory());
gen.writeString(product.getProductDesc());
gen.writeNumber(product.getProductOwnerId());
gen.writeNumber(product.getProductHierarchyId());
gen.writeString(product.getProductProcessID());
gen.writeNumber(product.getProductGroupID());
}
}
}
Actually, the problem turned out to be with the java.util.Date serialization with com.fasterxml.jackson (latest version of jackson) package. I reverted to org.codehaus.jackson and everything works like a charm.