Config ModelMapper giving me an error when converting From a Set<Author> to Set<Integer> - spring

I am trying to convert a book class (livro) to a bookDto. I was tryied doing that creating a bean config of model mapper but it is not working.
I have on the book class a Set of Authors (autores) and a Set of Genre (generos) and all classes have Integers ids. I want the BookDTO to have only a set of the ids. I guess the problem is on the model mapper config i did
package br.com.newgo.biblioteca.config;
import br.com.newgo.biblioteca.data.dto.output.LivroCriadoDto;
import br.com.newgo.biblioteca.data.entity.Autor;
import br.com.newgo.biblioteca.data.entity.Genero;
import br.com.newgo.biblioteca.data.entity.Livro;
import org.modelmapper.Converter;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Set;
import java.util.stream.Collectors;
#Configuration
public class MapperConfig {
#Bean
public ModelMapper modelMapper(){
ModelMapper modelMapper = new ModelMapper();
Converter<Set<Autor>, Set<Integer>> autoresParaAutoresId = context -> {
if (context.getSource() == null) {
return null;
}
return context.getSource().stream()
.map(Autor::getId).collect(Collectors.toSet());
};
Converter<Set<Genero>, Set<Integer>> generosParaGenerosId = context -> {
if (context.getSource() == null){
return null;
}
return context.getSource().stream()
.map(Genero::getId).collect(Collectors.toSet());
};
modelMapper.typeMap(Livro.class , LivroCriadoDto.class).addMappings(
src -> {
src.using(autoresParaAutoresId).map(Livro::getAutores, LivroCriadoDto::setAutores);
src.using(generosParaGenerosId).map(Livro::getGeneros, LivroCriadoDto::setGeneros);
});
return modelMapper;
}
}
Here is my book class:
package br.com.newgo.biblioteca.data.entity;
import jakarta.persistence.*;
import lombok.*;
import java.util.HashSet;
import java.util.Set;
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity()
#Table(name = "livros")
public class Livro {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(nullable = false)
private String nome;
#Column(nullable = false, length = 13)
private String isbn;
//de 10 ou 13?
#Column(nullable = false)
private Float valor;
#Column(nullable = false)
private Integer paginas;
#Column(nullable = false)
private Float altura;
#Column(nullable = false)
private Float largura;
#Column(nullable = false)
private Float profundidade;
#ManyToMany
#JoinTable(name = "livro_genero")
private Set<Genero> generos = new HashSet<>();
#ManyToMany
#JoinTable(name = "livro_autor",
joinColumns = #JoinColumn(name = "livro_id"),
inverseJoinColumns = #JoinColumn(name = "autor_id"))
private Set<Autor> autores = new HashSet<>();
}
and here is the dto i am trying to convert to :
package br.com.newgo.biblioteca.data.dto.output;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.validator.constraints.Length;
import java.util.HashSet;
import java.util.Set;
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class LivroCriadoDto {
#NotNull
private Integer id;
#NotBlank
private String nome;
#NotBlank
#Length(min = 10, max = 13)
private String isbn;
#NotNull
#Positive
private Float valor;
#NotNull
#Positive
private Integer paginas;
#NotNull
#Positive
private Float altura;
#NotNull
#Positive
private Float largura;
#NotNull
#Positive
private Float profundidade;
#NotNull
#NotEmpty
private Set<Integer> generos = new HashSet<>();
#NotNull
#NotEmpty
private Set<Integer> autores = new HashSet<>();
}
I am trying doing this
modelMapper.map(livro, LivroCriadoDto.class);
and it is returning me
Converter br.com.newgo.biblioteca.config.MapperConfig$$Lambda$1243/0x000000080140e3d8#16a95f37 failed to convert org.hibernate.collection.spi.PersistentSet to java.util.Set.
1) Converter br.com.newgo.biblioteca.config.MapperConfig$$Lambda$1243/0x000000080140e3d8#16a95f37 failed to convert org.hibernate.collection.spi.PersistentSet to java.util.Set.
Caused by: java.lang.NullPointerException
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at br.com.newgo.biblioteca.config.MapperConfig.lambda$modelMapper$0(MapperConfig.java:27)
at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:306)
at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:243)
at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:187)
at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:151)
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:105)
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:71)
at org.modelmapper.ModelMapper.mapInternal(ModelMapper.java:589)
at org.modelmapper.ModelMapper.map(ModelMapper.java:422)
at br.com.newgo.biblioteca.domain.services.LivroService.cadastrar(LivroService.java:51)
at br.com.newgo.biblioteca.presentation.controllers.LivroController.cadastrar(LivroController.java:21)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1010)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:913)

The problem was that jpa was creating a Autor and Genero null because it was not supposed to be null and passing it no Livro

Related

Spring boot entity has a list of another entity

I have a problem with the following code:
#Entity
#Table(name = "app_user")
#NoArgsConstructor
#AllArgsConstructor
#Data
#Builder
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
private String username;
#Column(unique = true)
private String email;
private String name;
private String password;
#Enumerated(EnumType.STRING)
private Role role;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
#JoinTable(name = "user_shoes",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "shoes_id"))
private List<Shoe> shoes = new ArrayList<>();
#Builder.Default
private final Instant created = new Date().toInstant();
}
#Entity
#Table(name = "shoes")
#NoArgsConstructor
#AllArgsConstructor
#Data
#Builder
public class Shoe {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private User user;
private String brand;
private String type;
private String size;
private String color;
private String image_url;
private String sex;
#Builder.Default
private Instant created = new Date().toInstant();
}
Inside User entity I want to make a list that contains Shoe entities, but I always get an error.
Table 'webshop.shoes' doesn't exist
Anybody know how to fix this problem?
It is required to my home project of a shoe webshop.
Thanks.
I had pretty similar codes with yours.
Please see mine and hope you solve it as I did.
import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
#Entity
#Getter
#Table(name = "orders")
#ToString(exclude = "user")
#NoArgsConstructor(access = AccessLevel.PROTECTED)
#EntityListeners(AuditingEntityListener.class)
#SequenceGenerator(
name = "order_seq_generator"
, sequenceName = "orders_order_id_seq"
, initialValue = 1
, allocationSize = 1
)
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE
, generator = "order_seq_generator")
#Column(name = "order_id")
private Long orderId;
#Column(name = "order_number")
private String orderNumber;
#Column(name = "salad_date")
private LocalDate saladDate;
#Column(name = "order_date")
#CreatedDate
private LocalDateTime orderDate;
#ManyToOne
#JsonBackReference
#JoinColumn(name = "user_id")
private User user;
#Column(name = "cancel_yn", columnDefinition = "boolean default false")
private boolean cancelYn;
#Builder
public Order(String orderNumber, User user, LocalDate saladDate, boolean cancelYn) {
this.orderNumber = orderNumber;
this.user = user;
this.saladDate = saladDate;
this.cancelYn = cancelYn;
}
public void updateOrder(String orderNumber, boolean cancelYn) {
this.orderNumber = orderNumber;
this.cancelYn = cancelYn;
}
}
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
#Entity
#Getter
#ToString
#Table(name = "users")
#NoArgsConstructor(access = AccessLevel.PROTECTED)
#EntityListeners(AuditingEntityListener.class)
#SequenceGenerator(
name= "users_seq_generator"
, sequenceName = "users_user_id_seq"
, initialValue = 1
, allocationSize = 1
)
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE
, generator = "users_seq_generator")
#Column(name = "user_id")
private Long userId;
#Column(name = "password")
private String password;
#Column(name = "user_email")
private String userEmail;
#JsonIgnore
#JsonManagedReference // Avoid infinite recursion
#OneToMany(mappedBy = "user", cascade = CascadeType.PERSIST)
private List<Order> orders = new ArrayList<>();
#Column(name = "user_sabun")
private String userSabun;
#Column(name = "user_name")
private String userName;
#Column(name = "user_phone")
private String userPhone;
#Column(name = "send_email_yn")
private boolean sendEmailYn;
#Column(name = "join_date")
#CreatedDate
private LocalDateTime joinDate;
#Builder
public User(Long userId, String userEmail, String password, String userSabun, String userName, String userPhone, boolean sendEmailYn, LocalDateTime joinDate) {
this.userId = userId;
this.userEmail = userEmail;
this.password = password;
this.userSabun = userSabun;
this.userName = userName;
this.userPhone = userPhone;
this.sendEmailYn = sendEmailYn;
this.joinDate = joinDate;
}
public void userUpdate(String userEmail, String userSabun, String userName, String userPhone, boolean sendEmailYn) {
this.userEmail = userEmail;
this.userSabun = userSabun;
this.userName = userName;
this.userPhone = userPhone;
this.sendEmailYn = sendEmailYn;
}
}

How to add the IDs of foreign tables to another table passing the parameters by constructor?

Hi everyone I'm working with SpringBoot and I want to send the ID's of table Producto and Cliente to Pedidos, I'm using the constructor for to pass of parametrs
I tried to create a List as String to hold the values ​​and then use it to send the data to the other method
Class Product
package com.example.demo.model;
import java.util.Set;
import javax.persistence.*;
#Entity
#Table(name = "Productos")
public class Producto {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nombreProducto;
private String precioProducto;
/*Here i send of FK of this table to Pedidos*/
#OneToMany(mappedBy = "producto",cascade = CascadeType.ALL)
private Set<Pedido> pedidos;
public Producto(String nombreProducto, String precioProducto) {
this.nombreProducto = nombreProducto;
this.precioProducto = precioProducto;
}
//Getters and Setters
}
Class Cliente
package com.example.demo.model;
import java.util.Set;
import javax.persistence.*;
#Entity
#Table(name="Clientes")
public class Cliente {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nombreCliente;
private String correoElectronico;
/*Here i send of FK of this table to Pedidos*/
#OneToMany(mappedBy = "cliente",cascade = CascadeType.ALL)
private Set<Pedido> pedidos;
public Cliente(String nombreCliente, String correoElectronico) {
this.nombreCliente = nombreCliente;
this.correoElectronico = correoElectronico;
}
//Getters and Setters
}
Class Pedido
package com.example.demo.model;
import javax.persistence.*;
#Entity
#Table(name = "Pedido")
public class Pedido {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fechaPedido;
private String direccion;
/*
Here I create the atribute of FK of the tables Cliente and Producto
*/
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "cliente_id", referencedColumnName = "id")
private Cliente cliente;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "producto_id", referencedColumnName = "id")
private Producto producto;
public Pedido(String fechaPedido, String direccion, Cliente cliente, Producto producto) {
this.fechaPedido = fechaPedido;
this.direccion = direccion;
this.cliente = cliente;
this.producto = producto;
}
//Getters and Setters
}
And the last Class it's the RunnClass
package com.example.demo;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
//import java.util.stream.Stream;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import com.example.demo.model.Cliente;
import com.example.demo.model.Pedido;
import com.example.demo.model.Producto;
import com.example.demo.repository.ClienteRepository;
import com.example.demo.repository.PedidosRepository;
import com.example.demo.repository.ProductoRepositroy;
import com.github.javafaker.Faker;
#Component
public class SampleDataLoader implements CommandLineRunner {
private final ClienteRepository clienteRepository;
private final ProductoRepositroy productoRepositroy;
private final PedidosRepository pedidosRepository;
private final Faker faker; //It's a ASI of DataFaker
public SampleDataLoader(ClienteRepository clienteRepository,
ProductoRepositroy productoRepositroy,
PedidosRepository pedioPedidosRepository) {
this.clienteRepository = clienteRepository;
this.productoRepositroy = productoRepositroy;
this.pedidosRepository = pedioPedidosRepository;
this.faker = new Faker(); //It's a ASI of DataFaker
}
#Override
public void run(String... args) throws Exception {
ejecutarClases();
}
private void ejecutarClases() {
List<Cliente> clientes = IntStream.rangeClosed(1, 20)
.mapToObj(i -> new Cliente(faker.name().fullName(),
faker.internet().emailAddress()))
.collect(Collectors.toList());
clienteRepository.saveAll(clientes);
List<Producto> productos = IntStream.rangeClosed(1, 100)
.mapToObj(i -> new Producto(faker.commerce().productName(), "$"+faker.commerce().price()))
.collect(Collectors.toList());
productoRepositroy.saveAll(productos);
//I don't know how to send two ID's to this table,
//if you can see I have two values as null
//I want to send the ID's the other tables
List<Pedido> pedidos = IntStream.rangeClosed(1, 30)
.mapToObj(i -> new Pedido(faker.backToTheFuture().date(),
faker.address().streetAddress(), null, null))
.collect(Collectors.toList());
pedidosRepository.saveAll(pedidos);
}
}
I hope someone can help me please.

Migrating Spring Boot application to Quarkus using JPA and JPA

Good afternoon, I'm new to Quarkus and I'm migrating a Spring Boot application, specifically a microservice that performs a DB query through a Procedure, to Quarkus using JPARepository, however I'm getting the following error:
Caused by: io.quarkus.spring.data.deployment.UnableToParseMethodException: Method 'findDataxMovil' of repository 'com.tmve.subscriber.repositories.FindAccountNumberRepository' cannot b
e parsed as there is no proper 'By' clause in the name.
My Repository and Entity classes are defined as follows, just like in Spring Boot:
AccountNumber
package com.tmve.subscriber.entities;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(name = "buscar_datos_x_movil", procedureName = "PERS.PKG_LCL_CUENTA.BUSCAR_DATOS_X_MOVIL", resultClasses = AccountNumber.class, parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, name = "p_movil", type = String.class),
#StoredProcedureParameter(mode = ParameterMode.IN, name = "p_fecha_operacion", type = Date.class),
#StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, name = "p_lista", type = AccountNumber.class) }) })
#Setter
#Getter
#Entity
public class AccountNumber implements Serializable {
private static final long serialVersionUID= 1L;
#Id
private long id;
#Column (name= "NOMBRE")
private String nombre;
#Column(name="APELLIDO")
private String apellido;
#Column(name ="SE")
private String se;
#Column(name = "NUMERO_DOC_PRINCIPAL")
private String numeroDocPrincipal;
#Column(name = "ID_TIPO_DOCUMENTO")
private String idTipoDocumento;
#Column(name = "TIPO")
private String tipo;
#Column(name = "FECHA_NAC")
private String fechaNac;
#Column(name = "ID_CICLO_CONTROL")
private String idCicloControl;
#Column(name = "ID_MARCA")
private String idMarca;
#Column(name = "ID_MODELO")
private String idModelo;
#Column(name = "NOMBRE_MARCA")
private String nombreMarca;
#Column(name = "NOMBRE_MODELO")
private String nombreModelo;
#Column(name = "ESN")
private String esn;
#Column(name = "NUMERO_MOVIL")
private String numeroMovil;
#Column(name = "ID_CUENTA_PAGADORA")
private String idCuentaPagadora;
#Column(name = "ID_CUENTA_USO")
private String idCuentaUso;
}
FindAccountNumberRepository
package com.tmve.subscriber.repositories;
import com.tmve.subscriber.entities.AccountNumber;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.query.Param;
import java.sql.Date;
import java.sql.ResultSet;
public interface FindAccountNumberRepository extends JpaRepository<AccountNumber,String> {
#Procedure(name = "buscar_datos_x_movil")
ResultSet findDataxMovil(#Param("p_movil") String movil, #Param("p_fecha_operacion") Date fechaOperacion);
}
Application.Properties
quarkus.datasource.username=APP_MS_PERS_DEV
quarkus.datasource.password=xxxxxxxx
quarkus.datasource.jdbc.driver=oracle.jdbc.driver.OracleDriver
quarkus.datasource.jdbc.url=jdbc:oracle:thin:#1xxxxxxxxx:1531/PERSDES
quarkus.hibernate-orm.log.sql=true
That could be happening? It seems that it is taking the procedure as a Query from the fields of the Entity
Is there another method that could be applied?

REST API Infinite loop

My API shows me infinite loop for adress field
When I insert #JsonIgnore, #JsonManagedReference or #JsonBackReference
I can clearly see one result as it should be, but than i don't have nested address fields.
What should I do to have also that address fields but one result?
These are my main entities:
1.Property
package com.realestate.petfriendly.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
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.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Data
#Table(name = "property")
public class Property {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_property")
private int id_property;
#Column(name = "title")
private String title;
#Column(name = "type")
private String type;
#Column(name = "room")
private String room;
#Column(name = "price")
private double price;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "address_id_address")
// #JsonBackReference
private Address address;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id_user")
// #JsonBackReference
private User user;
}
User
package com.realestate.petfriendly.entity;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.util.ArrayList;
import java.util.List;
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.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
#Entity
#Getter
#Setter
#Table(name = "user")
class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_user")
private int id_user;
#Column(name = "username")
private String username;
#Column(name = "name")
private String name;
#Column(name = "lastname")
private String lastname;
#Column(name = "phone")
private String phone;
#Column(name = "notes")
private String notes;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "user_address_id_user_address")
// #JsonManagedReference
private UserAddress userAddress;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
// #JsonManagedReference
private List<Property> property = new ArrayList<>();
}
Address
package com.realestate.petfriendly.entity;
import com.fasterxml.jackson.annotation.JsonManagedReference;
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.Table;
import lombok.Getter;
import lombok.Setter;
#Entity
#Getter
#Setter
#Table(name="address")
class Address{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_address")
private int id_address;
#Column(name = "city")
private String city;
#Column(name = "municipality")
private String municipality;
#Column(name = "place")
private String place;
#Column(name = "street")
private String street;
#Column(name = "house_number")
private double house_number;
#OneToOne(mappedBy = "address")
// #JsonManagedReference
private Property property;
}
You actually have the solution to your problem in your code, but the key annotations are commented-out and in the wrong places (according to your requirements). One of the ways to tackle this is by using #JsonManagedReference and #JsonBackReference as follows:
#Entity
#Data
#Table(name = "property")
public class Property {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_property")
private int id_property;
#Column(name = "title")
private String title;
#Column(name = "type")
private String type;
#Column(name = "room")
private String room;
#Column(name = "price")
private double price;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "address_id_address")
#JsonManagedReference
private Address address;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id_user")
#JsonBackReference
private User user;
}
#Entity
#Getter
#Setter
#Table(name = "user")
class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_user")
private int id_user;
#Column(name = "username")
private String username;
#Column(name = "name")
private String name;
#Column(name = "lastname")
private String lastname;
#Column(name = "phone")
private String phone;
#Column(name = "notes")
private String notes;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "user_address_id_user_address")
private UserAddress userAddress;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
#JsonManagedReference
private List<Property> property = new ArrayList<>();
}
#Entity
#Getter
#Setter
#Table(name="address")
class Address{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_address")
private int id_address;
#Column(name = "city")
private String city;
#Column(name = "municipality")
private String municipality;
#Column(name = "place")
private String place;
#Column(name = "street")
private String street;
#Column(name = "house_number")
private double house_number;
#OneToOne(mappedBy = "address")
#JsonBackReference
private Property property;
}
Keep in mind the following:
#JsonManagedReference is the forward part of the relationship: the one that gets serialized normally.
#JsonBackReference is the back part of the relationship: it will be omitted from serialization.
If you want to have a reference to the back part of the relationship, you can use #JsonIdentityInfo as follows:
#Entity
#Data
#Table(name = "property")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id_property")
public class Property {
(...)
}
#Entity
#Getter
#Setter
#Table(name = "user")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id_user")
class User {
(...)
}
#Entity
#Getter
#Setter
#Table(name="address")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id_address")
class Address{
(...)
}
You can read more about these and other techniques in the following online resource: https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion.
You have circular dependency between Property and Address class. In order to block infinite JSON serialization loop you can add #JsonIgnore annotation on one side of related properties

Function saves new record for room table instead of booking table (booking table has room_id as foreign key)

Ive tried to save record for booking in the bookings table, but it does not create a record and instead adds a room for the room table which i do not want as the room table is not supposed to change, only records of bookings should be added into the bookings table with a foreign key room_id of the room that was booked.
Any help would be much appreciated! Thanks!
Tbl_Bookings Entity
package com.sam.ResourceBookingMS.model;
import java.io.Serializable;
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.Table;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
#Entity
#Table(name = "Tbl_Bookings")
public class Tbl_Bookings implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "booking_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public Integer getEmployee_id() {
return employee_id;
}
public void setEmployee_id(Integer employee_id) {
this.employee_id = employee_id;
}
public Integer getEquipment_id() {
return equipment_id;
}
public void setEquipment_id(Integer equipment_id) {
this.equipment_id = equipment_id;
}
#Column(name = "type")
private String type;
#Column(name = "date")
private String date;
#Column(name = "time")
private String time;
#Column(name = "employee_id")
private Integer employee_id;
#Column(name = "equipment_id")
private Integer equipment_id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "room_id", insertable = false, updatable = false)
#Fetch(FetchMode.JOIN)
private Tbl_Rooms thisroom;
public Tbl_Rooms getThisroom() {
return thisroom;
}
public void setThisroom(Tbl_Rooms thisroom) {
this.thisroom = thisroom;
}
public Tbl_Bookings() {
}
public Tbl_Bookings(String type, String date, String time, Integer employee_id, Integer equipment_id) {
this.type = type;
this.date = date;
this.time = time;
this.employee_id = employee_id;
this.equipment_id = equipment_id;
}
}
Tbl_Rooms Entity
package com.sam.ResourceBookingMS.model;
import java.io.Serializable;
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.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "Tbl_Rooms")
public class Tbl_Rooms implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "room_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
private String name;
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 String getCapacity() {
return capacity;
}
public void setCapacity(String capacity) {
this.capacity = capacity;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Column(name = "capacity")
private String capacity;
#Column(name = "location")
private String location;
#Column(name = "description")
private String description;
#OneToMany(targetEntity = Tbl_Bookings.class, mappedBy = "id", orphanRemoval = false, fetch = FetchType.LAZY)
private Set<Tbl_Bookings> bookings;
public Set<Tbl_Bookings> getBookings() {
return bookings;
}
public void setBookings(Set<Tbl_Bookings> bookings) {
this.bookings = bookings;
}
public Tbl_Rooms() {
}
public Tbl_Rooms(String name, String capacity, String location, String description) {
this.name = name;
this.capacity = capacity;
this.location = location;
this.description = description;
}
}
Controller
package com.sam.ResourceBookingMS;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.sam.ResourceBookingMS.model.Tbl_Bookings;
import com.sam.ResourceBookingMS.model.Tbl_Rooms;
#RestController
public class BookRmController {
#Autowired
private TblBkRepository tbr;
#Autowired
private TblRmRepository trr;
#Autowired
private EntityManager entityManager;
#RequestMapping(value = "/bookRm", method = RequestMethod.POST)
#ResponseBody
public String sendData(#RequestBody Tbl_Bookings bk) {
Tbl_Rooms rm = entityManager.getReference(Tbl_Rooms.class, 1);
System.out.println(rm.getId());
Tbl_Bookings booking = new Tbl_Bookings();
booking.setDate(bk.getDate());
booking.setType(bk.getType());
booking.setTime(bk.getTime());
Tbl_Rooms room = new Tbl_Rooms();
room.setCapacity(rm.getCapacity());
room.setDescription(rm.getDescription());
room.setLocation(rm.getLocation());
room.setName(rm.getName());
Set<Tbl_Bookings> bookingOfRoom = new HashSet<Tbl_Bookings>();
bookingOfRoom.add(booking);
room.setBookings(bookingOfRoom);
booking.setThisroom(room);
trr.save(room);
return "Confirmed";
}
}
This is the json data being sent to the controller.
{"room_id":2,"date":"2019-07-26","time":"10:00am to 10:30am","type":"Room"}
mappedBy in parent must be matched with a name defined in the child
(change id to thisroom)
case: "save Child with Parents ID" (might be above UseCase)
For that, we have to request the Child Entity with Parent ID (see JSON request at the controller and set the Parent for that Child) and using Child Repository save the object instead of using parent repository.
case: "save child-parent at same request"
For that, we have to request the Parent Entity which has multiple children (for OneToMany) and using for setting the childerns
Parent
#OneToMany(targetEntity = Tbl_Bookings.class, mappedBy = "thisroom", orphanRemoval = false, fetch = FetchType.LAZY, cascade=CascadeType.ALL)
private Set<Tbl_Bookings> bookings;
Child
#ManyToOne(cascade=CascadeType.ALL,fetch = FetchType.LAZY)
#JoinColumn(name = "room_id", insertable = false, updatable = false)
#Fetch(FetchMode.JOIN)
private Tbl_Rooms thisroom;
Parent-Child Relationship for referance
Parent.java
#Entity
#Table(name = "parent")
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int parentId;
private String name;
#OneToMany(mappedBy="parent",fetch=FetchType.LAZY,cascade = CascadeType.PERSIST)
private List<Child> child = new ArrayList<Child>();
}
Child.java
#Entity
#Table(name = "child")
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int childId;
private String account;
#ManyToOne(fetch = FetchType.LAZY, targetEntity = Parent.class)
#JoinColumn(name="parentId", referencedColumnName = "parentId", nullable = false)
private Parent parent;
}
Controller
#RestController
public class RelationshipController {
#Autowired ParentRepository parentRepository;
#Autowired ChildRepository childRepository;
//save Child with Parent at same
#PostMapping(value = "/onetomany")
public String OneToMany(#RequestBody Parent parent)
{
for (Child child : parent.getChild()) {
child.setParent(parent);
}
parent.setChild(parent.getChild());
parentRepository.save(parent);
return "saved";
/*{
"name":"Romil",
"child":[
{"account":"1"},
{"account":"2"}
]
}*/
}
//save Child with Parent's ID
#PostMapping(value = "/onetomanyPID")
public String OneToMany(#RequestBody Child child)
{
child.setParent(child.getParent());;
childRepository.save(child);
return "saved";
/*{
"account":"3",
"parent":{
"parentId":"1",
"name":"Romil"
}
}*/
}
}
UPDATE
Controller
#PostMapping("/save")
public String save(#RequestBody Tbl_Bookings bookings)
{
bookings.setThisroom(bookings.getThisroom());
tbr.save(bookings);
return "Confirmed";
}
JSON
{
"thisroom":{
"id":"1"
},
"date":"2019-07-26",
"time":"10:00am to 10:30am",
"type":"Room"
}
Tbl_Bookings
#Entity
#Table(name = "Tbl_Bookings")
public class Tbl_Bookings implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "booking_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id", referencedColumnName = "room_id")
private Tbl_Rooms thisroom;
}
Tbl_Rooms
#Entity
#Table(name = "Tbl_Rooms")
public class Tbl_Rooms implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "room_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany(targetEntity = Tbl_Bookings.class, mappedBy = "thisroom", orphanRemoval = false, fetch = FetchType.LAZY, cascade=CascadeType.ALL)
private List<Tbl_Bookings> bookings = new ArrayList<Tbl_Bookings>();
}
There are two points you made mistakes.
First) You need to change OneToMany relation in Tbl_Rooms class as below:
#OneToMany(targetEntity = Tbl_Bookings.class, mappedBy = "thisroom", orphanRemoval = false, fetch = FetchType.LAZY)
private Set<Tbl_Bookings> bookings;
The mappedBy attribute should be the class member of owner side.
Second) You create a new Tbl_Rooms instance in controller. So it is natural a new record would be created for rooms too.

Resources